#ifndef GRADSDES_H
#define GRADSDES_H

#define gaint int
#define gadouble double
#define gafloat float
#define galloc(x, y) malloc(x)
#define gree(x, y) free(x)
#define gaprnt(i, ch) printf("%s", ch)

/* Handling of missing data values. After the data I/O is done,
   grid values are tested to see if they are within a small range
   (+-value/EPSILON) of the missing value. If true, then the undef
   mask is set to 0. If false, then the grid data values are good,
   and the undef mask is set to 1. Everywhere else in the code,
   undef tests are done on the mask values, not the data. */

#define EPSILON 1e5

#include <stdio.h>

/* Date/time structure */
struct dt
{
  gaint yr;
  gaint mo;
  gaint dy;
  gaint hr;
  gaint mn;
};

/* Structure that describes a variable in a file.  These structures
   are built in arrays that are hung off of gafile structures.         */
struct gavar
{
  char varnm[128];      /* Variable description.                */
  char abbrv[16];       /* Variable abbreviation.               */
  char longnm[257];     /* netcdf/hdf var name if different     */
  gadouble units[16];   /* Units indicator.
                           Vals 0-7 are for variable codes:
                           grib, non-float data, nc/hdf dims
                           Vals  8-11 are for grib level codes  */
  gaint offset;         /* Offset in grid elements of the start
                           of this variable within a time group
                           within this file.                    */
  gaint recoff;         /* Record (XY grid) offset of the start
                           of this variable within a time group */
  gaint ncvid;          /* netcdf vid for this variable         */
  gaint sdvid;          /* hdf vid for this variable            */
  gaint levels;         /* Number of levels for this variable.
                           0 is special and indiates one grid is
                           available for the surface only.      */
  gaint dfrm;           /* format  type indicator
                           1 - unsigned char
                           4 - int                              */
  gaint var_t;          /* variable t transform                 */
  gadouble scale;       /* scale factor for unpacking data      */
  gadouble add;         /* offset value for unpacking data      */
  gadouble undef;       /* undefined value                      */
  gaint vecpair;        /* Variable has a vector pair           */
  gaint isu;            /* Variable is the u-component of a vector pair */
  gaint isdvar;         /* Variable is a valid data variable (for SDF files) */
  gaint nvardims;       /* Number of variable dimensions        */
  gaint vardimids[100]; /* Variable dimension IDs.                */
};

/* Sructure for string substitution in templating -- the %ch template.
   This forms a linked list chained from pchsub1 in gafile */
struct gachsub
{
  struct gachsub *forw; /* Forward pointer */
  gaint t1;             /* First time for this substitution */
  gaint t2;             /* Last time.  -99 indicates open ended */
  char *ch;             /* Substitution string */
};

/* Structure for ensemble metadata */
struct gaens
{
  char name[16];    /* name of ensemble */
  gaint length;     /* length of time axis */
  struct dt tinit;  /* initial time */
  gaint gt;         /* initial time in grid units */
  gaint grbcode[4]; /* grib2 codes */
};

#define MAX_RECLEN 512
#define MAX_NAMELEN 512
typedef struct
{
  char name[MAX_NAMELEN];
  char dnam[MAX_NAMELEN];
  char title[MAX_NAMELEN];
  int bswap;
  long gsiz;   /* Number of elements in a grid (x*y)    */
               /* This is for actual grid on disk,
                  not psuedo grid (when pp in force) */
  long tsiz;   /* Number of elements in an entire time
                  group (all variables at all levels
                  for one time).                        */
  gaint trecs; /* Number of records (XY grids) per time
                  group.                                */
  long fhdr;
  struct gachsub *pchsub1; /* Pointer to first %ch substitution */
  gaint ncflg;             /* 1==netcdf  2==hdfsds */
  long xyhdr;
  int seqflg;
  int yrflg;
  int zrflg;
  int pa2mb;
  int calendar;
  /* init !? */
  FILE *infile;        /* File pointer.                         */
  gaint type;          /* Type of file:  1 = grid
                                         2 = simple station
                                         3 = mapped station
                                         4 = defined grid       */
  gadouble undef;      /* Global undefined value for this file  */
  gadouble ulow, uhi;  /* Undefined limits for missing data test  */
  gaint dnum[5];       /* Dimension sizes for this file.        */
  gaint vnum;          /* Number of variables.                  */
  struct gavar *pvar1; /* Pointer to an array of structures.
                          Each structure in the array has info
                          about the specific variable.          */
  struct gaens *ens1;  /* pointer to array of ensemble structures */
  gaint wrap;          /* The grid globally 'wraps' in X        */
  gadouble (*gr2ab[5])(double *, double);
  /* Addresses of routines to do conversion
     from grid coordinates to absolute
     coordinates for X, Y, Z.  All Date/time
     conversions handled by gr2t.          */
  gadouble (*ab2gr[5])(double *, double);
  /* Addresses of routines to do conversion
     from absolute coordinates to grid
     coordinates for X,Y,Z.  All date/time
     conversions handled by t2gr.          */
  gadouble *grvals[5]; /* Pointers to conversion information for
                          grid-to-absolute conversion routines. */
  gadouble *abvals[5]; /* Pointers to conversion information for
                          absolute-to-grid conversion routines. */
  gaint linear[5];     /* Indicates if a dimension has a linear
                          grid/absolute coord transformation
                          (Time coordinate always linear).      */
  gaint idxflg;        /* File records are indexed; 1==grib,station 2==grib2 */
  gaint flt64;         /* 20120711 Uwe Schulzweida: added support for 64 bit floats */
  gaint tmplat;        /* File name templating:
                           3==templating on E and T
                           2==templating only on E
                           1==templating only on T, or when
                              ddf has 'options template', but no % in dset
                           0==no templating  */
  gaint *fnums;        /* File number for each time */
  gaint fnumc;         /* Current file number that is open */
  gaint fnume;         /* Current ensemble file number that is open */
} dsets_t;

void dsets_init(dsets_t *dsets);

int read_gradsdes(char *filename, dsets_t *pfi);

gadouble liconv(gadouble *, gadouble);
gadouble gr2lev(gadouble *, gadouble);
gadouble lev2gr(gadouble *, gadouble);
void gr2t(gadouble *, gadouble, struct dt *);
char *gafndt(char *, struct dt *, struct dt *, gadouble *, struct gachsub *, struct gaens *, gaint, gaint, gaint *);

gaint cmpwrd(const char *ch1, const char *ch2);
char *intprs(char *ch, int *val);
void gabswp(void *r, gaint cnt);
void gabswp2(void *r, gaint cnt);

#endif /* GRADSDES_H */
