/***************************** 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 <assert.h>

// Methods for the PlotMod class
//
// --- METHOD:  Instance
//
// Methods to provide access to the singleton
//              PlotMod class 

PlotMod* PlotMod::plotModInstance_ = 0;

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

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

PlotMod::PlotMod () : exitOnErrorMessage_(true),
                      popupErrorMessage_(true),
                      calledFromMacro_(false),
                      calledFirstFromMacro_(false)
{
	watch_ = 0;
}

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;
}

#if 0
bool
PlotMod::CheckSetWindowOutputFormat( MvRequest& req )
{
	// Default value;
	isWindow_ = true;

	if ( IsParameterSet(req,"OUTPUT_DEVICES") )
	{
		// Output device definition was set by the user
		// Try to find the screen driver
		MvRequest outDev = req("OUTPUT_DEVICES");
		while ( outDev )
		{
			if ( strcmp(outDev.getVerb(),MVSCREEN_DRIVER) == 0 )
				return true;  //screen driver found

			outDev.advance();
		}

		// Screen driver not found
		isWindow_ = false;
		return false;
	}

	return true;
}
#endif


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

void PlotMod::infoMessage(const string& msg)
{
    printMessage("Info: " + msg, false);
}

void PlotMod::warningMessage(const string& msg, bool onScreen)
{
   string smsg = "Warning: " + msg;
   printMessage(smsg, true);

   if(popupErrorMessage() && onScreen)
      UserMessage (smsg);
}

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

    // intercept the 'spherical harmonics' message and add our own information
    if (msg.find("Grib Decoder") != string::npos && 
        msg.find("Representation [sh]") != 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.";
    }

    // Send message to the console
    printMessage(text, true);

    // Popup an error message window
    if(popupErrorMessage())
        UserMessage (text);

    // Exit module
    if(exitOnErrorMessage())
        exitWithError();
}

// -----------------------------------------------------------------
// General handling of info/warning/error messages.
// Combine functions: infoMessage, warningMessage and errorMessage.
// It can be used to avoid testing which of the three above 
// functions should be called.
// -----------------------------------------------------------------
void PlotMod::MetviewError ( const string & message, const string & errorlevel )
{
    string fullMsg;
    bool priority = false;
    bool exit     = false;

    // Check type of message
    if ( errorlevel.length() )
    {
        // Check if errorlevel is to be added to the output message
        std::size_t ipos = message.find(" ");
        string sfirst = (ipos != std::string::npos) ? message.substr(0,ipos) : message;
        if ( sfirst != errorlevel )
           fullMsg = errorlevel + ": ";

        // If infoMessage then just print the message;
        // otherwise, set the flags accordingly
        if (errorlevel == "Warn" || errorlevel == "WARNING" || errorlevel == "Warning")
            priority = true;
        else if (errorlevel == "Error")
        {
            priority = true;
            exit     = true;
        }
    }

    fullMsg += message;
    printMessage(fullMsg, priority);

    if (priority)
        UserMessage(fullMsg);

    if (exit)
        exitWithError();
}

// 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::instance().getService();
   if (service != NULL)
      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);
   }
}

// 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_ = 0;
	}
	else
		marslog(LOG_WARN,"stopwatch_stop - no watch running!");
}
