/**********************************************************************
File:  utils/grib1/GribView.C
Example program showing how one can decode an input file which has  
multiple-GRIB messages by calling the GRIB Library functions directly.

Input:  '$GRIB_ENV/data/GRIB0797.tar'
	a file containing 6 GRIB Edition 1 messages, with filler bytes
	before and after each message.

Output: 'GribView.out' 
	ASCII file contains data values for ALL of the messages found in
	input file.

Revisions:
02/02/98 atn:  change parmid/parmsub printing;
06/15/00 atn:  Main's return type is now int (for compiler)
*********************************************************************/ 
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "sigtypes.h"
#include "gribfuncs.h"  		/* GRIB library function prototypes */

/* Local function prototypes
 */

static void ProcessCommandLine
(int iArgc, 
 char *sArgv[],
 struct view_options *pOptions_a );

static void Usage( void );

struct view_options
{
  char sPath[PATHNAME_SIZE];
  SINT4 iRayCount;     /* Only print this many rays */
  SINT4 iLineLength;   /* Line length to use for data listing */
};

#define TABLE_PATH      "../tables"    /* default dir of Lookup Tables */ 
#define FILL_VALUE      -9999.00       /* default for missing data pts */

int main(int iArgc, char *sArgv[])
{
  FILE    *fout;	   /* output file */
  char    errmsg[2000];    /* required, error msgs back from Grib library */
  char    OutFn[200]; 	 /* name of output file */
  int	decoded_cnt;     /* number of messages decoded successfully */
  int     nReturn=0;       /* return status from Grib_dec           */
  int     Rd_Indexfile=0;  /* Zero to decode all msgs in input file  */
  long    offset;   	 /* byte offset from beginning of file, for inputfiles
			    with multiple GRIB messages; */
  float   *grib_data;  	 /* pointer to block of decoded data */
  
  BMS_INPUT	 bms;	/* input structure for bitmap section   */
  PDS_INPUT        pds;   /* input structure for product definition section */
  grid_desc_sec    gds;   /* input structure for grid description section */
  BDS_HEAD_INPUT   bds_head; /* input structure for bds section */
  GRIB_HDR 	 *gh1;	/* holds Msg and its info, put there by grib Seek */
  struct view_options Options;
  
  setlocale( LC_ALL, "" ) ;

  /* Process the command line arguments */
  ProcessCommandLine( iArgc, sArgv, &Options );
 
  /*
   * Initializes variables
   */
  errmsg[0] = '\0';		/* error buffer */
  offset= 0L;			/* byte offset */
  decoded_cnt = 0;		/* count of messages */
  fout = (FILE *)NULL;		/* output file */
  grib_data= (float *)NULL;  	/* decoder will create storage */
  
  /*
   * MAKE storage for Grib Header !exit on error
   */
  if ((nReturn= init_gribhdr (&gh1, errmsg) ))  goto bail_out; 
  
  /*
   * Open output file 'decoder_ex.output' to store ALL message's data (in ASCII)
   */
  sprintf (OutFn, "GribView.out");
  fout = fopen (OutFn, "w");
  if (fout == NULL) { 
    fprintf(stderr,"Failed to open output file %s\n", OutFn); 
    nReturn = 1;  /* error stat */
    goto bail_out;
  } 
  
  /*
   * loop until no more messages in File 
   */
  for  (offset = 0L; nReturn == 0;  offset += gh1->msg_length) 
    {
      int     ii;		 /* working var */
      int	D;		 /* Decimal Scale Factor */

      nReturn= grib_seek(Options.sPath, &offset, Rd_Indexfile, gh1, errmsg);
      if (nReturn)
	{	
	  fprintf(stdout,"Grib_seek returned non zero stat (%d)\n", nReturn);
	  if (nReturn == 2) break;	/* End of file error */
	  else goto bail_out;		/* abort if other error */
	}
      
      if (errmsg[0] != '\0') 
   	{ /* NO errors but got a Warning msg from seek */
	  fprintf(stdout,"%s; Skip Decoding...\n",errmsg);  
	  errmsg[0]='\0'; 	/* reset error to continue */
	  gh1->msg_length = 1L; 	/* set to 1 to bump offset up */
	  continue;
	}
      
      if (gh1->msg_length < 0) {
	fprintf(stderr, "Error:  message returned had bad length (%ld)\n",
		gh1->msg_length);
	goto bail_out;
      }
      else if (gh1->msg_length == 0) {  
	fprintf(stdout,"msg_lenth is Zero, set offset to 1\n");
	gh1->msg_length = 1L;  /* set to 1 to bump offset up */
	continue; 
      }
      
      /*
       * Clear out the Structures 
       */
      init_dec_struct(&pds,&gds,&bms,&bds_head);
      fprintf(stdout,"Decoding message found at %ld bytes ...\n",offset);
      
      /*
       * Go decode the message currently in Grib Header;
       * Float array MUST be Null, Decoder will allocate storage for it
       * If success, PDS, GDS, BDS_HEAD, BMS, GRIB_DATA are returned filled;
       */
      grib_data= (float *) NULL; 
      nReturn = grib_dec( (char *)gh1->entire_msg, &pds, &gds, &bds_head, 
			  &bms, &grib_data, errmsg);
      if (nReturn) goto bail_out;
      
      decoded_cnt++;
      
      /*
       * IF Bitmap Section is present, go apply BMS to Grib Data float array
       */
      if (bms.uslength>0)
	{
	  nReturn=apply_bitmap(&bms, &grib_data, FILL_VALUE, &bds_head,errmsg);
	  if (nReturn) goto bail_out; 
	}
      
      /*
       * .... 	  FLOAT DATA ARRAY IS READY TO GO             ....  
       * .... 	  YOU MAY CHOOSE TO DO WHATEVER HERE          ....
       * .... 	  PUT YOUR CODE FROM HERE TO <<END MARKER>>   .... 
       */
      
      /*
       * Here, let's go print it out
       */
      fprintf(stdout, "\n\t>>>  Content of GRIB Msg #%d =\n", decoded_cnt);
      prt_inp_struct(&pds, &gds, &bms, &bds_head, &grib_data);
      /*
       * Also display entire data array into ASCII output file
       */
      fprintf(fout,"decoded GRIB Msg #%d from %s\n"\
	      "  dtg= %02u%02u%02u%02u Fcstper=%03u\n",
	      decoded_cnt, Options.sPath, pds.usYear, pds.usMonth, pds.usDay, 
	      pds.usHour,pds.usP1);
      
      if (pds.usExt_flag == EXTENSION_FLAG && pds.usParm_sub != 0)
	/* GRIB Extension used */
	fprintf(fout,"  Parmid in Sub-Tbl '%c' =%03u ",
		pds.usParm_id-250 + 'A', pds.usParm_sub );
      
      else fprintf(fout,"  Parmid=%03u (Main Tbl), ", pds.usParm_id);
      
      fprintf(fout,"Levelid=%03u, GridId=%03u, lvl1=%05ld\n",
	      pds.usLevel_id, pds.usGrid_id, pds.usHeight1);
      fprintf(fout,"  Decimal Scale Factor =  %d\n", pds.sDec_sc_fctr);
      
      /* Change local 'D' to zero if the Decimal Scale factor is negative
	 Only doing this to work around "%10.-nf" format in the print statement 
      */
      D = ((int) pds.sDec_sc_fctr < 0 ?  0 : (int) pds.sDec_sc_fctr );
      
      for (ii=0; ii<(int)bds_head.ulGrid_size; ii++) {
        if (ii%5==0) fprintf(fout,"\n%5d:  ", ii);
	fprintf(fout, "%10.*f  ", D, grib_data[ii]);
      }
      fprintf(fout, "\n");
      
      /*
       *	.....     <<< END MARKER  >>>     .....
       *       .....  RETAIN THE REMAINING CODE  .....
       */
      
      /*
       * Done, now free up float array;
       */
      if (grib_data!=NULL) { free(grib_data); grib_data = NULL; }
      
    } /* FOR-loop */
  
  nReturn = 0;		/* all done, set to no error */
  
  
 bail_out:
  /*
   * IF (there is an error message) , print it out
   */
  if (errmsg[0] != '\0') 
    fprintf(stderr,"\n***ERROR: %s\n", errmsg); 
  /*
   *
   * CLEAN up before leaving
   *       !free data array if defined
   *	!close up output files if still opened
   *       !free up Grib Header struct
   */
  if (grib_data!=NULL) free(grib_data);
  if (fout != NULL) fclose (fout);
  free_gribhdr (&gh1); 
  if (!errmsg[0] && Options.sPath!=NULL && decoded_cnt==0) 
    fprintf(stdout, "No GRIB messages decoded from '%s'\n", Options.sPath);
  exit ( nReturn);
}

/* ======================================================================
 * Function to process the command line arguments.
 */
static void ProcessCommandLine
(int iArgc_a, 
 char *sArgv_a[],
 struct view_options *pOptions_a )
{

  int iArg;
  memset( pOptions_a, 0, sizeof(*pOptions_a) );
  pOptions_a->iLineLength = 80;

  /* Parse command line options
   */
  for( iArg=1 ; iArg<iArgc_a ; iArg++ )
    {
      const char *sArg = sArgv_a[iArg];
      /* fprintf( stderr, "Processing %d: '%s'\n", iArg, sArg ); */

      if ( sArg[0] == '-')
	{
	  if (0 == strncmp( sArg, "-count:", 7 ))
	    {
	      char *sEnd;
	      pOptions_a->iRayCount = strtol( &sArg[7], &sEnd, 10 );
	    }
	  else if (0 == strncmp( sArg, "-h", 2 ))
	    {
	      Usage();
	      exit(EXIT_FAILURE) ;
	    }
	  else if (0 == strncmp( sArg, "-length:", 8 ))
	    {
	      char *sEnd;
	      pOptions_a->iLineLength = strtol( &sArg[8], &sEnd, 10 );
	      if (pOptions_a->iLineLength<30) pOptions_a->iLineLength=30;
	    }
	}
      else
	{
	  strncpy( pOptions_a->sPath, sArg, PATHNAME_SIZE-1);
	}
    }
  if (!pOptions_a->sPath[0])
    {
      printf( "GribView requires a pathname arg.\n" );
      exit(EXIT_FAILURE);
    }
  return;
}
/* ==================================================
 */
static void Usage( void )
{
  fprintf( stderr, "Options:\n" );
  fprintf( stderr, "         -help     (print this list and exit)\n" );
  //  fprintf( stderr, "         -length:N (max line length to use)\n" );
  fprintf( stderr, "         pathname\n" );
  fprintf( stderr, "         (all other arguments ignored)\n" );
}

