/***************************** 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 "ThermoView.h"
#include "MvRequestUtil.hpp"
#include "ObjectList.h"
#include "PlotMod.h"
#include "PmContext.h"
#include "Root.h"

// Thermo types
static const string THERMOTEPHI   = "TEPHIGRAM";
static const string THERMOSKEWT   = "SKEW_T";
static const string THERMOEMAGRAM = "EMAGRAM";
static const string THERMOSTUVE   = "STUVE";

// Thermo data types
map<string,string> create_dataTypeMap()
{
   map<string,string> m;
   m["GRIB"] = "GRIB_THERMO";
   m["BUFR"] = "BUFR_THERMO";
   m["ODB"]  = "ODB_THERMO";
   return m;
}

static map<string,string> DATA_TYPE = create_dataTypeMap();

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

static ThermoViewFactory thermoViewFactoryInstance;

PlotModView*
ThermoViewFactory::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 Thermo view
   return new ThermoView ( page, expReq, setupRequest );
}

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

ThermoView::ThermoView ( Page& owner,
                         const MvRequest& viewRequest,
                         const MvRequest& setupRequest ):
               CommonXSectView ( owner, viewRequest, setupRequest ),
               type_("TEPHIGRAM")
{
   SetVariables(viewRequest,true);
}

ThermoView::ThermoView ( const ThermoView &old ) :
               CommonXSectView(old)
{
   type_ = old.type_;
}

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

   return name;
}

void ThermoView::DescribeYourself ( ObjectInfo& description )
{
   // Convert my request to Macro
   set<Cached> skipSet;
   description.ConvertRequestToMacro ( appViewReq_, PUT_END, MacroName().c_str(),"thermoview", skipSet);
   description.PutNewLine (" " );
}

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

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

   // Create a Cartesian View request related to Tephigram
   // Magics requires that the value for parameter map_projection be 
   // in lower case
   MvRequest cartView("CARTESIANVIEW");
   string sdata = type_;
   std::transform(sdata.begin(), sdata.end(), sdata.begin(), ::tolower);
   cartView("MAP_PROJECTION") = sdata.c_str();

   // Translate axes min/max values
   // Check where the 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";

      // Get min/max axes coordinates
      cartView("X_MIN") = viewRequest_("MINIMUM_TEMPERATURE");
      cartView("X_MAX") = viewRequest_("MAXIMUM_TEMPERATURE");
      cartView("Y_MIN") = viewRequest_("BOTTOM_PRESSURE");
      cartView("Y_MAX") = viewRequest_("TOP_PRESSURE");
   }

   // Copy ThermoGrid definition
   MvRequest reqGrid = viewRequest_.getSubrequest("THERMO_GRID");
   if ( reqGrid )
      cartView("THERMO_GRID") = reqGrid;

   // Remove some unnecessary Page and SubPage parameters and
   // copy the remaining ones to the new View
   if ( (const char*)viewRequest_("PAGE_FRAME") &&
        strcmp((const char*)viewRequest_("PAGE_FRAME"),"OFF") == 0 )
      RemoveParameters( viewRequest_, "PAGE_FRAME" );

   if ( (const char*)viewRequest_("PAGE_ID_LINE") &&
        strcmp((const char*)viewRequest_("PAGE_ID_LINE"),"OFF") == 0 )
      RemoveParameters( viewRequest_, "PAGE_ID_LINE" );

   if ( (const char*)viewRequest_("SUBPAGE_FRAME") &&
        strcmp((const char*)viewRequest_("SUBPAGE_FRAME"),"OFF") == 0 )
      RemoveParameters( viewRequest_, "SUBPAGE_FRAME" );

   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 ThermoView::UpdateView ( MvRequest& viewRequest )
{
   // Changing to another View is not allowed
   if ( !ObjectList::IsThermoView( viewRequest.getVerb() ) )
   {
      // Changing View is disabled at the moment
      char text[128];
      sprintf(text,"Changing View (%s to %s) is currently disabled",viewRequest_.getVerb(),viewRequest.getVerb() );
      PlotMod::Instance().errorMessage(text);
   }

   // If the request came from an Application then ignore the new
   // View definition and use the current View to draw the new plot
   MvRequest contextReq = viewRequest.getSubrequest("_CONTEXT");
   if ( contextReq )
      return;

   // Update the current view
   // Expand request
   MvRequest expRequest = ObjectList::ExpandRequest (viewRequest, EXPAND_DEFAULTS);

   // Update request
   viewRequest_ = expRequest;

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

   // Redraw this page
   //Owner().RedrawIfWindow();
   //Owner().NotifyObservers();

   //Owner().InitZoomStacks();
}

void ThermoView::ApplicationInfo( const MvRequest& req)
{
   // Get the VIEW request
   MvRequest viewReq;
   if ( ObjectList::IsView(req.getVerb()) )
      viewReq = req;
   else
   {
      // Try to find a hidden VIEW in the request
      viewReq = req.getSubrequest("_VIEW_REQUEST");
      if ( !viewReq )
      {
         // Nothing to be done
         return;
      }
   }

   return;
}

void ThermoView::Drop ( PmContext& context )
{
   // Before processing the drop (parent's function), check for icon drops
   // specific to this class:
   // a) dataUnit: initializes the type of the ThermoData module to be called
   // b) thermogrid: update the View
   MvRequest dropRequest = context.InRequest();
   bool first = true;
   while ( dropRequest )
   {
      // Data unit
      string verb = dropRequest.getVerb();
      if ( first && ObjectList::IsDataUnit ( verb.c_str() ) == true )
      {
         MvRequest req = dropRequest.justOneRequest();

         if ( !this->SetThermoType(req) )
            return;   // suitable thermo type not found

         first = false;
      }
      // Thermo grid
      else if ( ObjectList::IsThermoGrid ( verb.c_str() ) == true )
      {
         MvRequest req = dropRequest.justOneRequest();
         this->UpdateThermoGrid ( req );
      }

      dropRequest.advance();
   }

   // Call the parent to perform the Drop request
   CommonXSectView::Drop(context);

   return;
}

void ThermoView::UpdateThermoGrid ( MvRequest& req )
{
   // Update new thermo grid definition. The View will be updated later.
   viewRequest_("THERMO_GRID") = req;
}

bool ThermoView::SetThermoType( MvRequest& req )
{
   string thermoType;
   string verb = req.getVerb();
   map<string,string>::iterator it;
   it = DATA_TYPE.find(verb.c_str());
   if ( it != DATA_TYPE.end()  )
      thermoType = it->second;
   else if ( verb == "NETCDF" )
   {
      if ( (const char*)req("_VERB") )
         thermoType = (const char*)req("_VERB");
      else if ( (const char*)req("_CLASS") )
         thermoType = (const char*)req("_CLASS");
      else
      {
         // Thermo type not found
         char text[128];
         sprintf( text,"Suitable thermo type not found: %s ",verb.c_str() );
         PlotMod::Instance().errorMessage(text);
         return false;
      }
   }
   else if ( verb.find("NETCDF") != std::string::npos )
   {
      // The application has been already called to process the data.
      // These are a set of requests containing the NETCDF_XY_*;
      // therefore it will be processed withoug calling again the
      // application. There is no need to set the ApplicationName.
      return true;
   }
   else if ( verb.find("INPUT") != std::string::npos )
   {
      // The application has been already called to process the data.
      // These are a set of requests containing the _XY_*;
      // therefore it will be processed withoug calling again the
      // application. There is no need to set the ApplicationName.
      return true;
   }
   else
   {
      // Thermo type not found
      char text[128];
      sprintf( text,"Suitable thermo type not found: %s ",verb.c_str() );
      PlotMod::Instance().errorMessage(text);
      return false;
   }

   ApplicationName(thermoType);
   return true;
}
