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

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

//----------------------------------------------------------
static VertProfViewFactory vertprofViewFactoryInstance;

PlotModView*
VertProfViewFactory::Build ( Page& page,
                             const MvRequest& contextRequest,
                             const MvRequest& setupRequest )
{
   return new VertProfView ( page, contextRequest, setupRequest );
}

//--------------------------------------------------------
static VertProfViewM3Factory vertProfViewM3FactoryInstance;

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

   // Instantiate a VerticalProfile View
   return new VertProfView ( page, viewM4Req, setupRequest );
}

MvRequest
VertProfViewM3Factory::Translate ( const MvRequest& in )
{
   // Send a warning message
   //PlotMod::Instance().errorMessage("Error Message");
   //PlotMod::Instance().warningMessage("Warning Message\n");
   PlotMod::Instance().MetviewError ("The Metview 3 VERTICAL PROFILE VIEW icon is deprecated. An automatic translation to the Metview 4 VERTICAL PROFILE 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 Input Mode, Pont and Area parameters
   MvRequest viewReq("MVPROFILEVIEW");
   viewReq("INPUT_MODE") = (const char*)req("INPUT_MODE");
   if ( req.countValues("POINT") )
   {
      viewReq.addValue("POINT",(double)req("POINT",0));
      viewReq.addValue("POINT",(double)req("POINT",1));
   }
   if ( req.countValues("AREA") )
   {
      viewReq.addValue("AREA",(double)req("AREA",0));
      viewReq.addValue("AREA",(double)req("AREA",1));
      viewReq.addValue("AREA",(double)req("AREA",2));
      viewReq.addValue("AREA",(double)req("AREA",3));
   }

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

   // Translate axes parameters
   viewReq.setValue("LEVEL_AXIS", req.getSubrequest("PRESSURE_AXIS"));
   viewReq.setValue("VALUE_AXIS", req.getSubrequest("VALUE_AXIS"));

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

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

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

   return out;
}

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

VertProfView::VertProfView ( Page& owner,
                             const MvRequest& viewRequest,
                             const MvRequest& setupRequest ) :
              CommonXSectView ( owner, viewRequest, setupRequest),
              yReverse_ ("off"),
              xValuesAuto_ (true),
              xMin_ (0.),
              xMax_ (100.)
{
    ApplicationName("MVPROFILE");
    SetVariables(viewRequest,true);
}

VertProfView::VertProfView (const VertProfView& old) :
              CommonXSectView ( old ),
              yReverse_ (old.yReverse_),
              xValuesAuto_ (old.xValuesAuto_),
              xMin_ (old.xMin_),
              xMax_ (old.xMax_)
{
}

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

   return name;
}

void VertProfView::DescribeYourself ( ObjectInfo& description )
{
   // Use the original request to describe the View
   MvRequest viewReq = viewRequest_("_ORIGINAL_REQUEST");

   // Convert my request to macro
   set<Cached> skipSet;
   description.ConvertRequestToMacro ( viewReq, PUT_END, MacroName().c_str(),"mvertprofview",skipSet);
   description.PutNewLine (" " );
}

void VertProfView::SetVariables(const MvRequest& in, bool setMembers)
{
   string param = ( in.countValues("POINT") ) ? "POINT" : "AREA";

   // Called with a viewRequest
   if ( setMembers )
   {
      if ( in.countValues("POINT") )
      {
         latMin_ = latMax_ = in("POINT",0);
         lonMin_ = lonMax_ = in("POINT",1);
      }
      else
      {
         latMin_ = in("AREA",0);
         latMax_ = in("AREA",2);
         lonMin_ = in("AREA",1);
         lonMax_ = in("AREA",3);
      }
    }
    else   // Called with a netCDF request
    {
       if ( in.countValues("POINT") )
       {
          viewRequest_.unsetParam("POINT");
          viewRequest_.addValue("POINT",(double)in("POINT",0));
          viewRequest_.addValue("POINT",(double)in("POINT",1));
       }
       else
       {
          viewRequest_.unsetParam("AREA");
          viewRequest_.addValue("AREA",(double)in("AREA",0));
          viewRequest_.addValue("AREA",(double)in("AREA",1));
          viewRequest_.addValue("AREA",(double)in("AREA",2));
          viewRequest_.addValue("AREA",(double)in("AREA",3));
       }
    }

    // Save some data specific to some DataApplication
    ApplicationInfo(in);
}

bool VertProfView::UpdateView ()
{
   // It has already been updated
   if ( string(viewRequest_.getVerb()) == CARTESIANVIEW )
   {
      // First drop: data was dropped in an empty View. In this case, if user has not
      // selected X_MIN/MAX values, update parameter X_AUTOMATIC to ON. Initially, it was
      // forced to be OFF because MAGICS requires min/max values.
      if ( xValuesAuto_ &&
           strcmp( (const char*)viewRequest_("X_AUTOMATIC"), "OFF") == 0
         )
           viewRequest_("X_AUTOMATIC") = "ON";

      return true;
   }

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

   // Translate X coordinates
   bool ierror = false;
   MvRequest cartView("CARTESIANVIEW");
   cartView("X_AXIS_TYPE") = "REGULAR";
   if ( axisAuto )
      cartView("X_AUTOMATIC") = "on";
   else
   {
      cartView("X_AUTOMATIC") = "OFF";
      int nvals = viewRequest_.countValues("X_MIN_MAX");
      if ( nvals != 0 && nvals != 2 )
         ierror = true;
      else
      {
         string sx1,sx2;
         if ( nvals == 0 )
         {
            sx1 = "AUTO";
            sx2 = "AUTO";
         }
         else
         {
            // Read X values
            sx1 = (const char*)viewRequest_("X_MIN_MAX",0);
            sx2 = (const char*)viewRequest_("X_MIN_MAX",1);
         }

         if ( sx1 == "AUTO" && sx2 == "AUTO" )
         {
            xValuesAuto_ = true;

            // it seems that this is no longer needed
            //if ( (const char*)viewRequest_("_DATAATTACHED") &&
                 //strcmp((const char*)viewRequest_("_DATAATTACHED"),"YES") == 0 )
                     cartView("X_AUTOMATIC") = "ON";
         }
         else if ( sx1 == "AUTO" || sx2 == "AUTO" )
            ierror = true;
         else
         {
            xValuesAuto_ = false;
            xMin_ = viewRequest_("X_MIN_MAX",0);
            xMax_ = viewRequest_("X_MIN_MAX",1);
            cartView("X_MIN") = xMin_;
            cartView("X_MAX") = xMax_;
         }
      }
   }

   if ( ierror )
   {
       PlotMod::Instance().MetviewError ("Icon VERTICAL PROFILE VIEW, parameter X_MIN_MAX, has invalid input values. Please use the default values (AUTO/AUTO) or provide 2 numerical values.","WARNING");
       return false;
   }

   // Translate Y coordinates
   if ( axisAuto )
   {
      cartView("Y_AUTOMATIC") = "on";
      cartView("Y_AUTOMATIC_REVERSE") = yReverse_.c_str();
   }
   else
   {
      cartView("Y_AUTOMATIC") = "OFF";
      cartView("Y_MIN") = yMin_;
      cartView("Y_MAX") = yMax_;
   }

   const char* log = viewRequest_("VERTICAL_SCALING");
   cartView("Y_AXIS_TYPE") = ( log && strcmp(log,"LOG") == 0) ? "logarithmic" : "REGULAR";

   // Translate axes definitions
   cartView.setValue("HORIZONTAL_AXIS",viewRequest_.getSubrequest("VALUE_AXIS"));
   cartView.setValue("VERTICAL_AXIS",viewRequest_.getSubrequest("LEVEL_AXIS"));

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

   // Save the original request
   cartView("_ORIGINAL_REQUEST") = viewRequest_;

    // Update request
    viewRequest_ = cartView;;

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

    return true;
}

void VertProfView::ApplicationInfo ( const MvRequest& req )
{
   // Save direction of the vertical axis
   if ( (const char*)req("Y_AUTOMATIC_REVERSE") )
      yReverse_ = (const char*)req("Y_AUTOMATIC_REVERSE");
   else if ( (const char*)req("_Y_AUTOMATIC_REVERSE") )
      yReverse_ = (const char*)req("_Y_AUTOMATIC_REVERSE");
}

bool VertProfView::ConsistencyCheck( MvRequest& req1, MvRequest& req2 )
{
   // Build a list of parameters to be checked
   vector<string> params;
   params.push_back("INPUT_MODE");
   if ( (const char*)req1("POINT") )
      params.push_back("POINT");
   else
      params.push_back("AREA");

   // Call a function to perform the consistency check
   return req1.checkParameters(req2,params);
}