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

#include <QDebug>

#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include <QtCore5Compat/QRegExp>
#else
#include <QRegExp>
#endif

#include "MvQOgcParam.h"

MvQHtmlDecoder MvQOgcName::htmlDecoder_;


QString MvQHtmlDecoder::decode(QString& htmlTxt)
{
    clear();
    setHtml(htmlTxt);
    return toPlainText();
}

//--------------------------------
// MvQOgcValue
//--------------------------------

void MvQOgcIntValue::setValue(int value)
{
    value_ = value;
    checkValue();
}

void MvQOgcIntValue::setMinValue(int min)
{
    minValue_ = min;
    checkValue();
}

void MvQOgcIntValue::setMaxValue(int max)
{
    maxValue_ = max;
    checkValue();
}

void MvQOgcIntValue::checkValue()
{
    if (minIsSet_ && value_ < minValue_) {
        value_ = minValue_;
    }
    if (maxIsSet_ && value_ > maxValue_) {
        value_ = maxValue_;
    }
}

//--------------------------------
// MvQOgcList
//--------------------------------

QString MvQOgcList::currentValue()
{
    if (currentIndex_ != -1) {
        return values_[currentIndex_];
    }
    return {};
}

QString MvQOgcList::currentDisplayValue()
{
    if (currentIndex_ != -1) {
        return displayValues_[currentIndex_];
    }
    return {};
}

QString MvQOgcList::currentDescription()
{
    if (currentIndex_ != -1) {
        return descriptions_[currentIndex_];
    }
    return {};
}


void MvQOgcList::setCurrentValue(QString s)
{
    int index = values_.indexOf(s);
    if (index >= 0)
        currentIndex_ = index;
}

void MvQOgcList::setCurrentDisplayValue(QString s)
{
    int index = displayValues_.indexOf(s);
    if (index >= 0)
        currentIndex_ = index;
}

void MvQOgcList::setCurrentIndex(int index)
{
    if (index >= 0 && index < values_.count())
        currentIndex_ = index;
}

QString MvQOgcStyleList::currentLegend()
{
    if (currentIndex_ != -1) {
        return legends_[currentIndex_];
    }
    return {};
}

void MvQOgcStyleList::setLegends(QStringList lst)
{
    legends_.clear();
    foreach (QString s, lst) {
        legends_ << htmlDecoder_.decode(s);
    }
}

//--------------------------------
// MvQOgcCrsList
//--------------------------------

void MvQOgcCrsList::init()
{
    // desc_["EPSG:4326"]  = "Cylindrical/WGS 84";
    // desc_["EPSG:32661"] = "Polar Stereo North";
    // desc_["EPSG:32761"] = "Polar Stereo South";
}

void MvQOgcCrsList::setValues(QStringList values)
{
    MvQOgcList::setValues(values);

    foreach (QString val, values_) {
        QString dpyName = val;
        if (desc_.contains(val)) {
            dpyName = "(" + desc_[val] + ") " + dpyName;
        }
        addDisplayValue(dpyName);
    }
}

//--------------------------------
// MvQOgcGeoBoundingBox
//--------------------------------

MvQOgcGeoBoundingBox::MvQOgcGeoBoundingBox(QMap<QString, QString> att)
{
    if (att.contains("minx")) {
        minX_ = att["minx"];
        maxX_ = att["maxx"];
        minY_ = att["miny"];
        maxY_ = att["maxy"];
    }
    else if (att.contains("westBoundLongitude")) {
        minX_ = att["westBoundLongitude"];
        maxX_ = att["eastBoundLongitude"];
        minY_ = att["southBoundLatitude"];
        maxY_ = att["northBoundLatitude"];
    }
}

//--------------------------------
// MvQOgcBoundingBox
//--------------------------------

MvQOgcBoundingBox::MvQOgcBoundingBox(MvQOgcGeoBoundingBox* geo) :
    crs_("EPSG:4326")
{
    minX_ = geo->minX();
    maxX_ = geo->maxX();
    minY_ = geo->minY();
    maxY_ = geo->maxY();
}


MvQOgcBoundingBox::MvQOgcBoundingBox(QMap<QString, QString> att)
{
    if (att.contains("CRS"))
        crs_ = att["CRS"];
    else if (att.contains("SRS"))
        crs_ = att["SRS"];

    minX_ = att["minx"];
    maxX_ = att["maxx"];
    minY_ = att["miny"];
    maxY_ = att["maxy"];
    resX_ = att["resx"];
    resY_ = att["resy"];
}

//--------------------------------
// MvQOgcDimensionListList
//--------------------------------

MvQOgcDimension::MvQOgcDimension(QMap<QString, QString> att, QString value)
{
    // qDebug() << "dimName:" << att["name"];
    // valueMode_=ListMode;
    setAttributes(att);
    setValues(value);
}

void MvQOgcDimension::setAttributes(QMap<QString, QString> att)
{
    if (att.contains("name"))
        name_ = att["name"];
    if (att.contains("units"))
        units_ = att["units"];
    if (att.contains("unitSymbol"))
        unitSymbol_ = att["unitSymbol"];
    if (att.contains("default"))
        default_ = htmlDecoder_.decode(att["default"]);
    // default_=att["default"];
    if (att.contains("multipleValues"))
        multipleValues_ = att["multipleValues"];
    if (att.contains("nearesValues"))
        nearestValue_ = att["nearestValue"];
    if (att.contains("current"))
        current_ = att["current"];
}

void MvQOgcDimension::setValues(QString dimData)
{
    dimData = htmlDecoder_.decode(dimData);

    // Time
    values_.clear();

    if (default_.isEmpty() == false) {
        QString s = "Default (" + default_ + ")";
        values_ << s;
    }

    values_ << dimData.split(",");


    /*	if(units_ == "ISO8601")
    {
        if(name_.compare("time",Qt::CaseInsensitive) == 0)
        {
            valueSelectionMode_=MultipleSelectionMode;
        }

        qDebug() << "Time:" << dimData;
        QStringList data=dimData.split(",");
        foreach(QString item, data)
        {
            QStringList lst=item.split("/");

            qDebug() << "Time:" << lst;

            //Period
            if(lst.count() == 3)
            {
                QDateTime startDate=QDateTime::fromString(lst[0],Qt::ISODate);
                QDateTime endDate=QDateTime::fromString(lst[1],Qt::ISODate);
                QMap<QString,int> period;
                decodePeriod(lst[2],period);

                QDateTime dt=startDate;
                while(dt <= endDate)
                {
                    QString s=dt.toString(Qt::ISODate);
                    s+="Z";
                    values_.push_back(s);
                    addPeriod(dt,period);
                    if(dt <= startDate)
                        break;
                }

                qDebug() << "time: " << startDate << endDate << period;
                qDebug() << "value_" << values_;

            }
            else
            {
                values_.push_back(item);
            }
        }
    }
    else
    {
        QStringList data=dimData.split(",");
        foreach(QString item, data)
        {
            QStringList lst=item.split("/");

            //Period
            if(lst.count() == 3)
            {
                float minVal=lst[0].toFloat();
                float maxVal=lst[1].toFloat();
                float stepVal=lst[2].toFloat();

                if( (maxVal-minVal)/stepVal > 20)
                {
                    valueMode_=StepMode;
                    minValue_=minVal;
                    maxValue_=maxVal;
                    stepValue_=stepVal;
                }
                else
                {
                    float v=minVal;
                    while(v <= maxVal)
                    {
                        QString s=QString::number(v);
                        values_.push_back(s);
                        v+=stepVal;
                        if(v <= minVal)
                            break;
                    }
                }

            }
            else
            {
                values_.push_back(item);
            }

        }
    }	*/


    // displayValues_=values_;
}


void MvQOgcDimension::decodePeriod(const QString& period, QMap<QString, int>& res)
{
    QString pDate, pTime;

    // Test
    if (period.startsWith("P") == false)
        return;

    QStringList lst = period.split("T");
    pDate = lst[0];
    if (lst.count() > 1) {
        pTime = lst[1];
    }

    if (pDate.isEmpty() == false) {
        // Year
        QRegExp rx("(\\d+Y)");
        if (rx.indexIn(pDate) > -1) {
            res["year"] = rx.cap(1).remove("Y").toInt();
        }

        // Month
        rx = QRegExp("(\\d+M)");
        if (rx.indexIn(pDate) > -1) {
            res["month"] = rx.cap(1).remove("M").toInt();
        }

        // Day
        rx = QRegExp("(\\d+D)");
        if (rx.indexIn(pDate) > -1) {
            res["day"] = rx.cap(1).remove("D").toInt();
        }
    }

    if (pTime.isEmpty() == false) {
        // Hour
        QRegExp rx("(\\d+H)");
        if (rx.indexIn(pTime) > -1) {
            res["hour"] = rx.cap(1).remove("H").toInt();
        }

        // Minute
        rx = QRegExp("(\\d+M)");
        if (rx.indexIn(pTime) > -1) {
            res["minute"] = rx.cap(1).remove("M").toInt();
        }

        // Minute
        rx = QRegExp("(\\d+S)");
        if (rx.indexIn(pTime) > -1) {
            res["sec"] = rx.cap(1).remove("S").toInt();
        }
    }
}


void MvQOgcDimension::addPeriod(QDateTime& dt, const QMap<QString, int>& period)
{
    if (period.contains("year")) {
        dt = dt.addYears(period["year"]);
        // qDebug() << d;
    }

    if (period.contains("month")) {
        dt = dt.addMonths(period["month"]);
        // qDebug() << d;
    }

    if (period.contains("day")) {
        dt = dt.addDays(period["day"]);
        // qDebug() << d;
    }

    if (period.contains("hour")) {
        dt = dt.addSecs(period["hour"] * 3600);
        // qDebug() << d;
    }
    if (period.contains("minute")) {
        dt = dt.addSecs(period["minute"] * 60);
        // qDebug() << d;
    }
    if (period.contains("sec")) {
        dt = dt.addSecs(period["sec"]);
        // qDebug() << d;
    }
}

bool MvQOgcDimension::isTime()
{
    if (units_ == "ISO8601")
        return true;
    else
        return false;
}

bool MvQOgcNode::findByNode(MvQOgcNode* node, MvQOgcNode** resNode)
{
    if (node == this) {
        *resNode = this;
        return true;
    }

    foreach (MvQOgcNode* n, children_) {
        if (n->findByNode(node, resNode)) {
            return true;
        }
    }

    return false;
}

bool MvQOgcNode::findByValue(QString val, MvQOgcNode** resNode)
{
    if (value_ == val) {
        *resNode = this;
        return true;
    }

    foreach (MvQOgcNode* n, children_) {
        if (n->findByValue(val, resNode)) {
            return true;
        }
    }

    return false;
}

bool MvQOgcNode::findByDisplayValue(QString val, MvQOgcNode** resNode)
{
    if (displayValue_ == val) {
        *resNode = this;
        return true;
    }

    foreach (MvQOgcNode* n, children_) {
        if (n->findByDisplayValue(val, resNode)) {
            return true;
        }
    }

    return false;
}

QString MvQOgcNode::attribute(QString id)
{
    if (attr_.contains(id))
        return attr_[id];
    else
        return {};
}
void MvQOgcNode::addAttribute(QString id, QString val)
{
    attr_[id] = val;
}


void MvQOgcTree::setCurrentNode(MvQOgcNode* node)
{
    currentNode_ = nullptr;
    root_->findByNode(node, &currentNode_);
}

void MvQOgcTree::setCurrentValue(QString val)
{
    currentNode_ = nullptr;
    root_->findByValue(val, &currentNode_);
}

void MvQOgcTree::setCurrentDisplayValue(QString val)
{
    currentNode_ = nullptr;
    root_->findByDisplayValue(val, &currentNode_);
}


MvQOgcElem::~MvQOgcElem()
{
    QMapIterator<QString, MvQOgcElem*> it(elem_);
    while (it.hasNext()) {
        it.next();
        delete it.value();
    }
    elem_.clear();
}

QString MvQOgcElem::attribute(QString id)
{
    if (attr_.contains(id))
        return attr_[id];
    else
        return {};
}

MvQOgcElem* MvQOgcElem::elem(QString id)
{
    if (elem_.contains(id))
        return elem_[id];
    else
        return nullptr;
}

void MvQOgcElem::addAttribute(QString id, QString val)
{
    attr_[id] = val;
}

void MvQOgcElem::addElem(QString id, MvQOgcElem* val)
{
    elem_[id] = val;
}
