/***************************** 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 <MvApplication.h>
#include <MvRequestUtil.hpp>
#include "MvStopWatch.h"
#include "PlotMod.h"
#include "PlotModConst.h"
#include "Root.h"
#include "MvLog.h"
#include "MvMiscellaneous.h"

#include <cassert>


PlotMod* PlotMod::plotModInstance_ = nullptr;

void PlotMod::Instance(PlotMod* pm)
{
    plotModInstance_ = pm;
}

PlotMod&
PlotMod::Instance()
{
    assert(plotModInstance_ != nullptr);
    return *plotModInstance_;
}

PlotMod::PlotMod() = default;

bool PlotMod::IsWindow(const char* driver)
{
    return !strcmp(MVSCREEN_DRIVER, driver);
}

bool PlotMod::CalledFromMacro(MvRequest& req)
{
    // Check if the request comes from a Macro
    int calledFromMacro = req("_CALLED_FROM_MACRO");

    // Only updates the plot environment if the request
    // comes from Macro. Otherwise, keeps the current status.
    if (calledFromMacro) {
        calledFromMacro_ = calledFromMacro;
        calledFirstFromMacro_ = calledFromMacro;
    }

    return calledFromMacro;
}

MvRequest
PlotMod::OutputFormat()
{
    if (!outFormat_)
        outFormat_ = MakeDefaultOutputFormat();

    return outFormat_;
}

void PlotMod::OutputFormat(MvRequest& req)
{
    outFormat_ = req;
    if ((const char*)outFormat_("DESTINATION")) {
        plotDestination_ = (const char*)outFormat_("DESTINATION");
        if (plotDestination_ == MVPRINTER && (const char*)outFormat_("PRINTER_NAME"))
            printerName_ = (const char*)outFormat_("PRINTER_NAME");
    }
    else
        plotDestination_ = MVSCREEN;
}

MvRequest
PlotMod::MakeDefaultOutputFormat()
{
    MvRequest req("PRINTER_MANAGER");
    MvRequest gldriverReq(MVSCREEN_DRIVER);
    gldriverReq("DESTINATION") = MVSCREEN;
    req("OUTPUT_DEVICES") = gldriverReq;

    return req;
}

MvRequest
PlotMod::OutputFormatInfo()
{
    MvRequest info("OUTPUTINFO");
    info("DESTINATION") = plotDestination_.c_str();
    info("PRINTER_NAME") = printerName_.c_str();
    info("NUMBER_COPIES") = (int)outFormat_("NUMBER_COPIES");
    MvRequest subReq = outFormat_.getSubrequest("OUTPUT_DEVICES");
    if (subReq) {
        if ((const char*)subReq("OUTPUT_NAME"))
            info("FILE_NAME") = subReq("OUTPUT_NAME");
        else if ((const char*)subReq("OUTPUT_FULLNAME"))
            info("FILE_NAME") = subReq("OUTPUT_FULLNAME");
        else
            info("FILE_NAME") = "defaultFilename";  // default filename
    }

    return info;
}

// ----------------------------------------------------------------------------
// PlotMod::infoMessage, warningMessage, errorMessage
// Receives message callbacks from Magics
// ----------------------------------------------------------------------------

void PlotMod::infoMessage(const std::string& msg)
{
    MvLog().info() << msg;
}

void PlotMod::warningMessage(const std::string& msg)
{
    MvLog().warn() << msg;
}

void PlotMod::errorMessage(const std::string& msg)
{
    std::string text = "Error: " + msg;

    // intercept the 'spherical harmonics' message and add our own information
    if (msg.find("Grib Decoder") != std::string::npos &&
        msg.find("Representation [sh]") != std::string::npos) {
        text +=
            "\nIf you wish to plot this field, you should first convert it to a grid. "
            "If the data comes from a Mars Retrieval icon, you should set its GRID "
            "parameter; if it is from a GRIB file, you should use the GRIB Filter icon "
            "and set its GRID parameter.";
    }

    if (magicsErrorIgnored_) {
        MvLog().errNoExit() << text;
    }
    else {
        MvLog().popup().err() << text;
    }
}

#if 0
// The module will exit with an error code
void PlotMod::exitWithError()
{
    // FAMI20180916: forces uPlot to exit, if running in interactive
    // mode (because it was called from uPlotManager as a system
    // command). The ideal would be to remove the last request (the
    // one that is causing this error) from the internal MvRequest
    // and keep uPlot alive.
    // If running in batch, send an error message to the caller.

    svc* service = MvApplication::getService();
    if (service != nullptr)
        set_svc_err(service->id, 1);

    // This is not ideal unless we find a way to communicate
    // back to Metview
    if (IsInteractive()) {
        // FAMI20181120 Let MvTemplates.h to kill uPlot at the end of the
        // process. Otherwise, any error message will not be sent forward.
        //
        // Clean structures and auxiliary files/links
        //      Root::Instance().Clean();
        //      exit(0);
    }
}
#endif

// Timming functions
// Starts and names the session
void PlotMod::watchStart(const char* txt)
{
    if (watch_) {
        marslog(LOG_WARN, "stopwatch_start - watch already running, replace old watch!");
        delete watch_;
    }
    watch_ = new MvStopWatch(txt);
}

// Prints the laptime since the previous call to
// watchLaptime() or from watchStart()
void PlotMod::watchLaptime(const char* txt)
{
    if (!watch_) {
        marslog(LOG_WARN, "stopwatch_laptime - watch not running, starting now!");
        watch_ = new MvStopWatch("tictac");
    }
    else
        watch_->lapTime(txt);
}

// Stops and prints a report
void PlotMod::watchStop()
{
    if (watch_) {
        delete watch_;
        watch_ = nullptr;
    }
    else
        marslog(LOG_WARN, "stopwatch_stop - no watch running!");
}
