/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

// MvTephiData.h - Dec2004/vk  - original file
// DataThermo.h  - Jan2014/fii - update to new Thermo application
//
//  The purpose of these classes is to clean and simplify Tephigram
//  code. Note that this is partly a Q&D solution as some methods are
//  duplicated (with a simplified interface) from class MvTephiFrame.
//
//  What is more, this class hierarchy made it much easier to add new
//  data types, like plain pressure levels and UKMO New Dynamics data.
//

#ifndef DATATHERMO_H
#define DATATHERMO_H

#include "MvFieldSet.h"
#include "ParamsThermo.h"

class MvNetCDF;

//______________________________________________________________________
//                                                       MvThermoDataBase
//
//  Abstract base class for different thermoD input data types
//

class MvThermoDataBase
{
 private:

   MvThermoDataBase();
   MvThermoDataBase( MvThermoDataBase& );

 public:

   MvThermoDataBase( MvField&, const ThermoParams& );
   virtual ~MvThermoDataBase(){}

   // Initialise data values storage
   void initialiseDataMemory();

   // Reads and preprocesses one set of data, i.e. all fields valid at
   // the same time. Fields are sorted and thus we can trust the iterator.
   void readOneSetOfFields( MvFieldSetIterator& );

   //  Post-process and generate NetCDF output
   bool generate( MvNetCDF& );
   bool generateWind(MvNetCDF &netcdf);

   MvField returnToken() { return nextField_; }

   // Wind flag info
   bool windExist();

   // Title information
   string title( MvNetCDF& );

 protected:

   virtual void computeLevelsTd() = 0;
   virtual void processPressure( double ) = 0;

   // Re-scale values
   virtual void rescaleValues();

   // Get level value
   virtual int getLevel() { return (int)currField_.level(); }

   // Store parameter value
   virtual void collectValue( double );

   // Initialise a netCDF file: variables, dimensions and attributes
   bool ncInit(MvNetCDF&);

   // Add global attributes to the netcdf file
   bool ncGlobalAttributes(MvNetCDF&);

   // Get value from current field
   double getValueFromCurrentField();

   // Create a time key
   void generateTimeKey();

   // Check if LNSP field is required
   virtual bool needsLnsp() = 0;

   string formulaPrintName();

   // Variable members
   bool lnspFlag_;         // T: lnsp is available
   int  counter_;          // Number of plots
   int  tCount_;           // Temp count
   int  dCount_;           // Dewpoint count
   int  uCount_,vCount_;   // Wind count
   int  pCount_;           // Pressure/Levels count

   int  nTIME_STR_;        // 17 - yyyymmddhhmmstep + 1 ('end of string')

   // Data values storage
   vector <double> T_;     // Temperature
   vector <double> Q_;     // Humidity
   vector <double> U_;     // U wind
   vector <double> V_;     // V wind
   vector <double> TD_;    // Dewpoint
   vector <double> P_;     // Pressure
   vector <double> PUV_;   // Pressure for wind (can be different from P_)
   double LNSP_;

   string timeKey_;

   MvField currField_;
   MvField nextField_;

   const ThermoParams *pars_;
};

//______________________________________________________________________
//                                                 MvThermoDataHalfLevels
//  Class for ECMWF type level data

class MvThermoDataHalfLevels : public MvThermoDataBase
{
 public:

   MvThermoDataHalfLevels( MvField& fieldToken, const ThermoParams& pars )
    : MvThermoDataBase( fieldToken, pars ){}

   virtual ~MvThermoDataHalfLevels(){}

 protected:

   virtual void computeLevelsTd();
   virtual void processPressure( double );
   virtual  bool needsLnsp() { return true; }

};

//______________________________________________________________________
//                                                 MvThermoDataFullLevels
//  Class for "simple" level data

class MvThermoDataFullLevels : public MvThermoDataBase
{
 public:

   MvThermoDataFullLevels( MvField& fieldToken, const ThermoParams& pars )
    : MvThermoDataBase( fieldToken, pars ){}

   virtual ~MvThermoDataFullLevels(){}

 protected:

   virtual void computeLevelsTd();
   virtual void processPressure( double );
   virtual bool needsLnsp() { return true; }
};

//______________________________________________________________________
//                                             MvThermoDataPressureLevels
//  Class for data on pressure levels

class MvThermoDataPressureLevels : public MvThermoDataBase
{
 public:

   MvThermoDataPressureLevels( MvField&, const ThermoParams& );
   virtual ~MvThermoDataPressureLevels(){}

 protected:

   virtual void rescaleValues();
   virtual void computeLevelsTd();
   virtual void processPressure( double );
   virtual bool needsLnsp() { return false; }
};

//______________________________________________________________________
//                                               MvThermoDataUkmoNDLevels
//  Class for UKMO "New Dynamics" data

class MvThermoDataUkmoNDLevels : public MvThermoDataBase
{
 public:

   MvThermoDataUkmoNDLevels( MvField&, const ThermoParams& );
   virtual ~MvThermoDataUkmoNDLevels(){}

 protected:

   virtual void computeLevelsTd();
   virtual void collectValue( double );
   virtual void processPressure( double );
   virtual void rescaleValues();

   // Level value in second octet
   virtual int getLevel() { return (int)currField_.level_L2(); }

   virtual  bool needsLnsp() { return false; }
};

//______________________________________________________________________


MvThermoDataBase* MvThermoDataFactory( MvField&, const ThermoParams& );

#endif
