/*
  2/15/1993
  ScianWhisselFiles.c

  NEXRAD file reader
*/

#include "Scian.h"
#include "ScianTypes.h"
#include "ScianArrays.h"
#include "ScianIcons.h"
#include "ScianWindows.h"
#include "ScianObjWindows.h"
#include "ScianVisWindows.h"
#include "ScianVisObjects.h"
#include "ScianControls.h"
#include "ScianColors.h"
#include "ScianDialogs.h"
#include "ScianFiles.h"
#include "ScianFileSystem.h"
#include "ScianLists.h"
#include "ScianPictures.h"
#include "ScianErrors.h"
#include "ScianTimers.h"
#include "ScianDatasets.h"
#include "ScianFilters.h"
#include "ScianTextBoxes.h"
#include "ScianTitleBoxes.h"
#include "ScianButtons.h"
#include "ScianSliders.h"
#include "ScianScripts.h"
#include "ScianIDs.h"
#include "ScianVisContours.h"
#include "ScianStyle.h"
#include "ScianSpaces.h"
#include "ScianMethods.h"
#include "ScianObjFunctions.h"
#include "ScianWhisselFiles.h"

/* 
  Each file contains a number of elevation scans of velocity and
  reflectivity data.  The fields have different grid spacing, so I
  assumed that I needed to create two datasets out of each file.
*/

#define TORADS (3.1415926535898 / 180.0)

#ifdef PROTO
static ObjPtr ReadNXRFile(char *name)
#else
static ObjPtr ReadNXRFile(name)
  char   *name;
#endif
{
  struct NXRhead header;	/* NEXRAD/SciAn file header */
  FILE   *infile;

  char formname[TEMPSTRSIZE];
  char refname[TEMPSTRSIZE];
  char velname[TEMPSTRSIZE];
  char *tc;

  int     els, i, j, k;		/* Index variables */

  float   x, y, z, len, inc;	/* Used in grid-positioning calculations */
  float   sina, cosa;

  static ObjPtr  RefForm = NULL; /* Dataforms for Reflectivity */
  static ObjPtr  VelForm = NULL; /*   and Velocity */
  ObjPtr form;			/* Temp form pointer */

  ObjPtr  RefDataSet, VelDataSet; /* Datasets for reflec. and vel. */

  long    dims[3];
  real    bounds[6];		/* Used to define parameters of datasets */
  long    indices[3];		/*   and dataforms */

  float   val;			/* Conversion vars */
  unsigned char uchar;

  strcpy(formname, name);
  tc = formname;
  while(*tc && (*tc != '@') && (*tc != '.'))
    tc++;
  *tc = '\0';
  strcpy(refname, formname);
  strcpy(velname, formname);

  strcat(formname, ".form");
  strcat(refname, ".dBZ");
  strcat(velname, ".m/s");

  /* Open the file and verify that it contains appropriate data */

  if ((infile = fopen(name, "r")) == NULL) {
    FileFormatError("ReadNXRFile", "File not accessible");
    return NULLOBJ;
  }
  if (fread(&header, sizeof(header), 1, infile) != 1) {
    FileFormatError("ReadNXRFile", "Error reading file header");
    fclose(infile);
    return NULLOBJ;
  }
  if (strncmp(header.ident, FVERSION, 7) != 0) {
    FileFormatError("ReadNXRFile", "File version mismatch");
    fclose(infile);
    return NULLOBJ;
  }
  els = header.num_els;

  /* Set up the Reflectivity data form */

  dims[0] = 3;
  dims[1] = N_RADS;
  dims[2] = N_REFGATES;

  form = NewDataset(formname, 3, dims, 3);

  SetCurField(FIELD1, form);

  inc = (float) header.ref_gatespace / 1000.0;
  for (i = 0; i < els; i++) {	/* elevations */
    z = len * sin((double) header.elevs[i] * TORADS);
    indices[0] = i;
    for (j = 0; j < N_RADS; j++) {	/* radials */
      len = inc / 2.0;
      cosa = (float)cos((double)(90.0 - (j + 0.5)) * TORADS);
      sina = (float)sin((double)(90.0 - (j + 0.5)) * TORADS);
      indices[1] = j;
      for (k = 0; k < N_REFGATES; k++, len += inc) {	/* gates */
	x = len * cosa;
	y = len * sina;

	indices[2] = k;

	PutFieldComponent(FIELD1, 0, indices, x);
	PutFieldComponent(FIELD1, 1, indices, y);
	PutFieldComponent(FIELD1, 2, indices, z);
      }
    }
  }

  bounds[0] = 0.0;
  bounds[1] = sin((double) header.elevs[els-1] * TORADS) *
    N_REFGATES * inc + inc / 2.0;
  bounds[2] = -(inc * N_REFGATES + inc / 2.0);
  bounds[3] = -bounds[2];
  bounds[4] = bounds[2];
  bounds[5] = bounds[3];

  /* ...once the grid is created, it can be turned into a dataform... */

  RefForm = NewCurvilinearDataForm(formname, 3, dims, bounds, form);

  /* Set up the velocity data form */

  dims[0] = els;
  dims[1] = N_RADS;
  dims[2] = N_VELGATES;

  form = NewDataset(formname, 3, dims, 3);

  SetCurField(FIELD1, form);

  inc = (float) header.vel_gatespace / 1000.0;
  for (i = 0; i < els; i++) {	/* elevations */
    z = len * sin((double) header.elevs[i] * TORADS);
    indices[0] = i;
    for (j = 0; j < N_RADS; j++) {	/* radials */
      len = inc / 2.0;
      cosa = (float)cos((double)(90.0 - (j + 0.5)) * TORADS);
      sina = (float)sin((double)(90.0 - (j + 0.5)) * TORADS);
      indices[1] = j;
      for (k = 0; k < N_VELGATES; k++, len += inc) {	/* gates */
	x = len * cosa;
	y = len * sina;

	indices[2] = k;

	PutFieldComponent(FIELD1, 0, indices, x);
	PutFieldComponent(FIELD1, 1, indices, y);
	PutFieldComponent(FIELD1, 2, indices, z);
      }
    }
  }

  bounds[0] = 0.0;
  bounds[1] = sin((double) header.elevs[els-1] * TORADS) *
    N_VELGATES * inc + inc / 2.0;
  bounds[2] = -(inc * N_VELGATES + inc / 2.0);
  bounds[3] = -bounds[2];
  bounds[4] = bounds[2];
  bounds[5] = bounds[3];
  
  VelForm = NewCurvilinearDataForm(formname, 3, dims, bounds, form);

  /* Dataforms have been defined.  Now setup the complete datasets. */

  RefDataSet = NewDataset(refname, 3, dims, 0);
  VelDataSet = NewDataset(velname, 3, dims, 0);

  SetDatasetForm(RefDataSet, RefForm);
  SetDatasetForm(VelDataSet, VelForm);

  /* Read and convert data: reflectivity is first, then velocity data. */

  for (i = 0; i < els; i++) {
    /* Read reflectivity scan */
    indices[0] = i;
    SetCurField(FIELD1, RefDataSet);
    for (j = 0; j < N_RADS; j++) {
      indices[1] = j;
      if (feof(infile))
	goto READERROR;
      for (k = 0; k < N_REFGATES; k++) {
	indices[2] = k;
	uchar = (unsigned char) getc(infile);
	val = (uchar <= 1) ? missingData : (uchar - 2) / 2.0 - 32.0;
	PutFieldComponent(FIELD1, 0, indices, val);
      }
    }

    /* Read velocity scan using one of two resolution values */
    SetCurField(FIELD1, VelDataSet);
    if (header.vel_res == 2) {	/* 0.5 m/s resolution */
      for (j = 0; j < N_RADS; j++) {
	indices[1] = j;
	if (feof(infile))
	  goto READERROR;
	for (k = 0; k < N_VELGATES; k++) {
	  indices[2] = k;
	  uchar = (unsigned char) getc(infile);
	  val = (uchar <= 1) ? missingData : (uchar - 2) / 2.0 - 63.5;
	  PutFieldComponent(FIELD1, 0, indices, val);
	}
      }
    } else {	/* 1.0 m/s resolution */
      for (j = 0; j < N_RADS; j++) {
	indices[1] = j;
	if (feof(infile))
	  goto READERROR;
	for (k = 0; k < N_VELGATES; k++) {
	  indices[2] = k;
	  uchar = (unsigned char) getc(infile);
	  val = (uchar <= 1) ? missingData : (uchar - 2) - 127.0;
	  PutFieldComponent(FIELD1, 0, indices, val);
	}
      }
    }	/* end if */
  }	/* elevation loop */

  fclose(infile);

  /* Kludgy way of finding seconds since midnite */
  val = (float) (header.file_time % (24 * 60 * 60));

  RegisterTimeDataset(RefDataSet, val);
  RegisterTimeDataset(VelDataSet, val);

  return NULLOBJ;

READERROR:
  /* Do I not have to free any structures like forms or allocated data
     sets? */

  FileFormatError("ReadNXRFile", "Premature EOF!");
  fclose(infile);
  return NULLOBJ;
}


#ifdef PROTO
void InitWhisselFiles(void)
#else
void InitWhisselFiles()
#endif
{
    DefineFormat("NXR", "nxr", ReadNXRFile, 0);
}

#ifdef PROTO
void KillWhisselFiles(void)
#else
void KillWhisselFiles()
#endif
{
}
