# Copyright 2005-2018 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.
#

constant ECMWF = 98 : hidden;
constant ECMWF_s = "ecmf" : hidden;
constant WMO= 0;
constant conceptsMasterDir="grib1" : hidden;
constant conceptsLocalDirECMF="grib1/localConcepts/ecmf" : hidden;
constant conceptsLocalDirAll="grib1/localConcepts/[centre:s]" : hidden;

constant tablesMasterDir="grib1" : hidden;
constant tablesLocalDir="grib1/local/[centre:s]" : hidden;

transient productionStatusOfProcessedData=0;
position offsetSection1;
section_length[3] section1Length ;
meta section1Pointer section_pointer(offsetSection1,section1Length,1);
constant wrongPadding=0;

#  GRIB tables Version No.
# (currently 3 for international exchange)
unsigned[1] table2Version  : edition_specific,dump;
alias gribTablesVersionNo=table2Version;


#assert(section1Length > 5);

#  Identification of originating/generating centre
codetable[1] centre 'common/c-1.table' : dump,string_type;
alias identificationOfOriginatingGeneratingCentre=centre;
meta centreDescription codetable_title(centre);

alias parameter.centre=centre;
alias originatingCentre=centre;
alias ls.centre = centre;

#  Generating process identification number
# (allocated by originating centre)
unsigned[1] generatingProcessIdentifier : dump ;
alias generatingProcessIdentificationNumber=generatingProcessIdentifier;
alias process=generatingProcessIdentifier;

unsigned[1] gridDefinition = 255 : edition_specific ;
flags[1] section1Flags 'grib1/1.table' = 128 : hidden ; # = section 2 present

alias centreForTable2=centre;

codetable[1] indicatorOfParameter 'grib1/2.[centreForTable2:l].[table2Version:l].table' : edition_specific,no_copy,dump;
meta parameterName codetable_title(indicatorOfParameter);
meta parameterUnits codetable_units(indicatorOfParameter);

# Local comes before Master to give precedence to the local, centre-specific table
codetable[1] indicatorOfTypeOfLevel ('3.table',tablesLocalDir,tablesMasterDir) : edition_specific,no_copy,dump,string_type;
alias levelType=indicatorOfTypeOfLevel;

transient pressureUnits="hPa";

concept_nofail typeOfLevelECMF      (unknown,         "typeOfLevel.def",conceptsMasterDir,conceptsLocalDirECMF); 
concept_nofail vertical.typeOfLevel (typeOfLevelECMF, "typeOfLevel.def",conceptsMasterDir,conceptsLocalDirAll);

when ( typeOfLevel is "isobaricInPa" ) { set pressureUnits="Pa"; }
else { set pressureUnits="hPa";}

alias ls.typeOfLevel=typeOfLevel;

if ( indicatorOfTypeOfLevel == 101 or
     indicatorOfTypeOfLevel == 104 or
     indicatorOfTypeOfLevel == 106 or
     indicatorOfTypeOfLevel == 108 or
     indicatorOfTypeOfLevel == 110 or
     indicatorOfTypeOfLevel == 112 or
     indicatorOfTypeOfLevel == 114 or
     indicatorOfTypeOfLevel == 116 or
     indicatorOfTypeOfLevel == 120 or
     indicatorOfTypeOfLevel == 121 or
     indicatorOfTypeOfLevel == 128 or
     indicatorOfTypeOfLevel == 141    )
{
    unsigned[1] topLevel : can_be_missing,dump;
    unsigned[1] bottomLevel : can_be_missing,dump;
    meta levels sprintf("%d-%d",topLevel,bottomLevel) : dump;
    alias ls.levels=levels;
    alias vertical.level = topLevel;
    alias vertical.topLevel = topLevel;
    alias vertical.bottomLevel = bottomLevel;
}
else
{
    unsigned[2] level : can_be_missing,dump;
    if (indicatorOfTypeOfLevel == 210) {
        meta marsLevel scale(level,oneConstant,hundred) : read_only;
        alias mars.levelist = marsLevel;
    }
    alias vertical.level=level;
    alias vertical.topLevel    = level;
    alias vertical.bottomLevel = level;
    alias ls.level=level;
    alias lev=level;
}

if( indicatorOfTypeOfLevel == 109 ||
    indicatorOfTypeOfLevel == 100 ||
    indicatorOfTypeOfLevel == 110 ||
    indicatorOfTypeOfLevel == 113 ||
    indicatorOfTypeOfLevel == 117)
{
    alias mars.levelist = level;
}

unsigned[1] yearOfCentury : edition_specific ;
unsigned[1] month  ;
unsigned[1] day ;
unsigned[1] hour  ;
unsigned[1] minute  ;
transient second = 0;

codetable[1] unitOfTimeRange 'grib1/4.table' = 1 : edition_specific;
alias unitOfTime=unitOfTimeRange;
alias indicatorOfUnitOfTimeRange=unitOfTimeRange;

unsigned[1] P1 : edition_specific;

unsigned[1] P2 : edition_specific;

# Local comes before Master to give precedence to the local, centre-specific table
codetable[1] timeRangeIndicator ('5.table',tablesLocalDir,tablesMasterDir) = 1 : dump,edition_specific; 

unsigned[2] numberIncludedInAverage;

meta mybits bits(numberIncludedInAverage,0,12);

unsigned[1] numberMissingFromAveragesOrAccumulations;
unsigned[1] centuryOfReferenceTimeOfData ;

codetable[1] subCentre 'grib1/0.[centre].table' : dump;

if(table2Version >= 128) {
  _if (centre != 98 && subCentre == 98) {
    alias centreForTable2 = subCentre;
  } else {
    alias centreForTable2 = centre;
  }
} else {
  alias centreForTable2 = WMO;
}

#if ( subCentre == 98 ) {
#  alias conceptsLocalDir=conceptsLocalDirECMF;
#} else {
#  alias conceptsLocalDir=conceptsLocalDirAll;
#}

concept paramIdECMF (defaultParameter,"paramId.def",conceptsMasterDir,conceptsLocalDirECMF): no_copy;
concept paramId (paramIdECMF,"paramId.def",conceptsMasterDir,conceptsLocalDirAll): long_type,dump;

concept cfNameECMF(defaultName,"cfName.def",conceptsMasterDir,conceptsLocalDirECMF) : dump,no_copy,read_only;
concept cfName(cfNameECMF,"cfName.def",conceptsMasterDir,conceptsLocalDirAll) : dump,no_copy,read_only;

concept cfVarNameECMF(defaultName,"cfVarName.def",conceptsMasterDir,conceptsLocalDirECMF) : dump,no_copy,read_only;
concept cfVarName(cfVarNameECMF,"cfVarName.def",conceptsMasterDir,conceptsLocalDirAll) : dump,no_copy,read_only;

concept unitsECMF(defaultName,"units.def",conceptsMasterDir,conceptsLocalDirECMF) : no_copy,read_only;
concept units(unitsECMF,"units.def",conceptsMasterDir,conceptsLocalDirAll) : dump,no_copy,read_only;

concept nameECMF(defaultName,"name.def",conceptsMasterDir,conceptsLocalDirECMF) : dump,no_copy,read_only;
concept name(nameECMF,"name.def",conceptsMasterDir,conceptsLocalDirAll) : dump,no_copy,read_only;

signed[2] decimalScaleFactor :dump;
transient setLocalDefinition= 0 : no_copy;

# Try different values of binaryScaleFactor and decimalScaleFactor to reduce packing error
transient optimizeScaleFactor = 0;

meta dataDate   g1date(centuryOfReferenceTimeOfData,yearOfCentury,month,day) : dump;
meta year       evaluate(dataDate / 10000) ;

meta dataTime   time(hour,minute,second) : dump;
meta julianDay  julian_day(dataDate,hour,minute,second) : edition_specific;

codetable[1] stepUnits 'stepUnits.table' = 1 : transient,dump,no_copy;

concept_nofail stepType (timeRangeIndicator, "stepType.def", conceptsMasterDir, conceptsLocalDirAll);

#alias stepTypeInternal=stepType;
#alias lengthOfTimeRange=numberIncludedInAverage;
#alias indicatorOfUnitForTimeRange=unitOfTimeRange;
#alias indicatorOfUnitForTimeIncrement=zero;
#alias timeIncrement=zero;

#if (timeRangeIndicator==113) {
#    alias lengthOfTimeRange=numberIncludedInAverage;
#    alias indicatorOfUnitForTimeRange=unitOfTimeRange;
#    alias indicatorOfUnitForTimeIncrement=unitOfTimeRange;
#    alias timeIncrement=P2;
#    alias forecastTime=P1;
#}

#if (stepType is "accum") {
#        transient accumulationRange=P2-P1;
#        alias lengthOfTimeRange=accumulationRange;
#        alias forecastTime=P1;
#        alias indicatorOfUnitForTimeRange=unitOfTimeRange;
#}

#conversion 1->2
_if (stepType is "instant" ) {
  alias productDefinitionTemplateNumber=zero;
} else {
  alias productDefinitionTemplateNumber=eight;
}

meta stepRange g1step_range(P1,P2,timeRangeIndicator,unitOfTimeRange,stepUnits,stepType) : dump;
meta startStep long_vector(stepRange,0) : dump,no_copy;
meta endStep   long_vector(stepRange,1) : dump,no_copy;

alias stepInHours = endStep;
alias ls.stepRange = stepRange;
alias ls.dataDate  = dataDate;

alias mars.step    = endStep;
alias mars.date    = dataDate;
alias mars.levtype = indicatorOfTypeOfLevel;
alias mars.time    = dataTime;
#alias mars.param   = paramId;
meta marsParam mars_param(paramId,gribTablesVersionNo,indicatorOfParameter): read_only,dump;
alias mars.param  = marsParam;

# GRIB-860: JRA55 rule for MARS.
# subCentre of 241 means Japanese Reanalysis Project
if (centre == 34 && subCentre == 241)
{
   alias mars.param = paramId;

   if (indicatorOfTypeOfLevel == 101) {
      # See ECC-467
      constant sfc_levtype = "sfc";
      alias mars.levtype = sfc_levtype;
   }
}

meta time.validityDate validity_date(dataDate,dataTime,step,stepUnits);
meta time.validityTime validity_time(dataDate,dataTime,step,stepUnits);

transient deleteLocalDefinition=0;

if(((section1Length > 40) or new() or setLocalDefinition> 0) and deleteLocalDefinition==0)
{
  constant localUsePresent = 1 : edition_specific;
  alias grib2LocalSectionPresent=present;
  
  if( (centre == ECMWF) or
      (centre != ECMWF and
        subCentre == ECMWF))
  {
    unsigned[4] perturbationNumber2 = missing(): can_be_missing, hidden;
    pad reservedNeedNotBePresent(8);
    codetable[1] localDefinitionNumber 'grib1/localDefinitionNumber.98.table' = 1 : dump;
    template  localDefinition  "grib1/local.98.[localDefinitionNumber:l].def";
    if (changed(localDefinitionNumber)) {
      if(!new() && localDefinitionNumber!=4 ) {
         section_padding localExtensionPadding : read_only;
      }
    }

    template_nofail marsKeywords "mars/grib.[stream:s].[type:s].def";
    #template marsKeywords "mars/grib.[stream:s].[type:s].def";

  }
  else
  {
    if ( !new() || setLocalDefinition ) {
        # Other centres
        unsigned[4] perturbationNumber2 = missing(): can_be_missing, hidden;
        pad reservedNeedNotBePresent(8);
        template_nofail  localDefinition  "grib1/local.[centre:l].def";
    
        section_padding localExtensionPadding : read_only;
    }
  }
}
else
{
   constant localUsePresent  = 0 : edition_specific;
   #   template defaultMarsLabeling "mars/default_labeling.def";
}

section_padding section1Padding : read_only;

#if (!wrongPadding) {
#  padtoeven evenpadding_sec1(offsetSection1,section1Length);
#}


concept shortNameECMF (defaultShortName,"shortName.def",conceptsMasterDir,conceptsLocalDirECMF) : no_copy;
concept ls.shortName (shortNameECMF,"shortName.def",conceptsMasterDir,conceptsLocalDirAll) : no_copy,dump;
meta ifsParam ifs_param(paramId,type);

alias parameter.paramId=paramId;
alias parameter.shortName=shortName;
alias parameter.units=units;
alias parameter.name=name;

alias parameter=paramId;
alias short_name=shortName;

alias time.stepRange=stepRange;
alias time.stepUnits=stepUnits;
alias time.dataDate=dataDate;
alias time.dataTime=dataTime;
alias time.startStep=startStep;
alias time.endStep=endStep;
alias time.stepType=stepType;

# ECC-457: GRIB1 to GRIB2 conversion
concept_nofail stepTypeForConversion (unknown, "stepTypeForConversion.def", conceptsMasterDir, conceptsLocalDirAll);
if (stepTypeForConversion is "accum" ) {
    alias productDefinitionTemplateNumber=eight;
}

meta md5Section1 md5(offsetSection1,section1Length);
# md5(start,length,blacklisted1,blacklisted2,...);
meta md5Product md5(offsetSection1,section1Length,gridDefinition,section1Flags,decimalScaleFactor);
