#ifdef  HAVE_CONFIG_H
#include "../src/config.h"  /* The size of off_t depends on _FILE_OFFSET_BITS (on SUN) */
#endif

#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include "cgribex.h"
#include "gribapi.h"
#include "dmemory.h"
#include "namelist.h"

#ifdef  HAVE_LIBGRIB_API
#include "grib_api.h"


#define  UNDEFID  -1

char *Progname;

void version(void)
{
  fprintf(stderr, "%s version 1.4.0\n", Progname);
  fprintf(stderr, "  C_GRIBEX library version : %s\n", cgribexLibraryVersion());
#if  defined  (HAVE_LIBGRIB_API)
  fprintf(stderr, "  GRIB_API library version : %s\n", gribapiLibraryVersion());
#endif
  fprintf(stderr, "\n");
/*
  1.0.0   6 Dec 2000 : initial version
  1.0.1  10 Jan 2003 : update to libgrib.a
  1.0.2  15 Jan 2003 : create output buffer for copy
  1.0.3   2 Feb 2003 : change macro MAX/MIN to if statement
  1.0.4  27 Jul 2003 : handle missing values
  1.1.0  22 Mar 2005 : change level handling
  1.1.1  19 Apr 2005 : change date/time format to ISO
  1.2.0  12 Feb 2006 : SZ compression with -szip and -sunzip
  1.3.0  12 Feb 2006 : add parameter select
  1.3.1  20 Mar 2006 : add select parameter - bits
  1.3.2  25 Aug 2006 : use ISEC1 only if ljdecode is TRUE (bug fix)
  1.3.3  11 Jan 2007 : add select parameter - fcnum
  1.3.4  25 Jun 2007 : replace decodeDate/decodeTime
  1.3.5  27 Dec 2007 : add option read
  1.3.6  03 Mar 2008 : add select parameter - ltype
  1.4.0  08 Jun 2009 : added grib_api support
*/
}


void usage()
{
  fprintf(stderr, "usage : %s [-options]  ifile  [ofile]\n", Progname);
  fprintf(stderr, "with:\n");

  fprintf(stderr, "   -bits <num>    pack with num bits\n");
  fprintf(stderr, "   -edition <num> set GRIB edition number\n");
  fprintf(stderr, "   -info          print GRIB contents\n");
  fprintf(stderr, "   -ginfo         print GRIB information\n");
  fprintf(stderr, "   -linfo         print long information (gribex section)\n");
  fprintf(stderr, "   -gdsinfo       print grid description section\n");
  fprintf(stderr, "   -pdsinfo       print product definition section\n");
  fprintf(stderr, "   -bmsinfo       print bit-map section\n");
  fprintf(stderr, "   -bdsinfo       print binary data section\n");

  fprintf(stderr, "   -copy          decode and encode GRIB records\n");
  fprintf(stderr, "   -read <num>    read file <num> times (performance test)\n");
  fprintf(stderr, "   -regular       regular grid (HOPER='R')\n");

  fprintf(stderr, "   -select        select records via namelist:\n");
  fprintf(stderr, "                    bits   INTEGER  List of bits numbers\n");
  fprintf(stderr, "                    code   INTEGER  List of code numbers\n");
  fprintf(stderr, "                    fcnum  INTEGER  List of forecast numbers\n");
  fprintf(stderr, "                    day    INTEGER  List of days\n");
  fprintf(stderr, "                    hour   INTEGER  List of hours\n");
  fprintf(stderr, "                    level  INTEGER  List of levels\n");
  fprintf(stderr, "                    ltype  INTEGER  List of level types\n");
  fprintf(stderr, "                    minute INTEGER  List of minutes\n");
  fprintf(stderr, "                    month  INTEGER  List of months\n");
  fprintf(stderr, "                    rec    INTEGER  Start and end record number\n");
  fprintf(stderr, "                    record INTEGER  List of records\n");
  fprintf(stderr, "                    rdate  INTEGER  List of reference dates [YYYYMMDD]\n");
  fprintf(stderr, "                    rtime  INTEGER  List of reference times [hhmmss]\n");
  fprintf(stderr, "                    vdate  INTEGER  List of verification dates [YYYYMMDD]\n");
  fprintf(stderr, "                    vtime  INTEGER  List of verification times [hhmmss]\n");
  fprintf(stderr, "                    year   INTEGER  List of years\n");

  fprintf(stderr, "   -szip          szip compression\n");
  fprintf(stderr, "   -sunzip        szip decompression\n");

  fprintf(stderr, "   -debug         debugging mode\n");
  fprintf(stderr, "   -Version       version number\n");
}


void    cdiDecodeDate(int date, int *year, int *month, int *day);
void    cdiDecodeTime(int time, int *hour, int *minute, int *second);


static void
printInfo(int date, int time, int table, int code, double level,
          int datasize, int nmiss, double *data)
{
  static int rec = 0;
  int i, ivals = 0, imiss = 0;
  int year, month, day, hour, minute, second;
  double arrmean, arrmin, arrmax;

  if ( ! rec )
  {
    if ( table == -1 )
      fprintf(stdout, 
	      "   Rec :       Date     Time Code  Level    Size    Miss :     Minimum        Mean     Maximum\n");
    else
      fprintf(stdout, 
	      "   Rec :       Date     Time Param     Level    Size    Miss :     Minimum        Mean     Maximum\n");
/*             ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
  }

  cdiDecodeDate(date, &year, &month, &day);
  cdiDecodeTime(time, &hour, &minute, &second);

  if ( table == -1 )
    fprintf(stdout, "%6d : %4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d %3d %7g ",
	    ++rec, year, month, day, hour, minute, second, code, level);
  else
    fprintf(stdout, "%6d : %4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d %03d.%03d %7g ",
	    ++rec, year, month, day, hour, minute, second, table, code, level);

  fprintf(stdout, "%7d ", datasize);

  fprintf(stdout, "%7d :", nmiss);
    {
      if ( nmiss > 0 )
	{
	  arrmean = 0;
	  arrmin  =  1.e300;
	  arrmax  = -1.e300;
	  for ( i = 0; i < datasize; i++ )
	    {
	      if ( fabs(data[i]-GRIB_MISSVAL) > 0 )
		{
		  if ( data[i] < arrmin ) arrmin = data[i];
		  if ( data[i] > arrmax ) arrmax = data[i];
		  arrmean += data[i];
		  ivals++;
		}
	    }
	  imiss = datasize - ivals;
	  datasize = ivals;
	}
      else
	{
	  arrmean = 0;
	  arrmin  =  1.e300;
	  arrmax  = -1.e300;
	  for ( i = 0; i < datasize; i++ )
	    {
	      if ( data[i] < arrmin ) arrmin = data[i];
	      if ( data[i] > arrmax ) arrmax = data[i];
	      arrmean += data[i];
	    }
	}

      if ( datasize > 0 ) arrmean /= datasize;

      fprintf(stdout, "%#12.5g%#12.5g%#12.5g\n", arrmin, arrmean, arrmax);

      if ( imiss != nmiss && nmiss > 0 )
	fprintf(stdout, "Found %d of %d missing values!\n", imiss, nmiss);
    }
}


int notinlist_int(int nval, int *vallist, int val)
{
  int i, found;

  if ( nval == 0 ) found = 1;
  else             found = 0;

  for ( i = 0; i < nval; i++ )
    if ( val == vallist[i] ) { found = 1; break; }

  return (!found);
}


int notinlist_flt(int nval, double *vallist, double val)
{
  int i, found;

  if ( nval == 0 ) found = 1;
  else             found = 0;

  for ( i = 0; i < nval; i++ )
    if ( ! (fabs(val - vallist[i]) > 0) ) { found = 1; break; }

  return (!found);
}
#endif

int main(int argc, char *argv[])
{
#if  defined  (HAVE_LIBGRIB_API)
  namelist_t *nml = NULL;
  NML_DEF_INT(bits,     32, 0);
  (void)bits; (void)nselbits;
  NML_DEF_INT(code,   1024, 0);
  (void)code; (void)nselcode;
  NML_DEF_INT(day,      32, 0);
  (void)day; (void)nselday;
  NML_DEF_INT(fcnum,  1024, 0);
  (void)fcnum; (void)nselfcnum;
  NML_DEF_INT(hour,     25, 0);
  (void)hour; (void)nselhour;
  NML_DEF_INT(level,  1024, 0);
  (void)level; (void)nsellevel;
  NML_DEF_INT(ltype,   256, 0);
  NML_DEF_INT(minute,   61, 0);
  NML_DEF_INT(month,    16, 0);
  NML_DEF_FLT(param,  1024, 0);
  NML_DEF_INT(rec,       2, 0);
  NML_DEF_INT(record, 1024, 0);
  NML_DEF_INT(rdate,  1024, 0);
  NML_DEF_INT(rtime,    64, 0);
  NML_DEF_INT(table,  1024, 0);
  NML_DEF_INT(vdate,  1024, 0);
  NML_DEF_INT(vtime,    64, 0);
  NML_DEF_INT(year,   1024, 0);

  /* int second; */
  int select = 0;
  int c;
  char *cstring;
  char *ifile = NULL;
  char *ofile = NULL;
  int ierr;
  int nrec = 0;
  int ifileID = 0, ofileID = 0;
  int debug = 0;
  int copy = 0, move = 0;
  int info = 0, ginfo = 0;
  int pdsinfo = 0, gdsinfo = 0, bmsinfo = 0, bdsinfo = 0;
  int paraminfo = 0;
  int linfo = 0;
  int dinfo = 0;
  /* int nbits = 0; */
  int nread = 0;
  size_t irecsize = 0;
  size_t orecsize = 0;
  long recpos = 0;
  long offset = 0;
  unsigned char *igribbuffer = NULL;
  unsigned char *itmpbuffer = NULL;
  unsigned char *ogribbuffer = NULL;
  unsigned char *buffer = NULL;
  size_t igribbuffersize = 0;
  size_t itmpbuffersize = 0;
  size_t ogribbuffersize = 0;
  size_t buffersize = 0;
  int ldecode = 0, lencode = 0, ljdecode = 0;
  /* int iret = 0, iword = 0; */
  size_t datasize = 0, dummy;
  long numberOfPoints;
  double *data = NULL;
  /* double fsec2[512], fsec3[2]; */
  int date = 0, time = 0;
  /* int level1, level2; */
  int leveltype;
  double dlevel = 0;
  int nmiss = 0;
  size_t readsize;
  size_t allocdatasize = 0;
  /* int regular = 0; */
  int gribversion = -1;
  int lzip = 0, lunzip = 0;
  int szip = 0, sunzip = 0;
  int izip;
  int status;
  long edition = 0;
  long editionNumber;
  long lpar;
  size_t nbytes;
  size_t unzipsize;
  grib_handle *gh = NULL;

  memExitOnError();

  Progname = strrchr(argv[0], '/');
  if ( Progname == NULL ) Progname = argv[0];
  else                    Progname++;

  while ( --argc && (*++argv)[0] == '-' )
    {
      c = *++argv[0];
      cstring = argv[0];
      size_t len = strlen(cstring);
      switch (c)
	{
        case 'b':
	  if ( !strncmp(cstring, "bits", len) )
	    {
              ++argv;
	      /* nbits = atoi(argv[0]); */
	      --argc;
	    }
	  else if ( !strncmp(cstring, "bdsinfo", len) )
	    {
	      bdsinfo = 1;
	    }
	  else if ( !strncmp(cstring, "bmsinfo", len) )
	    {
	      bmsinfo = 1;
	    }
          break;
        case 'c':
	  if ( !strncmp(cstring, "copy", len) )
	    {
	      copy = 1;
	    }
          break;
        case 'd':
	  if ( !strncmp(cstring, "debug", len) )
	    {
	      debug = 1;
	    }
	  else if ( !strncmp(cstring, "dinfo", len) )
	    {
	      dinfo = 1;
	    }
          break;
        case 'e':
	  if ( !strncmp(cstring, "edition", len) )
	    {
	      edition = atol((++argv)[0]);
	      --argc;
	      if ( edition != 1 && edition != 2 )
		{
		  fprintf(stderr, "invalid GRIB edition number %ld!\n", edition);
		  return (-1);
		}
	    }
          break;
        case 'g':
	  if ( !strncmp(cstring, "ginfo", len) )
	    {
	      ginfo = 1;
	    }
	  else if ( !strncmp(cstring, "gdsinfo", len) )
	    {
	      gdsinfo = 1;
	    }
          break;
        case 'h':
	  if ( !strncmp(cstring, "help", len) )
	    {
	      usage ();
	      return (0);
            }
	  break;
	case 'i':
	  if ( !strncmp(cstring, "inputfile", len) )
	    {
	      ifile = (++argv)[0];
	      --argc;
	    }
	  else if ( !strncmp(cstring, "info", 4) )
	    {
	      info = 1;
	    }
          break;
        case 'l':
	  if ( !strncmp(cstring, "linfo", len) )
	    {
	      linfo = 1;
	    }
          break;
        case 'o':
	  if ( !strncmp(cstring, "outputfile", len) )
	    {
	      ofile = (++argv)[0];
	      --argc;
            }
          break;
        case 'p':
	  if ( len == 1 && *cstring == 'p' )
	    {
	      paraminfo = 1;
	    }
	  else if ( !strncmp(cstring, "pdsinfo", len) )
	    {
	      pdsinfo = 1;
	    }
          break;
        case 'r':
	  if ( !strncmp(cstring, "read", len) )
	    {
	      nread = atoi((++argv)[0]);
	      --argc;
	    }
	  /*
           * else if ( !strncmp(cstring, "regular", len) )
	   *   {
	   *     regular = 1;
	   *   }
           */
          break;
        case 's':
	  if ( !strncmp(cstring, "szip", len) )
	    {
	      szip = 1;
	    }
	  else if ( !strncmp(cstring, "sunzip", len) )
	    {
	      sunzip = 1;
	    }
	  else if ( !strncmp(cstring, "select", len) )
	    {
	      select = 1;
	    }
          break;
        case 'V':
	  if ( !strncmp(cstring, "Version", len) )
	    {
	      version();
	      return (0);
            }
	  break;
        default:
	  usage();
	  fprintf(stderr, "illegal option %s\n", cstring);
	  return (-1);
        }
    }

  if ( argc && !ifile )
    {
      ifile = argv[0];
      argc--;
    }
  if ( argc && !ofile )
    {
      ofile = (++argv)[0];
      argc--;
    }

  if ( !ifile || ( !ofile && copy ) )
    {
      usage();
      return (-1);
    }

  if ( debug )
    {
      fprintf(stderr, "\n");
      if ( ifile )
	fprintf(stderr, "  < %s  \n", ifile);
      if ( ofile )
	fprintf(stderr, "  > %s\n\n", ofile);

       gribSetDebug(debug);
    }

  if ( ofile && !copy ) move = 1;

  if ( !move && !copy && !bdsinfo && !bmsinfo && !ginfo && !gdsinfo &&
       !linfo && !pdsinfo && !info && !dinfo && !nread ) info = 1;

 LABEL_READ:

  ifileID = gribOpen(ifile, "r");
  if ( ifileID == UNDEFID )
    {
      fprintf(stderr, "Open failed on %s\n", ifile);
      return (1);
    }

  if ( ofile )
    {
      ofileID = gribOpen(ofile, "w");
      if ( ofileID == UNDEFID )
	{
	  fprintf(stderr, "Open failed on %s\n", ofile);
	  return (1);
	}
    }

  /* read namelist */
  if ( select )
    {      
      nml = namelistNew("SELECT");

      NML_ADD_INT(nml, bits);
      NML_ADD_INT(nml, code);
      NML_ADD_INT(nml, fcnum);
      NML_ADD_INT(nml, day);
      NML_ADD_INT(nml, hour);
      NML_ADD_INT(nml, level);
      NML_ADD_INT(nml, ltype);
      (void)ltype; (void)nselltype;
      NML_ADD_INT(nml, minute);
      (void)minute;
      (void)nselminute;
      NML_ADD_INT(nml, month);
      (void)month; (void)nselmonth;
      NML_ADD_FLT(nml, param);
      (void)param; (void)nselparam;
      NML_ADD_INT(nml, rec);
      (void)rec; (void)nselrec;
      NML_ADD_INT(nml, record);
      (void)record; (void)nselrecord;
      NML_ADD_INT(nml, rdate);
      (void)rdate; (void)nselrdate;
      NML_ADD_INT(nml, rtime);
      (void)rtime; (void)nselrtime;
      NML_ADD_INT(nml, table);
      (void)nseltable;
      NML_ADD_INT(nml, vdate);
      (void)vdate; (void)nselvdate;
      NML_ADD_INT(nml, vtime);
      (void)vtime; (void)nselvtime;
      NML_ADD_INT(nml, year);
      (void)year; (void)nselyear;
      namelistRead(stdin, nml);
      /* namelistPrint(nml); */

      NML_NUM(nml, bits);
      NML_NUM(nml, code);
      NML_NUM(nml, fcnum);
      NML_NUM(nml, day);
      NML_NUM(nml, hour);
      NML_NUM(nml, level);
      NML_NUM(nml, ltype);
      NML_NUM(nml, minute);
      NML_NUM(nml, month);
      NML_NUM(nml, param);
      NML_NUM(nml, rec);
      NML_NUM(nml, record);
      NML_NUM(nml, rdate);
      NML_NUM(nml, rtime);
      NML_NUM(nml, table);
      NML_NUM(nml, vdate);
      NML_NUM(nml, vtime);
      NML_NUM(nml, year);

#if 0
      if ( nselparam )
	{
	  int i;
	  int itable;
	  for ( i = 0; i < nselparam; i++ )
	    {
	      itable = (int) selparam[i];
	      /* int icode = (int) (1000*(selparam[i] - itable)); */
	      /* printf("%d %g %d %d\n", i, selparam[i], itable, icode); */
	    }
	}
#endif
    }

  if ( edition ) copy = 1;
  ldecode  = ( info || linfo || dinfo || copy );
  ljdecode = ( info || linfo || dinfo || copy || select );
  lencode  = copy;
  lzip     = szip;
  lunzip   = sunzip || info;
  /*
  fprintf(stderr, "lzip     %d\n", lzip);
  fprintf(stderr, "lunzip   %d\n", lunzip);
  fprintf(stderr, "lencode  %d\n", lencode);
  fprintf(stderr, "ldecode  %d\n", ldecode);
  fprintf(stderr, "ljdecode %d\n", ljdecode);
  */
  while ( 1 )
    {
      assert(irecsize <= LONG_MAX);
      offset   = -(recpos + (long)irecsize);
      irecsize = gribGetSize(ifileID);
      recpos   = gribGetPos(ifileID);
      offset  += recpos;

      if ( irecsize == 0 ) break;

      if ( igribbuffersize < (irecsize+1000) )
	{
	  igribbuffersize = irecsize+1000;
	  igribbuffer = (unsigned char *) realloc(igribbuffer, igribbuffersize);
	}

      readsize = irecsize;
      ierr = gribRead(ifileID, igribbuffer, &readsize);
      if ( ierr != 0 ) break;
      nrec++;

      gribversion = gribVersion(igribbuffer, readsize);

      if ( lunzip && (izip = gribGetZip(irecsize, igribbuffer, &unzipsize)) > 0 )
	{
	  /*
	  fprintf(stderr, "compressed data: %d %d %ld\n", izip, irecsize, unzipsize);
	  */
	  if ( izip == 128 ) /* szip */
	    {
	      if ( unzipsize < irecsize )
		{
		  fprintf(stderr, "Decompressed size smaller than compressed size (in %zu; out %zu)!\n",
			  irecsize, unzipsize);
		  continue;
		}

	      if ( itmpbuffersize < irecsize )
		{
		  itmpbuffersize = irecsize;
		  itmpbuffer = (unsigned char *) realloc(itmpbuffer, itmpbuffersize);
		}

	      memcpy(itmpbuffer, igribbuffer, itmpbuffersize);

	      unzipsize += 100; /* need 0 to 1 bytes for rounding of bds */
	      if ( igribbuffersize < unzipsize )
		{
		  igribbuffersize = unzipsize;
		  igribbuffer = (unsigned char *) realloc(igribbuffer, igribbuffersize);
		}

	      irecsize = (size_t)(gribUnzip(igribbuffer, (long)unzipsize, itmpbuffer, (long)irecsize));
	    }
	  else
	    {
	      fprintf(stderr, "Decompression for %d not implemented!\n", izip);
	    }
	}

      gh = grib_handle_new_from_message(NULL, (void *) igribbuffer, irecsize);
      GRIB_CHECK(grib_set_double(gh, "missingValue", GRIB_MISSVAL), 0);

      GRIB_CHECK(grib_get_long(gh, "editionNumber", &editionNumber), 0);

      /* get the size of the values array*/
      GRIB_CHECK(grib_get_size(gh, "values", &datasize), 0);
      GRIB_CHECK(grib_get_long(gh, "numberOfPoints", &numberOfPoints), 0);

      // printf("values_size = %d  numberOfPoints = %ld\n", datasize, numberOfPoints);


      /* get data values*/
      if ( ldecode )
	{
	  if ( allocdatasize < datasize )
	    {
	      allocdatasize = datasize;
	      data = (double *) realloc(data, datasize*sizeof(double));
	    }

	  //printf("datasize %d\n", datasize);
	  dummy = datasize;
	  GRIB_CHECK(grib_get_double_array(gh, "values", data, &dummy), 0);
	  //printf("datasize %d\n", dummy);
	}
      /*
      if ( ljdecode )
	{
	  gribExDP(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, data,
		   datasize, (int *) igribbuffer, igribbuffersize, &iword, "J", &iret);	  
	}
      */
      /*
      if ( ldecode )
	{
	  if ( regular && ISEC2_Reduced )
	    datasize = ISEC2_NumLat*ISEC2_NumLat*2;
	  else
	    datasize = isec4[0];

	  if ( allocdatasize < datasize )
	    {
	      allocdatasize = datasize;
	      data = (double *) realloc(data, datasize*sizeof(double));
	    }

	  if ( regular )
	    gribExDP(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, data,
		     datasize, (int *) igribbuffer, igribbuffersize, &iword, "R", &iret);
	  else
	    gribExDP(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, data,
		     datasize, (int *) igribbuffer, igribbuffersize, &iword, "D", &iret);
	}
      */
      if ( ljdecode )
	{
	  if ( editionNumber <= 1 )
	    {
	      GRIB_CHECK(grib_get_long(gh, "indicatorOfParameter", &lpar), 0);
	      code = (int) lpar;
	      status = grib_get_long(gh, "indicatorOfTypeOfLevel", &lpar);
	      if ( status == 0 )
		{
		  leveltype = (int) lpar;
		  GRIB_CHECK(grib_get_double(gh, "level", &dlevel), 0);
		  if ( leveltype == 100 ) dlevel *= 100;
		  if ( dlevel < -2.e9 || dlevel > 2.e9 ) dlevel = 0;
		}
	      else 
		{
		  leveltype = 0;
		  dlevel = 0;
		}
	    }
	  else
	    {
	      GRIB_CHECK(grib_get_long(gh, "parameterNumber", &lpar), 0);
	      code = (int) lpar;
	      status = grib_get_long(gh, "typeOfFirstFixedSurface", &lpar);
	      if ( status == 0 )
		{
		  leveltype = (int) lpar;
		  GRIB_CHECK(grib_get_double(gh, "level", &dlevel), 0);
		  if ( leveltype == 100 ) dlevel *= 100;
		  if ( dlevel < -2.e9 || dlevel > 2.e9 ) dlevel = 0;
		}
	      else 
		{
		  leveltype = 0;
		  dlevel = 0;
		}
	    }
	  /*
	  table  = ISEC1_CodeTable;
	  code   = ISEC1_Parameter;
	  param  = table + ((double)code)/1000;
	  level1 = ISEC1_Level1;
	  level2 = ISEC1_Level2;
	  dlevel = level1;
	  if ( ISEC1_LevelType != GRIB1_LTYPE_HYBRID    &&
	       ISEC1_LevelType != GRIB1_LTYPE_SIGMA     &&
	       ISEC1_LevelType != GRIB1_LTYPE_99        &&
	       ISEC1_LevelType != GRIB1_LTYPE_ISOBARIC  &&
	       ISEC1_LevelType != GRIB1_LTYPE_HEIGHT    &&
	       ISEC1_LevelType != GRIB1_LTYPE_LANDDEPTH &&
	       ISEC1_LevelType != GRIB1_LTYPE_SEADEPTH )
	    {
	      dlevel = (level1+level2)/2.;
	    }
      
	  if ( ISEC1_LevelType == GRIB1_LTYPE_ISOBARIC ) dlevel *= 100;
	  */
	  /*
	  GRIB_CHECK(grib_get_long(gh, "dataDate", &lpar), 0);
	  date = (int) lpar;
	  GRIB_CHECK(grib_get_long(gh, "dataTime", &lpar), 0);
	  time = (int) lpar*100;
	  */
	  GRIB_CHECK(grib_get_long(gh, "validityDate", &lpar), 0);
	  date = (int) lpar;
	  GRIB_CHECK(grib_get_long(gh, "validityTime", &lpar), 0);
	  time = (int) lpar*100;
	  
	  vdate = date;
	  vtime = time;
	  /*
	  rdate = gribRefDate(isec1);
	  rtime = gribRefTime(isec1);
	  */
	}
      /* later 
      if ( select )
	{
	  record++;

	  if ( nselrec >= 1 && record < selrec[0] ) continue;
	  if ( nselrec == 2 && record > selrec[1] ) break;

	  cdiDecodeDate(date, &year, &month, &day);
	  cdiDecodeTime(time, &hour, &minute, &second);

	  ltype = ISEC1_LevelType;
	  level = (int) dlevel;
	  bits = ISEC4_NumBits;

	  fcnum = 0;
	  
	  if ( (ISEC1_CenterID    == 98 && ISEC1_LocalFLag ==  1) ||
	       (ISEC1_SubCenterID == 98 && ISEC1_LocalFLag ==  1) ||
	       (ISEC1_CenterID    ==  7 && ISEC1_SubCenterID == 98) )
	    if ( isec1[36] == 1 )
	      fcnum = isec1[41];

	  if ( notinlist_int(NML_PAR(bits))   ||
	       notinlist_int(NML_PAR(code))   ||
	       notinlist_int(NML_PAR(fcnum))  ||
	       notinlist_int(NML_PAR(day))    ||
	       notinlist_int(NML_PAR(hour))   ||
	       notinlist_int(NML_PAR(level))  ||
	       notinlist_int(NML_PAR(ltype))  ||
	       notinlist_int(NML_PAR(minute)) ||
	       notinlist_int(NML_PAR(month))  ||
	       notinlist_flt(NML_PAR(param))  ||
	       notinlist_int(NML_PAR(record)) ||
	       notinlist_int(NML_PAR(rdate))  ||
	       notinlist_int(NML_PAR(rtime))  ||
	       notinlist_int(NML_PAR(table))  ||
	       notinlist_int(NML_PAR(vdate))  ||
	       notinlist_int(NML_PAR(vtime))  ||
	       notinlist_int(NML_PAR(year)) )
	    continue;
	}
      */
      if ( info )
	{
	  int gridtype;
	  GRIB_CHECK(grib_get_long(gh, "gridDefinitionTemplateNumber", &lpar), 0);
	  gridtype = (int) lpar;

	  nmiss = 0;
	  if ( gridtype < 50 || gridtype > 53 )
	    {
	      GRIB_CHECK(grib_get_long(gh, "numberOfMissing", &lpar), 0);
	      nmiss = (int) lpar;
	      // printf("gridtype %d, nmiss %d\n", gridtype, nmiss);
	    }

	  if ( paraminfo == 0 ) table = -1;
	  printInfo(date, time, table, code, dlevel, (int)datasize, nmiss, data);
	}
      /*
      else if ( linfo )
	{
	  gribPrintSec0(isec0);
	  gribPrintSec1(isec0, isec1);

	  if ( (isec1[4] == 0) || (isec1[4] == 64) )
	    printf(" No section 2 in GRIB message.\n");
	  else
	    gribPrintSec2DP(isec0, isec2, fsec2);
	  if ( (isec1[4] == 0) || (isec1[4] == 128) )
	    printf(" No section 3 in GRIB message.\n");
	  else
	    gribPrintSec3DP(isec0, isec3, fsec3);

	  gribPrintSec4DP(isec0, isec4, data);
	}
      else if ( dinfo )
	{
	  int i;
	  printf("Code %d   Level %d\n", ISEC1_Parameter, ISEC1_Level1);
	  for ( i = 0; i < isec4[0]; i++ )
	    {
	      printf(" %6d  %g\n", i+1, data[i]);
	    }
	}
      */
      else if ( ginfo   )  gribPrintALL(nrec, offset, recpos, (long)irecsize, igribbuffer);
      else if ( pdsinfo )  gribPrintPDS(nrec, recpos, (long)irecsize, igribbuffer);
      else if ( gdsinfo )  gribPrintGDS(nrec, recpos, (long)irecsize, igribbuffer);
      else if ( bmsinfo )  gribPrintBMS(nrec, recpos, (long)irecsize, igribbuffer);
      else if ( bdsinfo )  gribPrintBDS(nrec, recpos, (long)irecsize, igribbuffer);

      if ( ofile )
	{
	  if ( lencode )
	    {
	      void *dummy = NULL;

	      if ( edition ) GRIB_CHECK(grib_set_long(gh, "editionNumber", edition), 0);
	      GRIB_CHECK(grib_set_double_array(gh, "values", data, datasize), 0);

	      /* get the size of coded message  */
	      GRIB_CHECK(grib_get_message(gh, (const void **)&dummy, &orecsize), 0);
	      orecsize += 512; /* add some space for possible filling */

	      if ( ogribbuffersize < orecsize )
		{
		  ogribbuffersize = orecsize;
		  ogribbuffer = (unsigned char *) realloc(ogribbuffer, ogribbuffersize);
		}

	      /* get a copy of the coded message */
	      GRIB_CHECK(grib_get_message_copy(gh, ogribbuffer, &orecsize), 0);

	      nbytes = orecsize;

	      if ( lzip && gribversion == 1 )
		{
		  if ( buffersize < ogribbuffersize )
		    {
		      buffersize = ogribbuffersize;
		      buffer = (unsigned char *) realloc(buffer, buffersize);
		    }
		  memcpy(buffer, ogribbuffer, ogribbuffersize);
		  nbytes = (size_t)gribZip(ogribbuffer, (long)ogribbuffersize, buffer, (long)buffersize);
		}

	      // while ( nbytes & 7 ) ogribbuffer[nbytes++] = 0;

	      (void) gribWrite(ofileID, ogribbuffer, nbytes);
	    }
	  else
	    {
	      nbytes = irecsize;

	      if ( lzip && gribversion == 1 )
		{
		  if ( buffersize < igribbuffersize )
		    {
		      buffersize = igribbuffersize;
		      buffer = (unsigned char *) realloc(buffer, buffersize);
		    }
		  memcpy(buffer, igribbuffer, igribbuffersize);
		  /* nbytes = gribBzip(igribbuffer, igribbuffersize, buffer, buffersize); */
		  nbytes = (size_t)gribZip(igribbuffer, (long)igribbuffersize, buffer, (long)buffersize);
		}

	      // while ( nbytes & 7 ) igribbuffer[nbytes++] = 0;
	  
	      (void) gribWrite(ofileID, igribbuffer, nbytes);
	    }
	}

      grib_handle_delete(gh);
    }

  if ( ofile ) gribClose(ofileID);

  gribClose(ifileID);

  if ( --nread > 0 ) goto LABEL_READ;

  if ( igribbuffer ) free(igribbuffer);
  if ( itmpbuffer  ) free(itmpbuffer);
  if ( ogribbuffer ) free(ogribbuffer);
  if ( buffer ) free(buffer);
  if ( data ) free(data);

  if ( select ) namelistDelete(nml);
#else
  (void)argc;
  (void)argv;
 fprintf(stderr, "grib_api support not compiled in!\n");
#endif
 
  return (0);
}
