/***************************** 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 class XSectView
//
//
// This is the exemplar object for the XSectView  class
//

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

//--------------------------------------------------------
static XSectViewFactory xSectViewFactoryInstance;

PlotModView*
XSectViewFactory::Build(Page& page,
                        const MvRequest& contextRequest,
                        const MvRequest& setupRequest)
{
    // Instantiate a Xsection view
    return new XSectView(page, contextRequest, setupRequest);
}

//--------------------------------------------------------
static XSectViewM3Factory xSectViewM3FactoryInstance;

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

    // Instantiate a Xsection View
    return new XSectView(page, viewM4Req, setupRequest);
}

MvRequest
XSectViewM3Factory::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 CROSS SECTION VIEW icon is deprecated. An automatic translation to the Metview 4 XSECTION 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("MXSECTIONVIEW");
    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");

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

    return out;
}

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

XSectView::XSectView(Page& owner,
                     const MvRequest& viewRequest,
                     const MvRequest& setupRequest) :
    CommonXSectView(owner, viewRequest, setupRequest),
    yReverse_("off")
{
    ApplicationName("MXSECTION");
    SetVariables(viewRequest, true);
}

XSectView::XSectView(const XSectView& old) :
    CommonXSectView(old),
    yReverse_(old.yReverse_)
{
}

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

    return name;
}

void XSectView::DescribeYourself(ObjectInfo& description)
{
    // convert my request to macro
    set<Cached> skipSet;
    description.ConvertRequestToMacro(appViewReq_, PUT_END, MacroName().c_str(), "mxsectview", skipSet);
    description.PutNewLine(" ");
}

// In request is either a view request, if view parameters have
// changed, or a data info request.
// Using  AREA as metadata for all lat/lon specification in
// xsect/average/vprof.
void XSectView::SetVariables(const MvRequest& in, bool setMembers)
{
    char param[10];
    if (in.countValues("LINE"))
        strcpy(param, "LINE");
    else
        strcpy(param, "AREA");

    if (setMembers) {
        latMin_ = in(param, 0);
        latMax_ = in(param, 2);
        lonMin_ = in(param, 1);
        lonMax_ = in(param, 3);
    }
    else {
        viewRequest_.unsetParam("LINE");
        viewRequest_.addValue("LINE", (double)in(param, 0));
        viewRequest_.addValue("LINE", (double)in(param, 1));
        viewRequest_.addValue("LINE", (double)in(param, 2));
        viewRequest_.addValue("LINE", (double)in(param, 3));
    }

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

bool XSectView::UpdateView()
{
    // It has already been updated
    if (string(viewRequest_.getVerb()) == CARTESIANVIEW)
        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
    MvRequest cartView("CARTESIANVIEW");
    if (axisAuto)
        cartView("X_AUTOMATIC") = "on";
    else {
        cartView("X_AUTOMATIC")     = "off";
        cartView("X_MIN_LATITUDE")  = latMin_;
        cartView("X_MAX_LATITUDE")  = latMax_;
        cartView("X_MIN_LONGITUDE") = lonMin_;
        cartView("X_MAX_LONGITUDE") = lonMax_;
    }
    cartView("X_AXIS_TYPE") = "geoline";

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

    const char* log = viewRequest_("VERTICAL_SCALING");
    if (log && strcmp(log, "LOG") == 0)
        cartView("Y_AXIS_TYPE") = "logarithmic";
    else
        cartView("Y_AXIS_TYPE") = "regular";

    // Copy axis definition
    cartView.setValue("HORIZONTAL_AXIS", viewRequest_.getSubrequest("HORIZONTAL_AXIS"));
    cartView.setValue("VERTICAL_AXIS", viewRequest_.getSubrequest("VERTICAL_AXIS"));

    // 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 XSectView::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 XSectView::ConsistencyCheck(MvRequest& req1, MvRequest& req2)
{
    // Build a list of parameters to be checked
    vector<string> params;
    params.push_back("LINE");
    params.push_back("WIND_PARALLEL");
    params.push_back("WIND_PERPENDICULAR");
    params.push_back("WIND_INTENSITY");

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