# Copyright 2005-2017 ECMWF.
#
# This software is licensed under the terms of the Apache Licence Version 2.0
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
#
# In applying this licence, ECMWF does not waive the privileges and immunities granted to it by
# virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction.
#

# START grib1::section
# SECTION 4, Binary data section
#  Length of section
# (octets)
position offsetSection4;

# Due to a trick done by GRIBEX to support large GRIBs, we need a special treatment
# of the message length and of the section4 lenth, so instead of
# length[3] section4Length                     ;
# we get:
g1_section4_length[3] section4Length(totalLength);

meta section4Pointer section_pointer(offsetSection4,section4Length,4);

g1_half_byte_codeflag halfByte;
flags[1] dataFlag "grib1/11.table" = 0 : read_only;
signed[2] binaryScaleFactor = 0 : read_only,dump;
ibmfloat referenceValue : read_only,dump;

meta referenceValueError reference_value_error(referenceValue,ibm);

flagbit sphericalHarmonics(dataFlag,7) : dump;
flagbit complexPacking(dataFlag,6) : dump;
flagbit integerPointValues(dataFlag,5) : dump;
flagbit additionalFlagPresent(dataFlag,4) : edition_specific,dump;

# second order packing
if (complexPacking && sphericalHarmonics==0) {
	unsigned[1] widthOfFirstOrderValues : dump ;
	unsigned [2] N1;
	flags[1] extendedFlag "grib1/11-2.table";

	#  Undocumented use of octet 14 extededFlags
	#  Taken from d2ordr.F
	#         R------- only bit 1 is reserved.
	#         -0------ single datum at each grid point.
	#         -1------ matrix of values at each grid point.
	#         --0----- no secondary bit map.
	#         --1----- secondary bit map present.
	#         ---0---- second order values have constant width.
	#         ---1---- second order values have different widths.
	#         ----0--- no general extended second order packing.
	#         ----1--- general extended second order packing used.
	#         -----0-- standard field ordering in section 4.
	#         -----1-- boustrophedonic ordering in section 4.
	#         ------00 no spatial differencing used.
	#         ------01 1st-order spatial differencing used.
	#         ------10 2nd-order    "         "         " .
	#         ------11 3rd-order    "         "         " .

	#ksec4(8)
	flagbit matrixOfValues              (extendedFlag,6) = 0  : dump;
	#ksec4(9)
	flagbit secondaryBitmapPresent      (extendedFlag,5) = 0  : dump;
	#ksec4(10)
	flagbit secondOrderOfDifferentWidth (extendedFlag,4) = 0  : dump;
	#ksec4(12)
	flagbit generalExtended2ordr        (extendedFlag,3) = 0  : dump;
	#ksec4(13)
	flagbit boustrophedonicOrdering     (extendedFlag,2) = 0  : dump;
	#ksec4(14)
	flagbit twoOrdersOfSPD              (extendedFlag,1) = 0  : dump;
	#ksec4(15)
	flagbit plusOneinOrdersOfSPD        (extendedFlag,0) = 0  : dump;
	meta orderOfSPD evaluate(plusOneinOrdersOfSPD + 2 * twoOrdersOfSPD);
	alias secondaryBitmap = secondaryBitmapPresent;
	alias boustrophedonic=boustrophedonicOrdering;
}  else {
	transient orderOfSPD=2;
	transient boustrophedonic=0;
}
transient hideThis=0;

concept packingType {
#set uses the last one
#get returns the first match
  "grid_simple"                       = { sphericalHarmonics = 0; complexPacking = 0; additionalFlagPresent = 0;}
  "grid_ieee"                         = { sphericalHarmonics = 0; complexPacking = 0;
                                          integerPointValues=1; additionalFlagPresent=1;}
  "spectral_complex"                  = { sphericalHarmonics = 1; complexPacking = 1;
											additionalFlagPresent = 0; }
  "spectral_simple"                   = { sphericalHarmonics = 1; complexPacking = 0; additionalFlagPresent = 0;
                                          representationMode=1;}
  "spectral_ieee"                  = { sphericalHarmonics = 1; complexPacking = 1;
											additionalFlagPresent = 0;hideThis=1; }
  "grid_simple_matrix"                = { sphericalHarmonics = 0; complexPacking = 0; additionalFlagPresent = 1;}

  "grid_second_order_row_by_row"        = {	sphericalHarmonics = 0; complexPacking = 1; secondOrderOfDifferentWidth=1; 
  											matrixOfValues=0; secondaryBitmapPresent=0; generalExtended2ordr=0; }
  "grid_second_order_constant_width"    = {	sphericalHarmonics = 0; complexPacking = 1; secondOrderOfDifferentWidth=0; 
  											matrixOfValues=0; secondaryBitmapPresent=1; generalExtended2ordr=0; }
  "grid_second_order_general_grib1"    = {sphericalHarmonics = 0; complexPacking = 1; secondOrderOfDifferentWidth=1; 
  									matrixOfValues=0; secondaryBitmapPresent=1; generalExtended2ordr=0; }
  "grid_second_order_no_SPD"  = { 	sphericalHarmonics = 0; complexPacking = 1; secondOrderOfDifferentWidth=1; 
  									matrixOfValues=0; secondaryBitmapPresent=0; generalExtended2ordr=1;
									plusOneinOrdersOfSPD=0; twoOrdersOfSPD=0;}
  "grid_second_order"  = { 	sphericalHarmonics = 0; complexPacking = 1; secondOrderOfDifferentWidth=1; 
  									matrixOfValues=0; secondaryBitmapPresent=0; generalExtended2ordr=1;
									plusOneinOrdersOfSPD=0; twoOrdersOfSPD=1; boustrophedonic=1;}
  "grid_second_order"  = { 	sphericalHarmonics = 0; complexPacking = 1; secondOrderOfDifferentWidth=1; 
  									matrixOfValues=0; secondaryBitmapPresent=0; generalExtended2ordr=1;
									plusOneinOrdersOfSPD=0; twoOrdersOfSPD=1; boustrophedonic=0;}
  "grid_second_order_no_boustrophedonic"  = { 	sphericalHarmonics = 0; complexPacking = 1; secondOrderOfDifferentWidth=1; 
  									matrixOfValues=0; secondaryBitmapPresent=0; generalExtended2ordr=1;
									plusOneinOrdersOfSPD=0; twoOrdersOfSPD=1; boustrophedonic=0;}
  "grid_second_order_boustrophedonic"  = { 	sphericalHarmonics = 0; complexPacking = 1; secondOrderOfDifferentWidth=1; 
  									matrixOfValues=0; secondaryBitmapPresent=0; generalExtended2ordr=1;
									plusOneinOrdersOfSPD=0; twoOrdersOfSPD=1; boustrophedonic=1;}
  "grid_second_order_SPD1"  = { 	sphericalHarmonics = 0; complexPacking = 1; secondOrderOfDifferentWidth=1; 
  									matrixOfValues=0; secondaryBitmapPresent=0; generalExtended2ordr=1; 
									plusOneinOrdersOfSPD=1; twoOrdersOfSPD=0; }
  "grid_second_order_SPD2"  = { 	sphericalHarmonics = 0; complexPacking = 1; secondOrderOfDifferentWidth=1; 
  									matrixOfValues=0; secondaryBitmapPresent=0; generalExtended2ordr=1; 
									plusOneinOrdersOfSPD=0; twoOrdersOfSPD=1; }
  "grid_second_order_SPD3"  = { 	sphericalHarmonics = 0; complexPacking = 1; secondOrderOfDifferentWidth=1; 
  									matrixOfValues=0; secondaryBitmapPresent=0; generalExtended2ordr=1; 
									plusOneinOrdersOfSPD=1; twoOrdersOfSPD=1; }
  "grid_jpeg"                         = { sphericalHarmonics = 0; complexPacking = 0; additionalFlagPresent = 0;}
  "grid_png"                          = { sphericalHarmonics = 0; complexPacking = 0; additionalFlagPresent = 0;}
  "grid_ccsds"                        = { sphericalHarmonics = 0; complexPacking = 0; additionalFlagPresent = 0;}
  "grid_simple_log_preprocessing"= { sphericalHarmonics = 0; complexPacking = 0; additionalFlagPresent = 0;}
} : dump;


alias ls.packingType=packingType;
alias typeOfPacking=packingType;

if( binaryScaleFactor == -32767) {

unsigned[1] bitsPerValue : dump ;
alias numberOfBitsContainingEachPackedValue = bitsPerValue;

  constant dataRepresentationTemplateNumber = 0;
  constant bitMapIndicator = 0;
  # For grib 1 -> 2
  position offsetBeforeData;
  transient numberOfCodedValues=numberOfPoints;
  meta values data_dummy_field(
        section4Length,
        offsetBeforeData,
        offsetSection4,
        unitsFactor,
        unitsBias,
        changingPrecision,
        numberOfCodedValues,
        bitsPerValue,
        referenceValue,
        binaryScaleFactor,
        decimalScaleFactor,
        halfByte,
		packingType,
		grid_ieee,precision,
        missingValue,
        numberOfPoints,
        bitmap
      ) : dump;
} else {
  template dataValues "grib1/data.[packingType:s].def";
}

position offsetAfterData;

transient dataLength=(offsetAfterData-offsetBeforeData)/8;

if (bitmapPresent==1) {
  alias numberOfEffectiveValues=numberOfDataPoints;
} else {
  alias numberOfEffectiveValues=numberOfCodedValues;
}

_if (sphericalHarmonics) {
	alias numberOfEffectiveValues=numberOfValues;
}

meta changeDecimalPrecision decimal_precision(bitsPerValue,decimalScaleFactor,changingPrecision,values)  : edition_specific;
meta decimalPrecision decimal_precision(bitsPerValue,decimalScaleFactor,changingPrecision)  : edition_specific;
alias setDecimalPrecision=changeDecimalPrecision;

meta bitsPerValueAndRepack bits_per_value(values,bitsPerValue)  : edition_specific;
alias setBitsPerValue=bitsPerValueAndRepack;

meta scaleValuesBy scale_values(values,missingValue) : edition_specific;
meta offsetValuesBy offset_values(values,missingValue) : edition_specific;

concept gridType {
#set uses the last one
#get returns the first match
  "regular_ll"           = {dataRepresentationType = 0;  sphericalHarmonics = 0; PLPresent=0;}
  "reduced_ll"           = {dataRepresentationType = 0;  sphericalHarmonics = 0; PLPresent=1; Ni=missing(); }
  "mercator"             = {dataRepresentationType = 1;  sphericalHarmonics = 0; PLPresent=0; }
  "lambert"              = {dataRepresentationType = 3;  sphericalHarmonics = 0; PLPresent=0; }
  "polar_stereographic"  = {dataRepresentationType = 5;  sphericalHarmonics = 0; PLPresent=0; }
  "UTM"                  = {dataRepresentationType = 6;  sphericalHarmonics = 0; PLPresent=0; }
  "simple_polyconic"     = {dataRepresentationType = 7;  sphericalHarmonics = 0; PLPresent=0; }
  "albers"               = {dataRepresentationType = 8;  sphericalHarmonics = 0; PLPresent=0; }
  "miller"               = {dataRepresentationType = 8;  sphericalHarmonics = 0; PLPresent=0; }
  "rotated_ll"           = {dataRepresentationType = 10; sphericalHarmonics = 0; PLPresent=0; }
  "stretched_ll"         = {dataRepresentationType = 20; sphericalHarmonics = 0; PLPresent=0; }
  "stretched_rotated_ll" = {dataRepresentationType = 30; sphericalHarmonics = 0; PLPresent=0; }
  "regular_gg"           = {dataRepresentationType = 4;  sphericalHarmonics = 0; PLPresent=0; }
  "rotated_gg"           = {dataRepresentationType = 14; sphericalHarmonics = 0; PLPresent=0; }
  "stretched_gg"         = {dataRepresentationType = 24; sphericalHarmonics = 0; PLPresent=0; }
  "stretched_rotated_gg" = {dataRepresentationType = 34; sphericalHarmonics = 0; PLPresent=0; }
  "reduced_gg"           = {dataRepresentationType = 4;  sphericalHarmonics = 0;
                            PLPresent=1; numberOfPointsAlongAParallel = missing();
                            iDirectionIncrement = missing(); ijDirectionIncrementGiven=0;}

  "reduced_rotated_gg"   = {dataRepresentationType = 14;  sphericalHarmonics = 0;
                            PLPresent=1; numberOfPointsAlongAParallel = missing();
                            iDirectionIncrement = missing(); ijDirectionIncrementGiven=0;}
  "reduced_stretched_gg" = {dataRepresentationType = 24;  sphericalHarmonics = 0;
                            PLPresent=1; numberOfPointsAlongAParallel = missing();
                            iDirectionIncrement = missing(); ijDirectionIncrementGiven=0;}
  "reduced_stretched_rotated_gg" = {dataRepresentationType = 34;  sphericalHarmonics = 0;
                            PLPresent=1; numberOfPointsAlongAParallel = missing();
                            iDirectionIncrement = missing(); ijDirectionIncrementGiven=0;}

# For consistency add the prefix regular_
"regular_rotated_gg"           = { dataRepresentationType = 14; sphericalHarmonics = 0; PLPresent=0; } # = rotated_gg
"regular_stretched_gg"         = { dataRepresentationType = 24; sphericalHarmonics = 0; PLPresent=0; } # = stretched_gg
"regular_stretched_rotated_gg" = { dataRepresentationType = 34; sphericalHarmonics = 0; PLPresent=0; } # = stretched_rotated_gg


  "sh"                   = {dataRepresentationType = 50; sphericalHarmonics = 1; PLPresent=0; }
  "rotated_sh"           = {dataRepresentationType = 60; sphericalHarmonics = 1; PLPresent=0; }
  "stretched_sh"         = {dataRepresentationType = 70; sphericalHarmonics = 1; PLPresent=0; }
  "stretched_rotated_sh" = {dataRepresentationType = 80; sphericalHarmonics = 1; PLPresent=0; }
  "space_view"           = {dataRepresentationType = 90; sphericalHarmonics = 0; PLPresent=0; }
  "unknown"              = {PLPresent=0;}
  "unknown_PLPresent"    = {PLPresent=1;}
} : dump;

alias ls.gridType=gridType;
alias geography.gridType=gridType;
alias typeOfGrid=gridType;

meta getNumberOfValues size(values) : edition_specific,dump ;

if (complexPacking==0 || sphericalHarmonics==1) {
	padtoeven padding_sec4_1(offsetSection4,section4Length) ;
}

meta md5Section4 md5(offsetSection4,section4Length);
alias md5DataSection = md5Section4;

