/***************************** 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 <iostream>

#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"

// Globals
int ac;
char** av;

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

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

    // Get user action mode
    const char* modeC = (const char*)in("_ACTION");
    std::string mode;
    if (modeC)
        mode = std::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);
    }

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

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

    auto* client = new MvQWmsGetClient(in);

    if (mode == "update" && client->requestChanged() == false) {
        delete client;
        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) {
        delete client;
        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 != nullptr) {
        std::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();

    delete client;
}


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