/***************************** 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 AverageView
//
// This is the exemplar object for the AverageView class
//
//
#include "AverageView.h"
#include <MvRequestUtil.hpp>
#include "ObjectList.h"
#include "PlotMod.h"
#include "Root.h"
#include "MvLog.h"

//--------------------------------------------------------
static AverageViewFactory averageViewFactoryInstance;

PlotModView*
AverageViewFactory::Build(Page& page,
                          const MvRequest& contextRequest,
                          const MvRequest& setupRequest)
{
    // Instantiate a Average view
    return new AverageView(page, contextRequest, setupRequest);
}

//--------------------------------------------------------
static AverageViewM3Factory averageView3FactoryInstance;

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

    // Instantiate a Average view
    return new AverageView(page, viewM4Req, setupRequest);
}

MvRequest
AverageViewM3Factory::Translate(const MvRequest& in)
{
    // Send a warning message
    MvLog().popup().warn() << "The Metview 3 AVERAGE VIEW icon is deprecated. An automatic "
                              "translation to the Metview 4 AVERAGE 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 Area and Direction parameters
    MvRequest viewReq("MXAVERAGEVIEW");
    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));
    viewReq("DIRECTION") = req("DIRECTION");

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

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

    // Overlay Control parameter is not translated
    MvLog().popup().warn() << "The Metview 3 AVERAGE 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;
}

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

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

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

    return name;
}

void AverageView::DescribeYourself(ObjectInfo& description)
{
    // Convert my request to macro
    std::set<Cached> skipSet;
    description.ConvertRequestToMacro(appViewReq_, PUT_END,
                                      MacroName().c_str(), "maverageview", skipSet);

    description.PutNewLine(" ");
}

// In request is either a new viewrequest, or a data info request.
void AverageView::SetVariables(const MvRequest& in, bool resetMembers)
{
    // Called with a viewRequest
    if (resetMembers) {
        latMin_ = in("AREA", 0);
        latMax_ = in("AREA", 2);
        lonMin_ = in("AREA", 1);
        lonMax_ = in("AREA", 3);

        if (strcmp(in("DIRECTION"), "NS") != 0 &&
            strcmp(in("DIRECTION"), "NORTH SOUTH") != 0)
            axisType_ = "LATITUDE";
        else
            axisType_ = "LONGITUDE";
    }
    else  // Called with a netCDF request.
    {
        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));

        if ((const char*)in("MODE") && strcmp(in("MODE"), "AVERAGE_EW") == 0) {
            viewRequest_("DIRECTION") = "NS";
            axisType_ = "LONGITUDE";
        }
        else {
            viewRequest_("DIRECTION") = "EW";
            axisType_ = "LATITUDE";
        }
    }

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

bool AverageView::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";
        if (axisType_ == "LATITUDE") {
            cartView("X_MIN") = latMin_;
            cartView("X_MAX") = latMax_;
        }
        else {
            cartView("X_MIN") = lonMin_;
            cartView("X_MAX") = lonMax_;
        }
    }
    cartView("X_AXIS_TYPE") = axisType_.c_str();

    // 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");
    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
    metview::CopySomeParameters(viewRequest_, cartView, "PAGE");
    metview::CopySomeParameters(viewRequest_, cartView, "SUBPAGE");

    // Copy the original request without certain parameteres (to avoid duplication)
    metview::RemoveParameters(viewRequest_, "HORIZONTAL_AXIS");
    metview::RemoveParameters(viewRequest_, "VERTICAL_AXIS");
    metview::RemoveParameters(viewRequest_, "PAGE");
    metview::RemoveParameters(viewRequest_, "SUBPAGE");
    metview::RemoveParameters(viewRequest_, "_");
    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 AverageView::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 AverageView::ConsistencyCheck(MvRequest& req1, MvRequest& req2)
{
    // Build a list of parameters to be checked
    std::vector<std::string> params = {"AREA", "DIRECTION"};

    // Expand requests using the same expansion flag to avoid
    // problems with parameters with multiple values (e.g.
    // NS or NORTH_SOUTH are valid values for parameter DIRECTION
    MvRequest t1 = ObjectList::ExpandRequest(req1, EXPAND_DEFAULTS);
    MvRequest t2 = ObjectList::ExpandRequest(req2, EXPAND_DEFAULTS);

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