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

// Methods for HovmoellerView class

#include "HovmoellerView.h"
#include <MvRequestUtil.hpp>
#include "ObjectList.h"
#include "PlotMod.h"
#include "Root.h"

// Hovmoeller types
static const string HOVLINE = "LINE_HOVM";
static const string HOVAREA = "AREA_HOVM";
static const string HOVVERT = "VERTICAL_HOVM";

//--------------------------------------------------------
static HovmoellerViewFactory hovmoellerViewFactoryInstance;

PlotModView*
HovmoellerViewFactory::Build ( Page& page,
                               const MvRequest& contextRequest,
                               const MvRequest& setupRequest )
{
   // Expand request
   MvRequest expReq = ObjectList::ExpandRequest(contextRequest,EXPAND_DEFAULTS);

   // Copy hidden parameters
   expReq.mars_merge(contextRequest);

   // Instantiate a Hovmoeller view
   return new HovmoellerView ( page, expReq, setupRequest );
}

//--------------------------------------------------------
static HovmoellerViewM3Factory hovmoellerViewM3FactoryInstance;

PlotModView*
HovmoellerViewM3Factory::Build ( Page& page,
                                 const MvRequest& contextRequest,
                                 const MvRequest& setupRequest )
{
   // Translate view request to Metview 4
   MvRequest viewM4Req = this->Translate(contextRequest);

   // Instantiate a Hovmoeller View
   return new HovmoellerView ( page, viewM4Req, setupRequest );
}

MvRequest
HovmoellerViewM3Factory::Translate ( const MvRequest& in )
{
   // Send a warning message
   PlotMod::Instance().MetviewError ("The Metview 3 HOVMOELLER VIEW icon is deprecated. An automatic translation to the Metview 4 HOVMOELLER VIEW icon will be performed internally, but may not work for all cases. It is recommended to manually replace the old icons with their new equivalents.","WARNING");

   // Expand request
   MvRequest req = ObjectList::ExpandRequest(in,EXPAND_DEFAULTS);

   // Copy Line parameter
   MvRequest viewReq("MHOVMOELLERVIEW");
#if 0
   viewReq.addValue("LINE",(double)req("LINE",0));
   viewReq.addValue("LINE",(double)req("LINE",1));
   viewReq.addValue("LINE",(double)req("LINE",2));
   viewReq.addValue("LINE",(double)req("LINE",3));

   // Translate Levels interval
   viewReq("BOTTOM_LEVEL") = (double)req("BOTTOM_PRESSURE");
   viewReq("TOP_LEVEL")    = (double)req("TOP_PRESSURE");

   // Copy Wind parameters
   viewReq("WIND_PARALLEL")      = (const char*)req("WIND_PARALLEL");
   viewReq("WIND_PERPENDICULAR") = (const char*)req("WIND_PERPENDICULAR");
   viewReq("WIND_INTENSITY")     = (const char*)req("WIND_INTENSITY");

   // Translate Vertical scaling parameter
   viewReq("VERTICAL_SCALING") = (const char*)req("PRESSURE_LEVEL_AXIS");

   // Overlay Control parameter is not translated
   PlotMod::Instance().MetviewError ("The Metview 3 CROSS SECTION VIEW icon is deprecated. Parameter OVERLAY CONTROL will not be internally translated.\n","WARNING");

   // Copy Page and Subpage parameters
   CopySomeParameters ( req,viewReq,"Subpage");
   CopySomeParameters ( req,viewReq,"Page");
#endif

   // Expand output request
   MvRequest out = ObjectList::ExpandRequest(viewReq,EXPAND_DEFAULTS);

   return out;
}

//-----------------------------------------------------------------

HovmoellerView::HovmoellerView ( Page& owner,
                                 const MvRequest& viewRequest,
                                 const MvRequest& setupRequest ):
                CommonXSectView ( owner, viewRequest, setupRequest )
{
   SetVariables(viewRequest,true);
   ApplicationName(type_.c_str());
}

HovmoellerView::HovmoellerView ( const HovmoellerView &old ) :
                CommonXSectView(old)
{
   type_     = old.type_;
   bDateMin_ = old.bDateMin_;
   bDateMax_ = old.bDateMax_;
   dateMin_  = old.dateMin_;
   dateMax_  = old.dateMax_;
}

string HovmoellerView::Name()
{
   int id =  Owner().Id();
   string name =  (const char*)ObjectInfo::ObjectName ( viewRequest_, "HovmoellerView", id );

   return name;
}

void HovmoellerView::DescribeYourself ( ObjectInfo& description )
{
   // Convert my request to macro
   set<Cached> skipSet;
   description.ConvertRequestToMacro ( viewRequest_, PUT_END, MacroName().c_str(),"hovmoellerview", skipSet);
   description.PutNewLine (" " );
}

void HovmoellerView::SetVariables(const MvRequest &in, bool)
{
   // Set Hovmoeller type
   type_ = (const char*)in("TYPE");

   // Set geographical coordinates
   char param[6];
   if ( in.countValues("LINE") )
       strcpy(param,"LINE");
   else
       strcpy(param,"AREA");

   latMin_ = in(param,2);
   latMax_ = in(param,0);
   lonMin_ = in(param,1);
   lonMax_ = in(param,3);

   // Set date limits
   if ( strcmp((const char*)in("DATE_MIN"),"AUTOMATIC") == 0 )
   {
      bDateMin_ = true;
      dateMin_  = "2013-01-01";
   }
   else
   {
      bDateMin_ = false;
      dateMin_  = (const char*)in("DATE_MIN");
   }

   if ( strcmp((const char*)in("DATE_MAX"),"AUTOMATIC") == 0 )
   {
      bDateMax_ = true;
      dateMax_  = "2013-01-01 00:01:00";
   }
   else
   {
      bDateMax_ = false;
      dateMax_  = (const char*)in("DATE_MAX");
   }
}

bool HovmoellerView::UpdateView ()
{
   // It has already been updated
   if ( string(viewRequest_.getVerb()) == CARTESIANVIEW )
      return true;

   // Translate common parameters
   //GetCommonParameters ( req, cartView );
   bool swapAxes = ( (const char*)viewRequest_("SWAP_AXES") &&
                     strcmp(viewRequest_("SWAP_AXES"),"YES") == 0) ? true : false;

   // Translate specific parameters
   MvRequest cartView("CARTESIANVIEW");
   if ( type_ == HOVLINE )
      UpdateViewLine( swapAxes, viewRequest_, cartView );
   else if ( type_ == HOVAREA )
      UpdateViewArea( swapAxes, viewRequest_, cartView );
   else
      UpdateViewVert( viewRequest_, cartView );

    // Copy PAGE and SUBPAGE definition
    CopySomeParameters( viewRequest_,cartView,"PAGE" );
    CopySomeParameters( viewRequest_,cartView,"SUBPAGE" );

    // Copy the original request without certain parameteres (to avoid duplication)
    RemoveParameters( viewRequest_, "HORIZONTAL_AXIS" );
    RemoveParameters( viewRequest_, "VERTICAL_AXIS" );
    RemoveParameters( viewRequest_, "PAGE" );
    RemoveParameters( viewRequest_, "SUBPAGE" );
    RemoveParameters( viewRequest_, "_" );
    cartView("_ORIGINAL_REQUEST") = viewRequest_;

    // Update request
    viewRequest_ = cartView;

    // Indicate that the plotting tree needs to be rebuilt
    Root::Instance().Refresh(false);

    return true;
}

void HovmoellerView::UpdateView ( MvRequest& view )
{
   this->ApplicationInfo(view);
}

void HovmoellerView::UpdateViewLine ( bool swapAxes, MvRequest& in, MvRequest& cartView )
{
   // Check where the axes min/max values should be taken from
   if ( (const char*)viewRequest_("_DEFAULT") &&
        (int)viewRequest_("_DEFAULT") == 1 &&
        (const char*)viewRequest_("_DATAATTACHED") &&
        strcmp((const char*)viewRequest_("_DATAATTACHED"),"YES") == 0
      )
   {
      cartView("X_AUTOMATIC") = "on";
      cartView("Y_AUTOMATIC") = "on";
   }
   else
   {
      cartView("X_AUTOMATIC") = "off";
      cartView("Y_AUTOMATIC") = "off";
   }

   // Translate Geographical and Time coordinates
   if ( swapAxes )
   {
      cartView("Y_AXIS_TYPE")     = "geoline";
      cartView("Y_MIN_LATITUDE")  = latMin_;
      cartView("Y_MAX_LATITUDE")  = latMax_;
      cartView("Y_MIN_LONGITUDE") = lonMin_;
      cartView("Y_MAX_LONGITUDE") = lonMax_;

      cartView("X_AXIS_TYPE")     = "date";
      cartView("X_DATE_MIN")      = dateMin_.c_str();
      cartView("X_DATE_MAX")      = dateMax_.c_str();

      // Copy axis definition
      cartView.setValue("HORIZONTAL_AXIS",in.getSubrequest("TIME_AXIS"));
      cartView.setValue("VERTICAL_AXIS",in.getSubrequest("GEO_AXIS"));
   }
   else
   {
      cartView("X_AXIS_TYPE")     = "geoline";
      cartView("X_MIN_LATITUDE")  = latMin_;
      cartView("X_MAX_LATITUDE")  = latMax_;
      cartView("X_MIN_LONGITUDE") = lonMin_;
      cartView("X_MAX_LONGITUDE") = lonMax_;

      cartView("Y_AXIS_TYPE")     = "date";
      cartView("Y_DATE_MIN")      = dateMin_.c_str();
      cartView("Y_DATE_MAX")      = dateMax_.c_str();

      // Copy axis definition
      cartView.setValue("HORIZONTAL_AXIS",in.getSubrequest("GEO_AXIS"));
      cartView.setValue("VERTICAL_AXIS",in.getSubrequest("TIME_AXIS"));
   }
}

void HovmoellerView::UpdateViewArea ( bool swapAxes, MvRequest& in, MvRequest& cartView )
{
   // Get geo axis
   MvRequest geoAxisReq = in.getSubrequest("GEO_AXIS");
   if ( !geoAxisReq )
      geoAxisReq.setVerb("MAXIS");

   // Check where the axes min/max values should be taken from
   bool axisAuto;
   if ( (const char*)viewRequest_("_DEFAULT") &&
        (int)viewRequest_("_DEFAULT") == 1 &&
        (const char*)viewRequest_("_DATAATTACHED") &&
        strcmp((const char*)viewRequest_("_DATAATTACHED"),"YES") == 0
      )
   {
      cartView("X_AUTOMATIC") = "on";
      cartView("Y_AUTOMATIC") = "on";
      axisAuto = true;
   }
   else
   {
      cartView("X_AUTOMATIC") = "off";
      cartView("Y_AUTOMATIC") = "off";
      axisAuto = false;
   }

   // Translate Geographical and Time coordinates
   string dir = (const char*)in("AVERAGE_DIRECTION");
   int hAxis, vAxis;  // 1 - time, 2 - latitude, 3 - longitude
   if ( swapAxes )
   {
      hAxis = ( dir == "EAST_WEST" ) ? 2 : 1;
      vAxis = ( dir == "EAST_WEST" ) ? 1 : 3;
   }
   else
   {
      hAxis = ( dir == "EAST_WEST" ) ? 1 : 3;
      vAxis = ( dir == "EAST_WEST" ) ? 2 : 1;
   }

   if ( hAxis == 1 ) // Horizontal time axis
   {
      cartView("X_AXIS_TYPE")     = "date";
      cartView("X_DATE_MIN")      = dateMin_.c_str();
      cartView("X_DATE_MAX")      = dateMax_.c_str();

      geoAxisReq("AXIS_ORIENTATION") = "VERTICAL";
      if ( vAxis == 2 ) // vertical latitude axis
      {
         geoAxisReq("AXIS_TICK_LABEL_TYPE") = "LATITUDE";
         if ( axisAuto )
            cartView("Y_AUTOMATIC_REVERSE") = "on";
         else
         {
            cartView("Y_MIN")  = latMin_;
            cartView("Y_MAX")  = latMax_;
         }
      }
      else // vertical longitude axis
      {
         cartView("Y_MIN")  = lonMin_;
         cartView("Y_MAX")  = lonMax_;
         geoAxisReq("AXIS_TICK_LABEL_TYPE") = "LONGITUDE";
      }

      // Set axes definitions
      cartView.setValue("HORIZONTAL_AXIS",in.getSubrequest("TIME_AXIS"));
      cartView.setValue("VERTICAL_AXIS",geoAxisReq);
   }
   else if ( hAxis == 2 ) // Horizontal latitude axis
   {
      cartView("X_MIN") = latMin_;
      cartView("X_MAX") = latMax_;
      geoAxisReq("AXIS_ORIENTATION")     = "HORIZONTAL";
      geoAxisReq("AXIS_TICK_LABEL_TYPE") = "LATITUDE";

      cartView("Y_AXIS_TYPE")     = "date";
      cartView("Y_DATE_MIN")      = dateMin_.c_str();
      cartView("Y_DATE_MAX")      = dateMax_.c_str();

      // Set axes definitions
      cartView.setValue("HORIZONTAL_AXIS",geoAxisReq);
      cartView.setValue("VERTICAL_AXIS",in.getSubrequest("TIME_AXIS"));
   }
   else   // Horizontal longitude axis
   {
      cartView("X_MIN") = lonMin_;
      cartView("X_MAX") = lonMax_;
      geoAxisReq("AXIS_ORIENTATION")     = "HORIZONTAL";
      geoAxisReq("AXIS_TICK_LABEL_TYPE") = "LONGITUDE";

      cartView("Y_AXIS_TYPE")     = "date";
      cartView("Y_DATE_MIN")      = dateMin_.c_str();
      cartView("Y_DATE_MAX")      = dateMax_.c_str();

      // Set axes definitions
      cartView.setValue("HORIZONTAL_AXIS",geoAxisReq);
      cartView.setValue("VERTICAL_AXIS",in.getSubrequest("TIME_AXIS"));
   }
}

void HovmoellerView::UpdateViewVert ( MvRequest& in, MvRequest& cartView )
{
   // Vertical scaling mode
   const char* vs = "regular";
   if ( (const char*)in("VERTICAL_SCALING") && strcmp((const char*)in("VERTICAL_SCALING"),"LOG") == 0 )
      vs = "logarithmic";

   // Check where the axes min/max values should be taken from
   if ( (const char*)viewRequest_("_DEFAULT") &&
        (int)viewRequest_("_DEFAULT") == 1 &&
        (const char*)viewRequest_("_DATAATTACHED") &&
        strcmp((const char*)viewRequest_("_DATAATTACHED"),"YES") == 0
      )
   {
      cartView("X_AUTOMATIC") = "on";
      cartView("Y_AUTOMATIC") = "on";
   }
   else
   {
      cartView("X_AUTOMATIC") = "off";
      cartView("Y_AUTOMATIC") = "off";
   }

   // Translate Vertical and Time coordinates
   cartView("X_AXIS_TYPE") = "date";
   cartView("X_DATE_MIN")  = dateMin_.c_str();
   cartView("X_DATE_MAX")  = dateMax_.c_str();

   cartView("Y_AXIS_TYPE") = vs;
   cartView("Y_MIN")       = yMin_;
   cartView("Y_MAX")       = yMax_;

   // Copy axis definition
   cartView.setValue("HORIZONTAL_AXIS",in.getSubrequest("TIME_AXIS"));
   cartView.setValue("VERTICAL_AXIS",in.getSubrequest("VERTICAL_AXIS"));
}

void HovmoellerView::ApplicationInfo( const MvRequest& req)
{
   // If it is not a VIEW request, try to find a hidden VIEW in the request
   MvRequest viewReq;
   if ( ObjectList::IsView(req.getVerb()) )
      viewReq = req;
   else
   {
      MvRequest aux = req.getSubrequest("NETCDF_DATA");
      if ( (const char*)aux("_CARTESIANVIEW") )
         viewReq = aux.getSubrequest("_CARTESIANVIEW");
      else
      {
         PlotMod::Instance().MetviewError ("Missing View Request in HovmoellerView::ApplicationInfo","WARNING");
         return;
      }
   }

   // Update the DATE_MIN/MAX parameters in the View if the original values
   // were AUTOMATIC and the Hovmoeller application provided new values
   if ( bDateMin_ )
   {
      string str = (const char*)viewReq("X_DATE_MIN") ? "X_DATE_MIN" : "Y_DATE_MIN";
      dateMin_ = (const char*)viewReq(str.c_str());
      viewRequest_(str.c_str()) = dateMin_.c_str();
      bDateMin_ = false;
   }
   if ( bDateMax_ )
   {
      string str = (const char*)viewReq("X_DATE_MAX") ? "X_DATE_MAX" : "Y_DATE_MAX";
      dateMax_ = (const char*)viewReq(str.c_str());
      viewRequest_(str.c_str()) = dateMax_.c_str();
      bDateMax_ = false;
   }

   return;
}
