#include "mars.h"
#include "grib.h"
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>

#ifdef FORTRAN_NO_UNDERSCORE
#define GRIBEX gribex
#define GRPRS0 grprs0
#define GRPRS1 grprs1
#define GRPRS2 grprs2
#define GRPRS3 grprs3
#define GRPRS4 grprs4
#define GRPRS4N grprs4n
#define GRPRS4W grprs4w
#else
#define GRIBEX gribex_
#define GRPRS0 grprs0_
#define GRPRS1 grprs1_
#define GRPRS2 grprs2_
#define GRPRS3 grprs3_
#define GRPRS4 grprs4_
#define GRPRS4N grprs4n_
#define GRPRS4W grprs4w_
#endif

long isec0[2];
long isec1[1024];
long isec2[3048];
long isec3[2];
long isec4[1024];
#ifdef REAL_8
double zsec2[2048];
double zsec3[2];
double zsec4[RSECTION_4+ 8000000];
#else
float zsec2[2048];
float zsec3[2];
float zsec4[RSECTION_4+ 8000000];
#endif

#define LEN 2048
#define BUFLEN (10*1024*1024)
#define ENDFILE -1
#define TOOBIG -3

#ifdef __uxp__
MAIN__( int argc, char ** argv)
#else
main( int argc, char ** argv)
#endif
{
static char * buffer;
static long bufferSize = BUFLEN;
long length;
long ipunp,ierr,jpack,iword;
int status;
long position;
FILE *f;
int loop;
int missing, first, countNonMissing;

long imax, imin, iaverage;
#if (defined REAL_8) && (defined RS6000)
long ivalue[2];
#else
long ivalue;
#endif
long intMissingValue;

#ifdef REAL_8
double max, min, average;
double floatMissingValue;
#else
float max, min, average;
float floatMissingValue;
#endif
int maxIndex = 0, minIndex = 0;

  if(argc < 2) {
    printf("Usage: pgrib filename\nOr:    pgrib filename offset\n");
    exit(0);
  }

  buffer = (char *) malloc(bufferSize);
  if( buffer == NULL ) {
    perror("Problem mallocing buffer space");
    exit(1);
  }
/*
// Open file.
*/
  f = fopen(argv[1],"r");
  if( f == NULL ) {
    perror("Unable to open requested file");
    exit(1);
  }
/*
// Position to the required byte offset, if any.
*/
  if(argc > 2) {
    status = fseek(f,atol(argv[2]),0);
    if( status != 0 ) {
      perror("Problem positioning file");
      exit(1);
    }
  }
/*
// Read product.
*/
  do {
    position = ftell(f);
    length = bufferSize;
    status = readany(f,buffer,&length);
/*
// If product too big for the buffer...
*/
    while ( status == TOOBIG ) {
      bufferSize *= 2;
      buffer = (char *) realloc(buffer, bufferSize);
      if( buffer == NULL ) {
        perror("Problem reallocing buffer space");
        exit(1);
      }
      status = fseek(f,position,0);
      if( status != 0 ) {
        perror("Problem positioning file");
        exit(1);
      }
      length = bufferSize;
      status = readany(f,buffer,&length);
    }
/*
// If not end-of-file
*/
    if ( status != ENDFILE ) {
      ipunp  = NUMBER(zsec4);
      ierr   = 1;
      jpack  = (length+sizeof(long)-1) / sizeof(long);

      isec3[0] = 0;
      isec3[1] = LONG_MIN;
#ifdef REAL_8
      zsec3[1] = (double) LONG_MIN;
#else
      zsec3[1] = (float) LONG_MIN;
#endif
/*
// Decode the product.
*/
      GRIBEX(isec0,isec1,isec2,zsec2,isec3,zsec3,isec4,
             zsec4,&ipunp,buffer,&jpack,&iword,"D",&ierr,1);
/*
// Print sections 0 and 1.
*/
      GRPRS0(isec0);
      GRPRS1(isec0,isec1);
/*
// Print sections 2 and 3, if they exist.
*/
      if (isec1[4] == 0 || isec1[4] == 64) {
        printf("\n No section 2 in grib message\n");
        printf(" ----------------------------\n");
      }
      else
        GRPRS2(isec0,isec2,zsec2);

      if (isec1[4] == 0 || isec1[4] == 128) {
        printf("\n No section 3 in grib message\n");
        printf(" ----------------------------\n");
        missing = 0;
      }
      else {
        GRPRS3(isec0,isec3,zsec3);
        missing = 1;
      }
/*
// Print section 4.
*/
      GRPRS4N(isec0,isec2,isec4,zsec4);
/*
// If wave 2D spectra, print extra coefficients
*/
      if( (isec1[0]==140) && (isec1[1]==98) &&
        ( (isec1[5] == 250) || (isec1[5] == 251) ) )
        GRPRS4W(isec4);

      printf("\n\n----------------- End of product ----------------------------\n\n");

/*
// Calculate max/min/average for field
*/
      if( isec4[4] == 0 ) {
/*
//      Floating point values ...
*/
        if( missing ) {
          floatMissingValue = zsec3[1];
          first = 0;
          while ( (zsec4[first] == floatMissingValue) && (first < isec4[0]) )
            first++;

          if( first == (isec4[0]-1) )
            printf("max = undefined (all values in the field are missing)\n");
          else {
            average = zsec4[first];
            max = min = zsec4[first];
            maxIndex = minIndex = first;
            countNonMissing = 1;

            for( loop = (first+1); loop < isec4[0]; loop++ ) {
              if( zsec4[loop] != floatMissingValue ) {
                countNonMissing++;
                average += zsec4[loop];
                if( zsec4[loop] > max ) {
                  max = zsec4[loop];
                  maxIndex = loop;
                }
                if( zsec4[loop] < min ) {
                  min = zsec4[loop];
                  minIndex = loop;
                }
              }
            }
            average /= countNonMissing;
            printf("max = %f (value %d), min = %f (value %d), average = %f\n",max,(maxIndex+1),min,(minIndex+1),average);
          }
        }
        else {
          average = zsec4[0];
          max = min = zsec4[0];

            for( loop = 1; loop < isec4[0]; loop++ ) {
              average += zsec4[loop];
              if( zsec4[loop] > max ) {
                max = zsec4[loop];
                maxIndex = loop;
              }
              if( zsec4[loop] < min ) {
                min = zsec4[loop];
                minIndex = loop;
              }
            }
            average /= isec4[0];
            printf("max = %f (value %d), min = %f (value %d), average = %f\n",max,(maxIndex+1),min,(minIndex+1),average);
         }
       }

      else {
/*
//      Integer values ...
*/
#if (defined REAL_8) && (defined RS6000)
        if( missing ) {
          intMissingValue = isec3[1];

          for( first = 0; first < isec4[0]; first++ ) {
            memcpy(ivalue,&zsec4[first],8);
            if( ivalue[1] != intMissingValue ) break;
          }

          if( first == (isec4[0]-1) )
            printf("max = undefined (all values in the field are missing)\n");
          else {
            iaverage = ivalue[first];
            imax = imin = ivalue[first];
            countNonMissing = 1;

            for( loop = (first+1); loop < isec4[0]; loop++ ) {
              memcpy(ivalue,&zsec4[loop],8);
              if( ivalue[1] != intMissingValue ) {
                countNonMissing++;
                iaverage += ivalue[1];
                if( ivalue[1] > imax ) {
                  imax = ivalue[1];
                  maxIndex = loop;
                }
                if( ivalue[1] < imin ) {
                  imin = ivalue[1];
                  minIndex = loop;
                }
              }
              }
#ifdef REAL_8
            average = (double) iaverage / (double) countNonMissing;
#else
            average = (float) iaverage / (float) countNonMissing;
#endif
          }
        }
        else {
          memcpy(ivalue,&zsec4[0],8);
          iaverage = ivalue[1];
          imax = imin = ivalue[1];
          for( loop = 1; loop < isec4[0]; loop++ ) {
            memcpy(ivalue,&zsec4[loop],8);
            iaverage += ivalue[1];
            if( ivalue[1] > imax ) {
              imax = ivalue[1];
              maxIndex = loop;
            }
            if( ivalue[1] < imin ) {
              imin = ivalue[1];
              minIndex = loop;
            }
          }
#ifdef REAL_8
          average = (double) iaverage / (double) isec4[0];
#else
          average = (float) iaverage / (float) isec4[0];
#endif
        }
#else
        if( missing) {
          intMissingValue = isec3[1];

          for( first = 0; first < isec4[0]; first++ ) {
            memcpy(&ivalue,&zsec4[first],sizeof(ivalue));
            if( ivalue != intMissingValue ) break;
          }

          if( first == (isec4[0]-1) )
            printf("max = undefined (all values in the field are missing)\n");
          else {
            iaverage = ivalue;
            imax = imin = ivalue;
            maxIndex = minIndex = first;
            countNonMissing = 1;

            for( loop = (first+1); loop < isec4[0]; loop++ ) {
              memcpy(&ivalue,&zsec4[loop],sizeof(ivalue));
              if( ivalue != intMissingValue ) {
                countNonMissing++;
                iaverage += ivalue;
                if( ivalue > imax ) {
                  imax = ivalue;
                  maxIndex = loop;
                }
                if( ivalue < imin ) {
                  imin = ivalue;
                  minIndex = loop;
                }
              }
            }
#ifdef REAL_8
            average = (double) iaverage / (double) countNonMissing;
#else
            average = (float) iaverage / (float) countNonMissing;
#endif
          }
        }
        else {
          memcpy(&ivalue,&zsec4[0],sizeof(ivalue));
          iaverage = ivalue;
          imax = imin = ivalue;
          for( loop = 1; loop < isec4[0]; loop++ ) {
            memcpy(&ivalue,&zsec4[loop],sizeof(ivalue));
            iaverage += ivalue;
            if( ivalue > imax ) {
              imax = ivalue;
              maxIndex = loop;
            }
            if( ivalue < imin ) {
              imin = ivalue;
              minIndex = loop;
            }
          }
#ifdef REAL_8
          average = (double) iaverage / (double) isec4[0];
#else
          average = (float) iaverage / (float) isec4[0];
#endif
        }
#endif
        printf("max = %d (value %d), min = %d (value %d), average = %f\n",imax,(maxIndex+1),imin,(minIndex+1),average);
      }
    }
/*
// If offset given, exit after one product.
*/
    if(argc>2) break;

  } while ( status != ENDFILE);      /* loop back if not end-of-file */

/*
// Unexpected error, print status.
*/
  if(status && (status != ENDFILE)) printf("Unexpected error = %d\n",status);

}
