/***************************** LICENSE START ***********************************

 Copyright 2016 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 <QDateTime>
#include <QDebug>
#include <QStringList>
#include <QVector>
#include <QXmlFormatter>
#include <QXmlQuery>
#include <QXmlResultItems>
#include <QApplication>

#include "MvQWmsClient.h"
#include "MvQWmsClientEditor.h"
#include "MvQOgcRequest.h"
//#include "MvQOgcServiceManager.h"
#include "Metview.h"
#include "MvQService.h"

using namespace std;

// Globals
int ac;
char** av;

class MvWmsClient : public MvQService
{
public:
    MvWmsClient() :
        MvQService("WMSCLIENT") {}
    void serve(MvRequest&, MvRequest&);
//    void processUiMode(MvRequest&, MvRequest&);
    void processGetMode(MvRequest&, MvRequest&, const string&);
};

void MvWmsClient::serve(MvRequest& in, MvRequest& out)
{
    cout << "---MvWmsClient::serve() IN---" << endl;
    in.print();

    // Get user action mode
    const char* modeC = (const char*)in("_ACTION");
    string mode;
    if (modeC)
        mode = string(modeC);


    if (mode.empty()) {
        const char* appl = (const char*)in("_APPL");
        if (appl) {
            if (strcmp(appl, "macro") == 0 || strcmp(appl, "Python") == 0) {
                processGetMode(in, out, mode);
            }
        }

    }
//    else if (mode == "edit") {
//        processUiMode(in, out);
//    }
    else if (mode == "visualise" ||
             mode == "prepare" ||
             mode == "execute" ||
             mode == "update") {
        processGetMode(in, out, mode);
    }

    cout << "---MvWmsClient::serve() OUT---" << endl;
    out.print();
}

void MvWmsClient::processGetMode(MvRequest& in, MvRequest& out, const string& mode)
{
    QApplication app(ac, av);

    MvQWmsGetClient* client = new MvQWmsGetClient(in);

    if (mode == "update" && client->requestChanged() == false) {
        return;
    }

    client->runGetMap();

    //Listen to the mars event loop!
    setupSocketNotifier();

    //Enter the app loop
    app.exec();

    //If the getMap request failed returns
    if (client->getMapRunStatus() == false) {
        setError(13);  //,"GetMap request failed!");
        return;
    }

    //Else build the output request

    MvRequest req("PRASTER");
    req("IMPORT_FILE_TYPE")  = "png",
    req("IMPORT_X_POSITION") = -180;
    req("IMPORT_Y_POSITION") = -90;
    req("IMPORT_WIDTH")      = 360;
    req("IMPORT_HEIGHT")     = 180;

    MvQGetMapRequest* gmr = client->getMapRequest();

    req("CRS") = gmr->crs().toStdString().c_str();

    //In version 1.3.0 for epsg:4326 x lat and y is lon !!!!!
    //We need to swap here the coordinates because
    //magics++ interprets x as lon and y as lat!!
    if (gmr->request().contains("CRS=", Qt::CaseInsensitive) &&
        gmr->crs() == "EPSG:4326") {
        req("CRS_MINX") = gmr->minY().toStdString().c_str();
        req("CRS_MINY") = gmr->minX().toStdString().c_str();
        req("CRS_MAXX") = gmr->maxY().toStdString().c_str();
        req("CRS_MAXY") = gmr->maxX().toStdString().c_str();
    }
    else {
        req("CRS_MINX") = gmr->minX().toStdString().c_str();
        req("CRS_MINY") = gmr->minY().toStdString().c_str();
        req("CRS_MAXX") = gmr->maxX().toStdString().c_str();
        req("CRS_MAXY") = gmr->maxY().toStdString().c_str();
    }


    req("LAYERS") = gmr->layers().toStdString().c_str();

    req("SERVICE") = "WMS";

    const char* layerTitle = static_cast<const char*>(in("LAYER_TITLE"));
    if (layerTitle)
        req("TITLE") = layerTitle;

    const char* description = static_cast<const char*>(in("LAYER_DESCRIPTION"));
    if (description)
        req("DESCRIPTION") = description;

    const char* title = static_cast<const char*>(in("SERVICE_TITLE"));
    if (title)
        req("SERVICE_TITLE") = title;

    //const char *legend=static_cast<const char*>(in("LAYER_LEGEND"));
    //if(legend) req("LEGEND") = legend;

    if (client->legendImagePath().isEmpty() == false) {
        req("LEGEND") = client->legendImagePath().toStdString().c_str();
    }

    if (client->logoImagePath().isEmpty() == false) {
        req("LOGO") = client->logoImagePath().toStdString().c_str();
    }


    const char* url = static_cast<const char*>(in("SERVER"));
    if (url)
        req("URL") = url;

    /*QMap<QString,QString> nonTimeDim;
	gmr->nonTimeDimValues(nonTimeDim);
	QStringList nonTimeDimName, nonTimeDimValue;
	QMapIterator<QString,QString> it(nonTimeDim);
	while(it.hasNext())
	{
		it.next();
		nonTimeDimName << it.key();
		nonTimeDimValue << it.value();
	}*/

    /*QMap<QString,QString> nonTimeDimUnit;
	gmr->nonTimeDimUnits(nonTimeDimUnit);
	QStringList nonTimeDimUnit;
	QMapIterator<QString,QString> itu(nonTimeDimUnit);
	while(it.hasNext())
	{
		it.next();
		nonTimeDimUnit << it.value();
	}*/

    //req("NON_TIME_DIM_NAME")=nonTimeDimName.join("/").toStdString().c_str();
    //req("NON_TIME_DIM_VALUE")=nonTimeDimValue.join("/").toStdString().c_str();
    //req("NON_TIME_DIM_UNIT")=nonTimeDimUnit.join(":").toStdString().c_str();


    //Build rasterloop if there is at least one frame in the request
    if (gmr->requestFrameNum() > 0) {
        MvRequest reqLoop;

        QVector<MvRequest> rFrame(gmr->requestFrameNum());
        for (int i = 0; i < rFrame.count(); i++) {
            MvRequest reqFrame           = req;
            QString fnam                 = gmr->outFile(i);
            reqFrame("IMPORT_FILE_PATH") = fnam.toStdString().c_str();
            reqFrame("PATH")             = fnam.toStdString().c_str();

            QMap<QString, QString> dim;
            gmr->dimValuesForFrame(dim, i);
            QStringList dimName, dimValue;
            QMapIterator<QString, QString> it(dim);
            while (it.hasNext()) {
                it.next();
                dimName << it.key();
                if (gmr->isTimeDim(it.key())) {
                    dimValue << MvQOgcRequest::timeToString(it.value());
                }
                else {
                    dimValue << it.value();
                }
            }

            reqFrame("DIM_NAME")  = dimName.join("/").toStdString().c_str();
            reqFrame("DIM_VALUE") = dimValue.join("/").toStdString().c_str();
            ;

            reqLoop = reqLoop + reqFrame;
        }

        out.setVerb("PRASTERLOOP");
        out("RASTERS") = reqLoop;
    }
    else {
        MvRequest reqFrame           = req;
        QString fnam                 = gmr->outFile(0);
        reqFrame("IMPORT_FILE_PATH") = fnam.toStdString().c_str();
        reqFrame("PATH")             = fnam.toStdString().c_str();

        out.setVerb("PRASTERLOOP");
        out("RASTERS") = reqFrame;
    }

    out("IMPORT_X_POSITION") = -180;
    out("IMPORT_Y_POSITION") = -90;
    out("IMPORT_WIDTH")      = 360;
    out("IMPORT_HEIGHT")     = 180;

    //
    MvRequest current = in.justOneRequest();
    while (current != NULL) {
        string verb = current.getVerb();
        if (verb == "WMSCLIENT") {
            current("REQUEST")        = gmr->request().toStdString().c_str();
            out("WMS_CLIENT_REQUEST") = current;
        }
        break;
        current = in.advance().justOneRequest();
    }

    out.print();
}


int main(int argc, char** argv)
{
    ac = argc;
    av = argv;

    // Initialize a Metview application
    MvApplication app(argc, argv, "wmsclient");

    // Instantiate the application
    MvWmsClient ogc;
    ogc.saveToPool(false);
    app.run();
}
