/***************************** 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 <QDateTime>
#include <QMap>
#include <QStringList>
#include <QTextDocument>

class MvQHtmlDecoder : public QTextDocument
{
public:
    MvQHtmlDecoder() = default;
    QString decode(QString&);
};


class MvQOgcName
{
public:
    MvQOgcName() = default;
    MvQOgcName(QString requestName, QString displayName) :
        requestName_(requestName),
        displayName_(displayName) {}

    virtual ~MvQOgcName() = default;

    QString requestName() { return requestName_; }
    void setRequestName(QString s) { requestName_ = s; }

    QString displayName() { return displayName_; }
    void setDisplayName(QString s) { displayName_ = s; }

protected:
    QString requestName_;
    QString displayName_;
    static MvQHtmlDecoder htmlDecoder_;
};

class MvQOgcColourValue : public MvQOgcName
{
public:
    MvQOgcColourValue() = default;
    MvQOgcColourValue(QString value, QString requestName, QString displayName) :
        MvQOgcName(requestName, displayName),
        value_(value) {}

    int value();
    void setValue(QString);

protected:
    QString value_;
};

class MvQOgcIntValue : public MvQOgcName
{
public:
    MvQOgcIntValue() :
        minIsSet_(false),
        maxIsSet_(false) {}
    MvQOgcIntValue(int value, QString requestName, QString displayName) :
        MvQOgcName(requestName, displayName),
        value_(value),
        minIsSet_(false),
        maxIsSet_(false) {}

    int value() { return value_; }
    void setValue(int);
    void setMinValue(int);
    void setMaxValue(int);

private:
    void checkValue();

    int value_;
    bool minIsSet_;
    bool maxIsSet_;
    int maxValue_;
    int minValue_;
};


class MvQOgcList : public MvQOgcName
{
public:
    // MvQOgcList() : {};
    MvQOgcList(QString requestName, QString displayName) :
        MvQOgcName(requestName, displayName) {}
    ~MvQOgcList() override { clear(); }

    virtual void clear()
    {
        values_.clear();
        displayValues_.clear();
        descriptions_.clear();
        currentIndex_ = -1;
    }

    QStringList values() { return values_; }
    QStringList displayValues() { return displayValues_; }
    QStringList descriptions() { return descriptions_; }
    QString currentValue();
    QString currentDisplayValue();
    QString currentDescription();

    virtual void setValues(QStringList lst) { values_ = lst; }
    void setDisplayValues(QStringList lst) { displayValues_ = lst; }
    void setDescriptions(QStringList lst) { descriptions_ = lst; }
    void setCurrentIndex(int);
    int currentIndex() { return currentIndex_; }
    void setCurrentValue(QString);
    void setCurrentDisplayValue(QString);


    void addValue(QString s) { values_.push_back(s); }
    void addDisplayValue(QString s) { displayValues_.push_back(s); }

protected:
    QStringList values_;
    QStringList displayValues_;
    QStringList descriptions_;
    int currentIndex_{-1};
};

class MvQOgcStyleList : public MvQOgcList
{
public:
    // MvQOgcList() : {};
    MvQOgcStyleList(QString requestName, QString displayName) :
        MvQOgcList(requestName, displayName) {}
    ~MvQOgcStyleList() override { clear(); }

    void clear() override
    {
        legends_.clear();
        MvQOgcList::clear();
    }
    void setLegends(QStringList);
    QStringList legends() { return legends_; }
    QString currentLegend();

private:
    QStringList legends_;
};

class MvQOgcCrsList : public MvQOgcList
{
public:
    MvQOgcCrsList(QString requestName, QString displayName) :
        MvQOgcList(requestName, displayName) { init(); }

    void setValues(QStringList) override;

private:
    void init();

    QStringList allowedCrs_;
    QMap<QString, QString> desc_;
};


class MvQOgcGeoBoundingBox : public MvQOgcName
{
public:
    MvQOgcGeoBoundingBox() = default;
    MvQOgcGeoBoundingBox(QString requestName, QString displayName) :
        MvQOgcName(requestName, displayName) {}
    MvQOgcGeoBoundingBox(QMap<QString, QString> att);

    QString minX() { return minX_; }
    QString maxX() { return maxX_; }
    QString minY() { return minY_; }
    QString maxY() { return maxY_; }

private:
    QString minX_;
    QString maxX_;
    QString minY_;
    QString maxY_;
};

class MvQOgcBoundingBox : public MvQOgcName
{
public:
    MvQOgcBoundingBox() = default;
    MvQOgcBoundingBox(QString requestName, QString displayName) :
        MvQOgcName(requestName, displayName) {}
    MvQOgcBoundingBox(QMap<QString, QString> att);
    MvQOgcBoundingBox(MvQOgcGeoBoundingBox*);

    QString crs() { return crs_; }
    QString minX() { return minX_; }
    QString maxX() { return maxX_; }
    QString minY() { return minY_; }
    QString maxY() { return maxY_; }
    QString resX() { return resX_; }
    QString resY() { return resY_; }
    void setArea(QString minX, QString maxX, QString minY, QString maxY)
    {
        minX_ = minX;
        maxX_ = maxX;
        minY_ = minY;
        maxY_ = maxY;
    }

    void clear()
    {
        crs_.clear();
        minX_.clear();
        maxX_.clear();
        minY_.clear();
        maxY_.clear();
        resX_.clear();
        resY_.clear();
    }

private:
    QString crs_;
    QString minX_;
    QString maxX_;
    QString minY_;
    QString maxY_;
    QString resX_;
    QString resY_;
};

class MvQOgcDimension : public MvQOgcName
{
public:
    MvQOgcDimension(QMap<QString, QString>, QString);
    void setValues(QString);
    void setAttributes(QMap<QString, QString>);
    QString name() { return name_; }
    QString units() { return units_; }
    QString unitSymbol() { return unitSymbol_; }
    QString defaultValue() { return default_; }

    QStringList values() { return values_; }
    QString currentValues() { return currentValues_; }
    void setCurrentValues(QString txt) { currentValues_ = txt; }


    bool isTime();

private:
    void decodePeriod(const QString&, QMap<QString, int>& res);
    void addPeriod(QDateTime&, const QMap<QString, int>&);

    QString name_;
    QString units_;
    QString unitSymbol_;
    QString default_;
    QString multipleValues_;
    QString nearestValue_;
    QString current_;

    QStringList values_;
    QString currentValues_;
};

class MvQOgcNode : public MvQOgcName
{
public:
    MvQOgcNode() = default;
    ~MvQOgcNode() override { clear(); }

    void clear()
    {
        foreach (MvQOgcNode* n, children())
            delete n;
        children_.clear();
    }

    QString value() { return value_; }
    QString displayValue() { return displayValue_; }
    QString description() { return description_; }
    QString logo() { return logo_; }

    void setValue(QString v) { value_ = v; }
    void setDisplayValue(QString d) { displayValue_ = d; }
    void setDescription(QString d) { description_ = d; }
    void setLogo(QString d) { logo_ = d; }

    void addChild(MvQOgcNode* node)
    {
        children_ << node;
        node->setParent(this);
    }
    QList<MvQOgcNode*> children() { return children_; }
    bool findByNode(MvQOgcNode*, MvQOgcNode**);
    bool findByValue(QString, MvQOgcNode**);
    bool findByDisplayValue(QString, MvQOgcNode**);

    MvQOgcNode* parent() { return parent_; }

    QString attribute(QString);
    void addAttribute(QString, QString);

private:
    void setParent(MvQOgcNode* parent) { parent_ = parent; }

    QString value_;
    QString displayValue_;
    QString description_;
    QString logo_;
    QMap<QString, QString> attr_;

    MvQOgcNode* parent_{nullptr};
    QList<MvQOgcNode*> children_;
};

class MvQOgcTree : public MvQOgcName
{
public:
    MvQOgcTree(QString requestName, QString displayName) :
        MvQOgcName(requestName, displayName), root_(new MvQOgcNode) {}

    ~MvQOgcTree() override { clear(); }

    MvQOgcNode* currentNode() { return currentNode_; }
    void setCurrentNode(MvQOgcNode*);
    QString currentValue() { return (currentNode_) ? currentNode_->value() : QString(); }
    QString currentDisplayValue() { return (currentNode_) ? currentNode_->displayValue() : QString(); }
    QString currentDescription() { return (currentNode_) ? currentNode_->description() : QString(); }

    void setCurrentValue(QString);
    void setCurrentDisplayValue(QString);

    MvQOgcNode* root() { return root_; }
    void clear()
    {
        root_->clear();
        currentNode_ = nullptr;
    }

private:
    MvQOgcNode* root_{nullptr};
    MvQOgcNode* currentNode_{nullptr};
};


class MvQOgcElem
{
public:
    MvQOgcElem() = default;
    virtual ~MvQOgcElem();

    QString attribute(QString);
    MvQOgcElem* elem(QString);

    void addAttribute(QString, QString);
    void addElem(QString, MvQOgcElem*);

private:
    QMap<QString, QString> attr_;
    QMap<QString, MvQOgcElem*> elem_;
};
