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

#pragma once

//#include <QAbstractMessageHandler>
#include <QDomDocument>
#include <QFile>
#include <QMap>
#include <QObject>
#include <QStringList>

#include "MvRequest.h"

#include "MvQOgcParam.h"


class QAuthenticator;
class QDomElement;
class QNetworkReply;

class MvQNetworkAccessManager;
class MvQGetMapRequest;

class MvQProjInfo : public QMap<QString, QString>
{
public:
    MvQProjInfo(const MvRequest&);
    QString get(QString);

protected:
    void parseProj4String(const char*);
    void parseRequest(const MvRequest&);
};


// class MvQWmsMessageHandler : public QAbstractMessageHandler
//{
// public:
//     MvQWmsMessageHandler(QObject* parent = 0) :
//         QAbstractMessageHandler(parent){};
//     void clear() { fatalMsg_.clear(); }
//     bool fatalFound() { return fatalMsg_.count() > 0; }
//     QStringList fatalMessages() { return fatalMsg_; }

// protected:
//     void handleMessage(QtMsgType, const QString&, const QUrl&, const QSourceLocation&);

//    QStringList fatalMsg_;
//};

class MvQWmsClientBase : public QObject
{
public:
    ~MvQWmsClientBase() override;
    QStringList supportedMimeType() { return supportedMimeType_; }
    QStringList supportedCrs() { return supportedCrs_; }

protected:
    MvQWmsClientBase();

    QStringList supportedMimeType_;
    QStringList supportedCrs_;

    QString getMimeType(QByteArray);
    QString getRequestedMimeType(QString);

    //    MvQWmsMessageHandler* queryMsgHandler_;
};


class MvQWmsGetClient : public MvQWmsClientBase
{
    Q_OBJECT

public:
    MvQWmsGetClient(MvRequest&);
    ~MvQWmsGetClient() override;

    MvQGetMapRequest* getMapRequest() { return getMapRequest_; }
    void setGetMapRequest(QString);

    QStringList outFiles() { return outFiles_; }

    void runGetMap();
    bool getMapRunStatus() { return getMapRunStatus_; }
    QString legendImagePath() { return legendImagePath_; }
    QString logoImagePath() { return logoImagePath_; }
    bool requestChanged() { return requestChanged_; }


public slots:
    void slotReplyGetMap(QNetworkReply*);
    void slotReplyLegend(QNetworkReply*);
    void slotReplyLogo(QNetworkReply*);

private:
    bool updateBoundingBox();
    void downloadGetMapFrame();
    void downloadLegend();
    void downloadLogo();

    MvQGetMapRequest* getMapRequest_{nullptr};

    MvQNetworkAccessManager* networkGetMap_{nullptr};
    MvQNetworkAccessManager* networkLegend_{nullptr};
    MvQNetworkAccessManager* networkLogo_{nullptr};

    QNetworkReply* getMapReply_{nullptr};
    QNetworkReply* legendReply_{nullptr};
    QNetworkReply* logoReply_{nullptr};

    int getMapFrameNum_{0};
    int getMapFrameToDownload_{-1};

    MvRequest reqInfo_;
    QString iconFile_;
    QStringList outFiles_;
    bool getMapRunStatus_{false};
    QString legendPath_;
    QString legendImagePath_;
    QString logoPath_;
    QString logoImagePath_;
    bool requestChanged_{false};
};


class MvQWmsUiClient : public MvQWmsClientBase
{
    Q_OBJECT

public:
    MvQWmsUiClient(std::string&, MvRequest&);
    ~MvQWmsUiClient() override;

    enum ClientMode
    {
        BasicMode,
        AdvancedMode
    };

    QString url() { return url_; }
    void setUrl(const QString&, const QString version = "Default");
    QString version() { return version_; }
    void setVersion(const QString&);
    MvQGetMapRequest* getMapRequest() { return getMapRequest_; }
    void setGetMapRequest(QString);

    QString getCapabilityDoc() { return capability_; }

    QStringList outFiles() { return outFiles_; }

    ClientMode clientMode() { return clientMode_; }
    void setClientMode(ClientMode);

    QStringList formatDisplayValues() const;
    QString formatCurrentDisplayValue() const;

    QStringList transparentDisplayValues() const;
    QString transparentCurrentDisplayValue() const;
    void setTransparentCurrentDisplayValue(QString);

    void setWidth(QString);
    QString width() const;
    void setHeight(QString);
    QString height() const;

    QStringList crsDisplayValues() const;
    QString crsCurrentDisplayValue() const;
    void setCrsCurrentDisplayValue(QString);
    QString crsDisplayName();

    QStringList styleDisplayValues() const;
    QStringList styleDescriptions() const;
    int styleCurrentIndex() const;
    void setStyleCurrentIndex(int);

    void setLayerFromDpy(MvQOgcNode*);
    QStringList layerDisplayValues() const;
    QStringList layerDescriptions() const;
    const QList<MvQOgcDimension*>& dimension() { return dimension_; }
    QStringList dimensionNameToDpy() const;
    QStringList dimensionToDpy(QString) const;
    void setDimensionFromDpy(QString, QString);
    void setDimensionFromDpy(QString, QStringList);
    void setBoundingBoxFromDpy(QString, QString, QString, QString);
    const MvQOgcBoundingBox* boundingBox() { return requestBbox_; }
    MvQOgcBoundingBox lastBoundingBox() const;
    MvQOgcBoundingBox* currentBoundingBox() const;

    QString extraGetCapPar() { return extraGetCapPar_; }
    QString extraGetMapPar() { return extraGetMapPar_; }
    void setExtraGetCapPar(QString);
    void setExtraGetMapPar(QString);

    MvQOgcTree* layer() { return layer_; }
    int layerCurrentIndex();
    QString layerName() { return layer_->currentValue(); }
    QString layerTitle() { return layer_->currentDisplayValue(); }
    QString layerAbstract() { return layer_->currentDescription(); }

    QString iconFile() { return iconFile_; }
    void setFileNameInfo(std::string& name) { iconFile_ = QString::fromStdString(name); }
    void setRequestInfo(MvRequest& req) { reqInfo_ = req; }

    void downloadPreview(QSize s = QSize(512, 256));
    void downloadLegend();
    void downloadLogo();

    void reset(QString);

    QMap<QString, QString> serviceMetaData() { return serviceMeta_; }

    bool previewDownloadActive();
    bool legendDownloadActive();


public slots:
    void slotReplyGetCap(QNetworkReply*);
    void slotReplyPreview(QNetworkReply*);
    void slotReplyLegend(QNetworkReply*);
    void slotReplyLogo(QNetworkReply*);
    void slotRunGetCapabilities();
    void slotAbortDownloadProcess();
    void slotSaveInfo();

    void slotAuthentication(QNetworkReply*, QAuthenticator*);

    void slotSetFormatFromDpy(QString);

signals:
    void getCapabilityLoaded();
    void getMapRequestChanged(QString, QStringList);
    void previewLoaded(QString);
    void legendLoaded(QString);
    void logoLoaded(QString);
    void clientResetDone();

private:
    void clearServerDependentData(bool keepRequest = false);
    void clearLayerDependentData();
    void clearDimension();
    void clearBoundingBox();
    void runGetCapabilities();
    void buildGetMapRequest();
    void saveGetMapRequest(QMap<QString, QString>&);
    void downloadGetMap();

    QString readVersion();
    void readService();
    void readFormat();
    void readLayer();
    void readLayer(QDomElement&, MvQOgcNode*);
    // void readLayerAbstract();
    void readLayerProperties();
    void readStyle(const QList<QDomElement>& layers);
    void readBoundingBox(const QList<QDomElement>& layers);
    void readCrs(const QList<QDomElement>& layers);
    void readDimension(const QList<QDomElement>& layers);
    void readGeographicBoundingBox(const QList<QDomElement>& layers);
    void readAttribution(const QList<QDomElement>& layers);
    void readException(QByteArray, QString&);
    void updatRequestBoundingBox();
    QString crsQueryName();
    QString crsRequestName();

    QStringList timeDimName();

    void clearPreview();
    void clearLegend();
    void clearLogo();

    void updateAfterGetCapLoaded();
    void updateAfterLayerLoaded();

    QString url_;
    QString version_;
    QString repliedVersion_;
    QString capability_;
    MvQGetMapRequest* getMapRequest_{nullptr};
    MvQGetMapRequest* currentGetMapRequest_{nullptr};
    MvQGetMapRequest* lastGetMapRequest_{nullptr};

    // Global
    MvQOgcList* format_{nullptr};
    MvQOgcList* transparent_{nullptr};
    MvQOgcIntValue* width_{nullptr};
    MvQOgcIntValue* height_{nullptr};
    MvQOgcColourValue* bgColour_{nullptr};

    // Layer
    MvQOgcTree* layer_{nullptr};
    QString layerAbstract_;
    MvQOgcCrsList* crs_{nullptr};
    MvQOgcStyleList* style_{nullptr};

    MvQOgcBoundingBox* requestBbox_{nullptr};
    MvQOgcGeoBoundingBox* geographicBbox_{nullptr};
    QList<MvQOgcBoundingBox*> bbox_;
    QList<MvQOgcDimension*> dimension_;

    MvQNetworkAccessManager* networkGetCap_{nullptr};
    MvQNetworkAccessManager* networkPreview_{nullptr};
    MvQNetworkAccessManager* networkLegend_{nullptr};
    MvQNetworkAccessManager* networkLogo_{nullptr};

    QNetworkReply* getCapReply_{nullptr};
    QNetworkReply* previewReply_{nullptr};
    QNetworkReply* legendReply_{nullptr};
    QNetworkReply* logoReply_{nullptr};

    QString iconFile_;
    MvRequest reqInfo_;
    QStringList outFiles_;

    QSize previewSize_;

    ClientMode clientMode_;
    QString defaultNsDeclaration_;
    QString xlinkNsDeclaration_;
    QString previewFile_;
    QString legendFile_;
    QString logoFile_;
    QMap<QString, QString> serviceMeta_;

    QString extraGetCapPar_;
    QString extraGetMapPar_;

    QString httpUser_;
    QString httpPassword_;

    QDomDocument dom_;
};
