#ifndef  CGRIBEX_H
#define  CGRIBEX_H

#include <stdio.h>
#include <stdbool.h>
#include <sys/types.h>

#define  GRIB_MISSVAL  -9.E33

// GRIB1 Level Types
#define  GRIB1_LTYPE_SURFACE               1
#define  GRIB1_LTYPE_CLOUD_BASE            2
#define  GRIB1_LTYPE_CLOUD_TOP             3
#define  GRIB1_LTYPE_ISOTHERM0             4
#define  GRIB1_LTYPE_TROPOPAUSE            7
#define  GRIB1_LTYPE_TOA                   8
#define  GRIB1_LTYPE_SEA_BOTTOM            9
#define  GRIB1_LTYPE_ATMOSPHERE           10
#define  GRIB1_LTYPE_99                   99
#define  GRIB1_LTYPE_ISOBARIC            100
#define  GRIB1_LTYPE_ISOBARIC_PA         210
#define  GRIB1_LTYPE_MEANSEA             102
#define  GRIB1_LTYPE_ALTITUDE            103
#define  GRIB1_LTYPE_HEIGHT              105
#define  GRIB1_LTYPE_SIGMA               107
#define  GRIB1_LTYPE_SIGMA_LAYER         108
#define  GRIB1_LTYPE_HYBRID              109
#define  GRIB1_LTYPE_HYBRID_LAYER        110
#define  GRIB1_LTYPE_LANDDEPTH           111
#define  GRIB1_LTYPE_LANDDEPTH_LAYER     112
#define  GRIB1_LTYPE_ISENTROPIC          113
#define  GRIB1_LTYPE_SEADEPTH            160  // Depth Below Sea Level                                 
#define  GRIB1_LTYPE_LAKE_BOTTOM         162  // Lake or River Bottom                                  
#define  GRIB1_LTYPE_SEDIMENT_BOTTOM     163  // Bottom Of Sediment Layer                              
#define  GRIB1_LTYPE_SEDIMENT_BOTTOM_TA  164  // Bottom Of Thermally Active Sediment Layer             
#define  GRIB1_LTYPE_SEDIMENT_BOTTOM_TW  165  // Bottom Of Sediment Layer Penetrated By Thermal Wave   
#define  GRIB1_LTYPE_MIX_LAYER           166  // Mixing Layer                                          

// GRIB1 Data representation type (Grid Type) [Table 6]
#define  GRIB1_GTYPE_LATLON                0  //  latitude/longitude                                   
#define  GRIB1_GTYPE_LATLON_ROT           10  //  rotated latitude/longitude                           
#define  GRIB1_GTYPE_LATLON_STR           20  //  stretched latitude/longitude                         
#define  GRIB1_GTYPE_LATLON_ROTSTR        30  //  rotated and stretched latitude/longitude             
#define  GRIB1_GTYPE_GAUSSIAN              4  //  gaussian grid                                        
#define  GRIB1_GTYPE_GAUSSIAN_ROT         14  //  rotated gaussian grid                                
#define  GRIB1_GTYPE_GAUSSIAN_STR         24  //  stretched gaussian grid                              
#define  GRIB1_GTYPE_GAUSSIAN_ROTSTR      34  //  rotated and stretched gaussian grid                  
#define  GRIB1_GTYPE_LCC                   3  //  Lambert conformal                                    
#define  GRIB1_GTYPE_SPECTRAL             50  //  spherical harmonics                                  
#define  GRIB1_GTYPE_GME                 192  //  hexagonal GME grid                                   

// Macros for the indicator section ( Section 0 )
#define  ISEC0_GRIB_Len             (isec0[ 0])  //  Number of octets in the GRIB message              
#define  ISEC0_GRIB_Version         (isec0[ 1])  //  GRIB edition number                               


// Macros for the product definition section ( Section 1 )
#define  ISEC1_TABLE4_MINUTE      0
#define  ISEC1_TABLE4_HOUR        1
#define  ISEC1_TABLE4_DAY         2
#define  ISEC1_TABLE4_3HOURS     10
#define  ISEC1_TABLE4_6HOURS     11
#define  ISEC1_TABLE4_12HOURS    12
#define  ISEC1_TABLE4_QUARTER    13
#define  ISEC1_TABLE4_30MINUTES  14


#define  ISEC1_CodeTable            (isec1[ 0])  //  Version number of code table                 
#define  ISEC1_CenterID             (isec1[ 1])  //  Identification of centre                     
#define  ISEC1_ModelID              (isec1[ 2])  //  Identification of model                      
#define  ISEC1_GridDefinition       (isec1[ 3])  //  Grid definition                              
#define  ISEC1_Sec2Or3Flag          (isec1[ 4])  //  Section 2 or 3 included                      
#define  ISEC1_Parameter            (isec1[ 5])  //  Parameter indicator                          
#define  ISEC1_LevelType            (isec1[ 6])  //  Type of level indicator                      
#define  ISEC1_Level1               (isec1[ 7])  //  Level 1                                      
#define  ISEC1_Level2               (isec1[ 8])  //  Level 2                                      
#define  ISEC1_Year                 (isec1[ 9])  //  Year of century (YY)                         
#define  ISEC1_Month                (isec1[10])  //  Month (MM)                                   
#define  ISEC1_Day                  (isec1[11])  //  Day (DD)                                     
#define  ISEC1_Hour                 (isec1[12])  //  Hour (HH)                                    
#define  ISEC1_Minute               (isec1[13])  //  Minute (MM)                                  
#define  ISEC1_TimeUnit             (isec1[14])  //  Time unit indicator                          
#define  ISEC1_TimePeriod1          (isec1[15])  //  P1 Time period                               
#define  ISEC1_TimePeriod2          (isec1[16])  //  P2 Time period                               
#define  ISEC1_TimeRange            (isec1[17])  //  Time range indicator                         
#define  ISEC1_AvgNum               (isec1[18])  //  Number of products included in an average    
#define  ISEC1_AvgMiss              (isec1[19])  //  Number of products missing from an average   
#define  ISEC1_Century              (isec1[20])  //  Century                                      
#define  ISEC1_SubCenterID          (isec1[21])  //  Subcenter identifier                         
#define  ISEC1_DecScaleFactor       (isec1[22])  //  Decimal scale factor                         
#define  ISEC1_LocalFLag            (isec1[23])  //  Flag field to indicate local use in isec1    

#define  ISEC1_ECMWF_LocalExtension (isec1[36])
#define  ISEC1_ECMWF_Class          (isec1[37])


// Macros for the grid definition section ( Section 2 )
#define  ISEC2_GridType             (isec2[ 0])  // Data representation type 

// Triangular grids

#define  ISEC2_GME_NI2              (isec2[ 1])  //  Number of factor 2 in factorisation of Ni    
#define  ISEC2_GME_NI3              (isec2[ 2])  //  Number of factor 3 in factorisation of Ni    
#define  ISEC2_GME_ND               (isec2[ 3])  //  Nubmer of diamonds                           
#define  ISEC2_GME_NI               (isec2[ 4])  //  Number of tri. subdiv. of the icosahedron    
#define  ISEC2_GME_AFlag            (isec2[ 5])  //  Flag for orientation of diamonds (Table A)   
#define  ISEC2_GME_LatPP            (isec2[ 6])  //  Latitude of pole point                       
#define  ISEC2_GME_LonPP            (isec2[ 7])  //  Longitude of pole point                      
#define  ISEC2_GME_LonMPL           (isec2[ 8])  //  Longitude of the first diamond               
#define  ISEC2_GME_BFlag            (isec2[ 9])  //  Flag for storage sequence (Table B)          

// Spherical harmonic coeficients

#define  ISEC2_PentaJ               (isec2[ 1])  //  J pentagonal resolution parameter            
#define  ISEC2_PentaK               (isec2[ 2])  //  K pentagonal resolution parameter            
#define  ISEC2_PentaM               (isec2[ 3])  //  M pentagonal resolution parameter            
#define  ISEC2_RepType              (isec2[ 4])  //  Representation type                          
#define  ISEC2_RepMode              (isec2[ 5])  //  Representation mode                          

// Gaussian grids

#define  ISEC2_NumLon               (isec2[ 1])  //  Number of points along a parallel (Ni)       
#define  ISEC2_NumLat               (isec2[ 2])  //  Number of points along a meridian (Nj)       
#define  ISEC2_FirstLat             (isec2[ 3])  //  Latitude of the first grid point             
#define  ISEC2_FirstLon             (isec2[ 4])  //  Longitude of the first grid point            
#define  ISEC2_ResFlag              (isec2[ 5])  //  Resolution flag: 128 regular grid            
#define  ISEC2_LastLat              (isec2[ 6])  //  Latitude of the last grid point              
#define  ISEC2_LastLon              (isec2[ 7])  //  Longitude of the last grid point             
#define  ISEC2_LonIncr              (isec2[ 8])  //  i direction increment                        
#define  ISEC2_LatIncr              (isec2[ 9])  //  j direction increment                        
#define  ISEC2_NumPar               (isec2[ 9])  //  Number of parallels between a pole and the E.
#define  ISEC2_ScanFlag             (isec2[10])  //  Scanning mode flags                          
#define  ISEC2_NumVCP               (isec2[11])  //  Number of vertical coordinate parameters     

// Lambert

#define  ISEC2_Lambert_Lov          (isec2[ 6])  //  Orientation of the grid                      
#define  ISEC2_Lambert_dx           (isec2[ 8])  //  X-direction grid length                      
#define  ISEC2_Lambert_dy           (isec2[ 9])  //  Y-direction grid length                      
#define  ISEC2_Lambert_ProjFlag     (isec2[12])  //  Projection centre flag                       
#define  ISEC2_Lambert_LatS1        (isec2[13])  //  First lat at which the secant cone cuts the sphere 
#define  ISEC2_Lambert_LatS2        (isec2[14])  //  Second lat at which the secant cone cuts the sphere 
#define  ISEC2_Lambert_LatSP        (isec2[19])  //  Latitude of the southern pole                
#define  ISEC2_Lambert_LonSP        (isec2[20])  //  Longitude of the southern pole               


#define  ISEC2_Reduced              (isec2[16])  // 0: regular, 1: reduced grid                   

#define  ISEC2_ReducedPointsPtr     (&isec2[22])
#define  ISEC2_ReducedPoints(i)     (isec2[22+i]) // Number of points along each parallel         


#define  ISEC2_LatSP                (isec2[12])  // Latitude of the southern pole of rotation     
#define  ISEC2_LonSP                (isec2[13])  // Longitude of the southern pole of rotation    

#define  FSEC2_RotAngle             (fsec2[ 0])  // Angle of rotation                             
#define  FSEC2_StrFact              (fsec2[ 1])  // Stretching factor                             

// Macros for the bit map section ( Section 3 )

#define  ISEC3_PredefBitmap         (isec3[ 0])  // Predefined bitmap                             
#define  ISEC3_MissVal              (isec3[ 1])  // Missing data value for integers               
#define  FSEC3_MissVal              (fsec3[ 1])  // Missing data value for floats                 

// Macros for the binary data section ( Section 4 )

#define  ISEC4_NumValues            (isec4[ 0])  // Number of data values for encode/decode       
#define  ISEC4_NumBits              (isec4[ 1])  // Number of bits used for each encoded value    
#define  ISEC4_NumNonMissValues     (isec4[20])  // Number of non-missing values                  


#ifdef __cplusplus
extern "C" {
#endif


void  gribFixZSE(int flag);     // 1: Fix ZeroShiftError of simple packed spherical harmonics
void  gribSetConst(int flag);   // 1: Don't pack constant fields on regular grids
void  gribSetDebug(int debug);  // 1: Debugging
void  gribSetRound(int round);
void  gribSetRefDP(double refval);
void  gribSetRefSP(float  refval);
void  gribSetValueCheck(int vcheck);


void  gribExSP(int *isec0, int *isec1, int *isec2, float *fsec2, int *isec3,
               float *fsec3, int *isec4, float *fsec4, int klenp, int *kgrib,
               int kleng, int *kword, const char *hoper, int *kret);

void  gribExDP(int *isec0, int *isec1, int *isec2, double *fsec2, int *isec3,
               double *fsec3, int *isec4, double *fsec4, int klenp, int *kgrib,
               int kleng, int *kword, const char *hoper, int *kret);


const char *cgribexLibraryVersion(void);

void  gribDebug(int debug);
void  gribSetCalendar(int calendar);

void  gribDateTimeX(int *isec1, int *date, int *time, int *startDate, int *startTime);
void  gribDateTime(int *isec1, int *date, int *time);
int   gribRefDate(const int *isec1);
int   gribRefTime(const int *isec1);
bool  gribTimeIsFC(const int *isec1);

void  gribPrintSec0(int *isec0);
void  gribPrintSec1(int *isec0, int *isec1);
void  gribPrintSec2DP(int *isec0, int *isec2, double *fsec2);
void  gribPrintSec2SP(int *isec0, int *isec2, float  *fsec2);
void  gribPrintSec3DP(int *isec0, int *isec3, double *fsec3);
void  gribPrintSec3SP(int *isec0, int *isec3, float  *fsec3);
void  gribPrintSec4DP(int *isec0, int *isec4, double *fsec4);
void  gribPrintSec4SP(int *isec0, int *isec4, float  *fsec4);
void  gribPrintSec4Wave(int *isec4);

void  gribPrintALL(int nrec, long offset, long recpos, long recsize, unsigned char *gribbuffer);
void  gribPrintPDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer);
void  gribPrintGDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer);
void  gribPrintBMS(int nrec, long recpos, long recsize, unsigned char *gribbuffer);
void  gribPrintBDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer);
void  gribCheck1(int nrec, long recpos, long recsize, unsigned char *gribbuffer);
void  gribRepair1(int nrec, long recsize, unsigned char *gribbuffer);

int   gribGetZip(size_t recsize, unsigned char *gribbuffer, size_t *urecsize);

int   gribBzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize);
int   gribZip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize);
int   gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize);

int   gribOpen(const char *filename, const char *mode);
void  gribClose(int fileID);

int   gribRead(int fileID, void *buffer, size_t *buffersize);
int   gribWrite(int fileID, void *buffer, size_t buffersize);
off_t gribGetPos(int fileID);
size_t gribGetSize(int fileID);
int   gribCheckSeek(int fileID, long *offset, int *version);
int   gribFileSeek(int fileID, long *offset);
size_t gribReadSize(int fileID);
int   gribVersion(unsigned char *buffer, size_t buffersize);

int   grib_info_for_grads(off_t recpos, long recsize, unsigned char *gribbuffer, int *intnum, float *fltnum, off_t *bignum);

double calculate_pfactor_float(const float* spectralField, long fieldTruncation, long subsetTruncation);
double calculate_pfactor_double(const double* spectralField, long fieldTruncation, long subsetTruncation);

#ifdef  __cplusplus
}
#endif

#endif  /* CGRIBEX_H */ 

