/***************************** 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 *************************************/

#ifndef HOVTOOLKIT_H
#define HOVTOOLKIT_H

#include "Factory.h"
#include "MvHovmFrame.h"
#include "MvNetCDF.h"

enum
{
    HOV_TIME,
    HOV_GEO
};  //vertical axis: time or 'second' axis
enum
{
    HOV_NS,
    HOV_EW
};  //average direction: North-South or East-West
enum
{
    HOV_ASINDATA,
    HOV_PRESSURE
};  //height axis type options

const string HOV_VARLEVEL = "nlev";
const string HOV_VARTIME  = "time";
const string HOV_VARLAT   = "lat";
const string HOV_VARLON   = "lon";

class HovToolkit
{
public:
    HovToolkit();
    virtual ~HovToolkit();

    // Release memory
    void ReleaseAllMemory();
    void ReleaseMemory();
    void ReleaseMemoryParam();

    // Initialise internal variables
    bool GetInputParameters(MvRequest&);
    virtual bool GetInputInfo(MvRequest&) = 0;
    bool GetInputCommonInfo(MvRequest&);  //from user interface
    virtual bool GetInputInfo(MvNetCDF*) = 0;
    bool GetInputCommonInfo(MvNetCDF*);  //from the netcdf file

    // Compute Hovmoeller diagram (main routine)
    // Create a new netcdf file
    virtual bool Compute(MvRequest&, MvRequest&);

    // Compute Hovmoeller diagram (main routine)
    // Expand a existing netcdf file
    virtual bool Compute(string&, MvRequest&, string, MvRequest&);

    // Handle creating variables, data and file
    virtual bool ComputeValues(MvField&, int = 0) = 0;
    virtual bool GenerateData(MvRequest&);
    virtual bool Initialiser();

    // Create output request using information from the application
    MvRequest CreateOutputRequest();

    // Create output request using information from the request
    MvRequest CreateOutputRequest(MvRequest&);

    // Create View request
    virtual MvRequest CreateViewRequest() = 0;

    // Initialize Param Info structure
    bool CreateParamInfo(MvRequest&);

    // Create access keys
    virtual void GenerateKey(string&, MvRequest&);
    void GenerateTimeKey(string&, MvRequest&);

    // Access time/date information
    double GetRefTime() { return refTime_; }
    void SetRefTime(double ref) { refTime_ = ref; }
    MvDate GetDate(MvField&);
    double GetDateDif(string&);
    bool GetTimeInfo();
    void GetTimeInfoFromParam();

    // Handle number of points of the second coordinates
    int NPoints() { return nrPoints_; }
    void NPoints(int size) { nrPoints_ = size; }

    // Handle number of indexes
    int NrIndexes() { return nrIndexes_; }

    // Functions to handle list of levels
    virtual void InitializeLevelList() {}
    virtual void UpdateLevelList(MvField&, double) {}

    // Functions to handle the netcdf file
    bool NcAddCommonVariables();
    bool NcWriteData(MvField&, const string& key);
    void NcAddMetadata(MvNcVar*, ParamInfo*);
    string getNetcdfVarname(string);  // Get netCDF variable name
    virtual string GetTitle(ParamInfo*)   = 0;
    virtual const char* ApplicationType() = 0;
    virtual void NcWriteGlobalAttributes();
    virtual void NcWriteGlobalAttributesApp() = 0;
    virtual bool NcWriteTimeInfo();
    virtual bool NcWriteSecondCoord() = 0;

    // Update output matrix of values
    void NcFillValues(MvNcVar*, ParamInfo*);
    void NcWriteValues(MvNcVar*, IndexesInfo*, int);

    // Functions to handle the Expand option
    void ExpandOpenNcFile();
    void ExpandCloseNcFile();
    void ExpandFillValues(MvNcVar*, int&);
    bool ExpandFillValues(const char*, int, vector<double>&);
    bool ExpandGetTimeInfo();

    MvRequest GetVariableData(MvRequest&);
    void InitializeAxes(MvRequest&);

    // Functions to handle axes parameters
    virtual const char* GetSecondCoordName() = 0;  // the first axis name is "time"
    virtual const char* GetSecondAuxiliaryCoordName() { return " "; }
    virtual bool SecondAuxiliaryCoord() = 0;
    virtual bool ComputeSecondCoord()   = 0;
    virtual string GeolineConvention() { return glConvention_; }

    // Functions to handle action mode
    void ActionMode(string action) { actionMode_ = action; }
    string ActionMode() { return actionMode_; }
    bool IsVisualise();
    bool IsDataModule(const char*);

    // Get Parameter info given the key
    ParamInfo* GetParamInfo(const string&);

    // Get application view
    MvRequest GetAppView(MvRequest&);

    // Check if parameters between two requests are consistent
    virtual bool consistencyCheck(MvRequest&, MvRequest&) = 0;

    // Add information to help the Macro Converter to translate
    // the output request to a Macro code
    MvRequest buildMacroConverterRequest();

protected:
    bool swapAxes_{false};               // swap default axes
    int procType_;                // process type
    int verticalAxis_;            // Time axis or Geo axis
    int nrPoints_;                // number of points of the second axis
    int nrIndexes_;               // number of points of the time axis
    double x1_, x2_, y1_, y2_;    // geographical coordinates
    double gridNS_, gridEW_;      // grid interval
    double refTime_;              // reference Time value
    double dateMinD_, dateMaxD_;  // min/max date values
    string ncdfPath_;             // netCDF file path
    string actionMode_;           // "examine"/"save"/"execute"/...
    string glConvention_{"lonlat"};         // geoline convention: lonlat or latlon
    MvNetCDF* netcdf_{nullptr};            // netcdf structure
    MvRequest dataRequest_;       // grib data
    MvRequest origReq_;           // original input request

    // Variables related to Param info and values
    double* xint_{nullptr};           // point values
    vector<double> coord1_;  // second coordinate values (lat/lng/level)
    vector<double> coord2_;  // second coordinate values (lat/lng)
    vector<double> vtime_;   // time values
    ParamMap params_;        // structure holding computed values

    // Variables related to the Expand option
    bool expand_{false};         // true: expand option
    int nrIndexesIn_;     // number of initial time points
    string netfnameIn_;   // input netcdf filename
    MvNetCDF* netcdfIn_{nullptr};  // Input netcdf structure
};

#endif
