/***************************** 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 "Metview.h"
#include "MvQApplication.h"


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

int main(int argc, char** argv)
{
    if (argc < 2) {
        marslog(LOG_EROR, "No arguments are specified");
        exit(1);
    }

    MvRequest in, out;
    in.read(argv[1], false, true);

    marslog(LOG_INFO, "Request:");
    in.print();

    std::string outPath;
    if (const char* outPathCh = in("_OUT_REQ_FILE")) {
        outPath = std::string(outPathCh);
    }
    else {
        marslog(LOG_EROR, "No output request specified in _OUT_REQ_FILE!");
        exit(1);
    }

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

    bool doProcess = false;
    if (mode.empty()) {
        if (const char* appl = (const char*)in("_APPL")) {
            if (strcmp(appl, "macro") == 0 || strcmp(appl, "Python") == 0) {
                doProcess = true;
            }
        }
    }
    else if (mode == "visualise" ||
             mode == "prepare" ||
             mode == "execute" ||
             mode == "update") {
        doProcess = true;
    }

    if (!doProcess) {
        out.save(outPath.c_str());
        exit(0);
    }

    // Create the qt application. The appname must be unique!
    std::string appName = MvApplication::buildAppName("WmsClient");
    MvQApplication app(argc, argv, appName.c_str());

    auto* client = new MvQWmsGetClient(in);
    if (mode == "update" && client->requestChanged() == false) {
        out.save(outPath.c_str());
        exit(0);
    }

    client->runGetMap();

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

    // If the getMap request failed returns
    if (client->getMapRunStatus() == false) {
        out.save(outPath.c_str());
        marslog(LOG_EROR, "GetMap request failed!");
        exit(13);
    }

    // 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();
    out.save(outPath.c_str());
}


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