/***************************** 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"
#include "MvLog.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
    MvLog().popup().warn() << "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.";

    // 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
    MvLog().warn() << "The Metview 3 VERTICAL PROFILE VIEW icon is deprecated. Parameter OVERLAY CONTROL will not be internally translated.";

    // Copy Page and Subpage parameters
    metview::CopySomeParameters(req, viewReq, "Subpage");
    metview::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) = default;

string VertProfView::Name()
{
    int id = Owner().Id();
    std::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
    std::set<Cached> skipSet;
    description.ConvertRequestToMacro(viewReq, PUT_END, MacroName().c_str(), "mvertprofview", skipSet);
    description.PutNewLine(" ");
}

void VertProfView::SetVariables(const MvRequest& in, bool setMembers)
{
    std::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 {
            std::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) {
        MvLog().warn() << "Icon VERTICAL PROFILE VIEW, parameter X_MIN_MAX, has invalid input values. Please use the default values (AUTO/AUTO) or provide 2 numerical values.";
        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
    metview::CopySomeParameters(viewRequest_, cartView, "PAGE");
    metview::CopySomeParameters(viewRequest_, cartView, "SUBPAGE");

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

    // Update request
    Owner().UpdateView(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
    std::vector<std::string> params;
    params.emplace_back("INPUT_MODE");
    if ((const char*)req1("POINT"))
        params.emplace_back("POINT");
    else
        params.emplace_back("AREA");

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