/***************************** 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 "uPlot.h"
#include "MvRequest.h"
#include "Root.h"
#include "MvDebugPrintControl.h"
#include "MvScanFileType.h"
#include "PlotModInteractive.h"
#include "uPlotApp.h"
#include "MagPlusInteractiveService.h"
#include "SuperPage.h"
#include "MvLog.h"
#include "ConfigLoader.h"

#include "MvQTheme.h"

#include <mars.h>

const std::string PLOT_STAND_ALONE = "uplotSA";

bool SetUplotEnv(int argc, char** argv, std::string& mode, MvRequest& req, bool& reqExists, std::string& errorMessage)
{
    // Create Root instance
    Root::Create();

    // Initialize Mars communication
    marsinit(&argc, argv, nullptr, 0, nullptr);
    mvSetMarslogLevel();

    ConfigLoader::init();

    // Check if the input filename exists.
    // If the filename does not exist then uPlot is running in the
    // INTERACTIVE mode and should continue running.
    // If uPlot is running STANDALONE mode then the filename does exist
    // because this is checked in the Metview initialisation script.
    reqExists = false;
    if (argc <= 1 || access(argv[1], F_OK) != 0)
        return true;

    // Read the input file or request
    if (mode == PLOT_STAND_ALONE) {
        // uPlot is running stand alone.
        // First, find out the type of the input filename
        const char* filename = (const char*)argv[1];
        std::string stype = ScanFileType(filename);
        if (stype == std::string("BAD")) {
            errorMessage = "<<< METVIEW ERROR >>>\n\n\nInput file type not recognised!\n\nFilename: ";
            errorMessage += std::string(filename) + "\n\nFile type: ";
            errorMessage += stype + "\n";
            return false;
        }

        // Only file types GRIB/BUFR/GEOPOINTS can be directly visualised
        if (stype == "GRIB" || stype == "BUFR" || stype == "GEOPOINTS") {
            // Build a request
            req.setVerb(stype.c_str());
            req.setValue("PATH", filename);
            req.setValue("_NAME", filename);
            req.setValue("_CLASS", stype.c_str());
            req.setValue("_PATH", filename);

            // Use contour ecChart convention
            if (stype == "GRIB") {
                MvRequest req1("MCONT");
                req1("CONTOUR_AUTOMATIC_SETTING") = "ECCHART";

                req = req + req1;
            }
        }
        else {
            errorMessage = "<<< METVIEW ERROR >>>\n\n\nOnly file types GRIB/BUFR/GEOPOINTS can be directly visualised!\n\nFilename: ";
            errorMessage += std::string(filename) + "\n\nFile type: ";
            errorMessage += stype + "\n";
            return false;
        }
    }
    else {
        // Read the initial input request saved by uPlotManager
        req.read(argv[1]);

        // Skip UPLOT_MANAGER request
        if (strcmp(req.getVerb(), "UPLOT_MANAGER") == 0)
            req.advance();
    }

    reqExists = true;

// DOES IT NEED TO TEST FOR INTERACTIVE MODE?????
//  CHECK THIS CODE LATER WHEN THE EXPORT BUTTON IS ACTIVATED
#if 0
	// Batch or Interactive mode
	const char *metviewMode = getenv("METVIEW_MODE");
	if ( metviewMode && strcmp(metviewMode,"batch") == 0 )
	{
		// Initialize uPlot in batch mode
		PlotMod::Instance().SetBatchMode();
	}
	else
	{
		// Initialize uPlot in interactive mode
		PlotMod::Instance().SetInteractiveMode();

		// Indicate if a window needs to be created
		bool dispWindow = true;
		if (reqExists)
		{
			// Check if a Display Window needs to be created
			MvRequest reqaux = req.justOneRequest();
			dispWindow = PlotMod::Instance().CheckSetWindowOutputFormat(reqaux);
		}
		PlotMod::Instance().SetWindowMode(dispWindow);
	}

	return PlotMod::Instance().IsWindow();
#endif

    return true;
}

std::string GetProcessName(std::string& mode)
{
    // Build process name
    std::string name;
    if (mode == PLOT_STAND_ALONE)
        name = "uPlot";  // stand alone plotting
    else {
        // includes the process id
        //      name = "uPlot%ld" + (long int)getpid();
        std::ostringstream appName;
        appName << "uPlot" << (long int)getpid();
        name = appName.str();
    }

    return name;
}

int main(int argc, char** argv)
{
    // Retrieve the processing mode
    std::string metviewMode = (const char*)getenv("METVIEW_MODE");
    std::string name = GetProcessName(metviewMode);

    MvRequest req;
    bool reqExists;

    // Setup uPlot environment
    std::string errorMessage;
    bool ok = SetUplotEnv(argc, argv, metviewMode, req, reqExists, errorMessage);

    // Initialise resorces from a static library (libMvQtGui)
    // Initialise resorces from a static library (libMvQtGui)
    //     Q_INIT_RESOURCE(edit);
    //     Q_INIT_RESOURCE(window);
    //     Q_INIT_RESOURCE(keyDialog);

    // Start uPlot interactively with Qt facilities
    uPlotApp app(argc, argv, name.c_str());
    auto* magplus = new MagPlusInteractiveService();
    MagPlusService::Instance(magplus);

    auto* pm = new PlotModInteractive();
    PlotMod::Instance(pm);

    // If function SetUplotEnv returned an error then send an error
    // message and abort uPlot.
    // This test is performed here because class PlotMod needs to be
    // intantiated before function errorMessage can be used. This error
    // message is issued when uPlot is running in the standalone mode and
    // there is a problem in the input filename. In this case, function
    // errorMessage must be called, instead of "exit(0)" for instance,
    // because Event needs also to be terminated.
    if (!ok) {
        MvLog().popup().err() << errorMessage;
    }

    //---------------------------
    // Load the ui theme
    //---------------------------

    // MvQTheme::init(&app);

    // Instantiate uPlot Display Window
    uPlotBase* pw = new uPlot;
    magplus->setPlotApplication(pw);
    SuperPage::setPlotApplication(pw);
    pm->setPlotApplication(pw);

    // Initialize plotting dimension
    double x = 29.7;
    double y = 21.;
    pw->setPlotWidgetSize(x, y);

    // Call myself to execute the initial request
    // It needs to be execute after uPlot window has been created
    if (reqExists)
        MvApplication::callService(name.c_str(), req, nullptr);

    // Show uPlot
    pw->show();

    return app.exec();

    // DOES IT NEED TO TEST FOR INTERACTIVE MODE?????
    //  CHECK THIS CODE LATER WHEN THE EXPORT BUTTON IS ACTIVATED

#if 0
	else
	{
		// Start uPlot without a window (eg. batch mode or interactive mode
		// without a Qt window)
//		uPlotApp app(argc, argv, name.c_str());

		// Call myself to execute the initial request
//		if(reqExists)
//			MvApplication::callService ( name.c_str(),req,0 );

//		app.run();
	}
#endif

    Root::ServerDead(0, nullptr);
}
