/***************************** 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>
#include <QBuffer>
#include <QFile>
#ifdef METVIEW_QT5
#include <QtXmlPatterns/QXmlQuery>
#include <QtXmlPatterns/QXmlResultItems>
#else
#include <QXmlQuery>
#include <QXmlResultItems>
#endif
#include "MvKeyProfile.h"

#include "MvQXmlQuery.h"
#include "MvQVisDefManager.h"


void MvQVisDef::addKey(QString key, QString value)
{
    keys_[key] << value;
}
//===============================================================
//
// MvQVisDefManagerBase
//
//===============================================================

MvQVisDefManagerBase::MvQVisDefManagerBase(string fConf, DataType dataType) :
    fConf_(fConf),
    dataType_(dataType)
{
    loaded_                 = false;
    dataTypeName_[GribType] = "GRIB";
}


MvQVisDefManagerBase::~MvQVisDefManagerBase()
{
    clear();
}

void MvQVisDefManagerBase::clear()
{
    foreach (MvQVisDef* item, items_) {
        delete item;
    }
    items_.clear();
}

MvQVisDef* MvQVisDefManagerBase::addItem(QString name)
{
    MvQVisDef* item = new MvQVisDef(name);
    items_.push_back(item);
    return item;
}

void MvQVisDefManagerBase::deleteItem(int index)
{
    //vector<MvKeyProfile*>::iterator it=begin()+index;
    //delete (*it);
    //erase(it);
}

void MvQVisDefManagerBase::collectKeys()
{
    keys_.clear();
    foreach (MvQVisDef* item, items_) {
        QMapIterator<QString, QStringList> it(item->keys());
        while (it.hasNext()) {
            it.next();
            if (!keys_.contains(it.key())) {
                keys_ << it.key();
            }
        }
    }

    keys_.removeDuplicates();
    qDebug() << "All keys:" << keys_;
}

//===============================================================
//
// MvQVisDefManager
//
//===============================================================

MvQVisDefManager::MvQVisDefManager(string fConf, DataType dataType) :
    MvQVisDefManagerBase(fConf, dataType)
{
    classType_ = "MvQVisDefManager";
}

void MvQVisDefManager::loadItems()
{
    loaded_ = true;

    QFile file(fConf_.c_str());

    if (file.open(QFile::ReadOnly | QFile::Text) == false) {
        //MvKeyProfile *prof=new MvKeyProfile("Metview default");
        //push_back(prof);

        //createDefaultProfile(prof);
        //saveProfiles();
        return;
    }

    QString xmlConf(file.readAll());
    qDebug() << xmlConf;

    QXmlResultItems result;

    QByteArray ba = xmlConf.toUtf8();
    QBuffer buffer(&ba);  // This is a QIODevice.
    buffer.open(QIODevice::ReadOnly);

    MvQXmlQuery query;
    query.bindVariable("myDoc", &buffer);
    query.bindVariable("dataType", QVariant(dataTypeName_[GribType]));
    query.setQuery("doc($myDoc)//VisDef[@dataType=$dataType]/Item");
    query.evaluateTo(&result);

    //Item nodes
    QXmlItem item(result.next());
    while (!item.isNull()) {
        if (item.isNode()) {
            QXmlResultItems keyResult, iconResult;
            QString name;

            //QXmlQuery query;
            query.setFocus(item);

            //Name of item node
            query.setQuery("string(./@name)");
            query.evaluateTo(&name);
            name = name.simplified();

            qDebug() << "Item:" << name;

            //Create new item
            MvQVisDef* visDef = new MvQVisDef(name);
            items_.push_back(visDef);

            //Key nodes
            query.setQuery("./Key");
            query.evaluateTo(&keyResult);

            //Key nodes
            QXmlItem keyItem(keyResult.next());
            while (!keyItem.isNull()) {
                if (keyItem.isNode()) {
                    QString keyName, keyValue;

                    QMap<QString, QString> att;
                    query.getAttributes(keyItem, att);

                    if (att.contains("name"))
                        keyName = att["name"];

                    if (att.contains("value"))
                        keyValue = att["value"];

                    visDef->addKey(keyName, keyValue);

                    qDebug() << "Key:" << keyName << keyValue;
                }

                keyItem = keyResult.next();
            }

            //Key nodes
            //QXmlQuery query;
            query.setFocus(item);
            query.setQuery("./Icon");
            query.evaluateTo(&iconResult);

            //Key nodes
            QXmlItem iconItem(iconResult.next());
            while (!iconItem.isNull()) {
                if (iconItem.isNode()) {
                    QString iconName;

                    QMap<QString, QString> att;
                    query.getAttributes(iconItem, att);

                    if (att.contains("name"))
                        iconName = att["name"];

                    visDef->addVisDef(iconName);

                    qDebug() << "Icon:" << iconName;
                }

                iconItem = iconResult.next();
            }
        }

        item = result.next();
    }

    file.close();

    collectKeys();
}

void MvQVisDefManager::saveItems()
{
    //Open file for writing
    QFile out(fConf_.c_str());
    out.open(QFile::WriteOnly | QFile::Text);

    QString s;

    s = "<VisDef dataType=\"" + dataTypeName_[GribType] + "\">\n";
    out.write(s.toUtf8());

    foreach (MvQVisDef* item, items_) {
        s = "<Item name=\"" + item->name() + "\">\n";
        out.write(s.toUtf8());

        QMapIterator<QString, QStringList> it(item->keys());
        while (it.hasNext()) {
            it.next();

            s = "\t<Key name=\"" + it.key() + "\"" +
                "     value=\"" + it.value().join(",") + "\"/>\n";

            out.write(s.toUtf8());
        }

        foreach (QString icon, item->visDefs()) {
            s = "<Icon name=\"" + icon + "\"/>\n";
            out.write(s.toUtf8());
        }

        s = "</Item>\n";
        out.write(s.toUtf8());
    }

    s = "</VisDef>\n";
    out.write(s.toUtf8());
    //s="</Service>\n";
    //out.write(s.toUtf8());

    out.close();
}


QStringList MvQVisDefManager::visDefFile(MvKeyProfile* prof, int index)
{
    QMap<QString, QString> messageKeys;
    for (vector<MvKey*>::iterator it = prof->begin(); it != prof->end(); it++) {
        QString name      = QString::fromStdString((*it)->name());
        QString val       = QString::fromStdString((*it)->value().at(index));
        messageKeys[name] = val;
    }

    qDebug() << messageKeys;

    bool found;
    foreach (MvQVisDef* item, items_) {
        QMapIterator<QString, QStringList> it(item->keys());

        while (it.hasNext() == true) {
            it.next();

            qDebug() << "key:" << it.key() << it.value();

            found = false;
            if (messageKeys.contains(it.key()) == true &&
                it.value().contains(messageKeys[it.key()]) == true) {
                found = true;
            }
            else
                break;
        }
        if (found == true) {
            qDebug() << "icons:" << item->visDefs();
            return item->visDefs();
        }
    }

    return QStringList();
}


//===============================================================
//
// MvQObstatVisDefManager
//
//===============================================================


MvQObstatVisDefManager::MvQObstatVisDefManager(string fConf, DataType dataType) :
    MvQVisDefManagerBase(fConf, dataType)
{
    classType_ = "MvQObstatVisDefManager";

    MvRequest req("PCONT");
    //req("PATH")      = grib_->fileName().c_str();
    req("TEMPORARY") = 0;
    //req("OFFSET")    = offset;
    //req("LENGTH")    = size;
    //req("_CLASS")    = GRIB;
    //req("_NAME")     = (const char*)name.c_str();

    req("CONTOUR") = "OFF";
    //req("CONTOUR_MIN_LEVEL") = "10";
    req("CONTOUR_LEVEL_SELECTION_TYPE") = "INTERVAL";
    //req("CONTOUR_INTERVAL") = "10";
    req("CONTOUR_SHADE")                  = "ON";
    req("CONTOUR_SHADE_TECHNIQUE")        = "GRID_SHADING";
    req("CONTOUR_SHADE_MIN_LEVEL_COLOUR") = "BLUE";
    req("CONTOUR_SHADE_MAX_LEVEL_COLOUR") = "RED";
    req("CONTOUR_SHADE_COLOUR_DIRECTION") = "ANTICLOCKWISE";
    req("CONTOUR_SHADE_METHOD")           = "AREA_FILL";
    req("CONTOUR_LABEL")                  = "OFF";
    req("CONTOUR_HILO")                   = "OFF";

    baseRequest_ = req;
}

void MvQObstatVisDefManager::loadItems()
{
    loaded_ = true;

    QFile file(fConf_.c_str());

    if (file.open(QFile::ReadOnly | QFile::Text) == false) {
        return;
    }

    QTextStream in(&file);
    while (!in.atEnd()) {
        QString line = in.readLine();
        if (line.contains("#") == false) {
            QStringList lst = line.split(" | ", QString::SkipEmptyParts);

            if (lst.count() == 0 || lst[0].count() < 8)
                continue;

            qDebug() << lst;

            QString str     = lst[0].simplified();
            QString id      = str.mid(0, 3);
            QString sensor  = str.mid(3, 3);
            QString channel = str.mid(6);

            //Obs        fgdep       bcor       Obstdv       fgdStdv    BcorSTDV      Count     Unit
            QStringList statId;
            statId << "2"
                   << "4"
                   << "18"
                   << "3"
                   << "5"
                   << "19"
                   << "1";

            int statCnt = 0;
            for (int i = 1; i < lst.count() && i < statId.count(); i++) {
                QString keyName, keyValue;

                QStringList vDefLst = lst[i].split(" ", QString::SkipEmptyParts);
                qDebug() << "stat:" << vDefLst;
                if (vDefLst.count() == 3) {
                    MvQVisDef* visDef = new MvQVisDef("obstat");
                    items_.push_back(visDef);

                    keyName  = "platform";
                    keyValue = QString::number(id.toInt());
                    visDef->addKey(keyName, keyValue);

                    keyName  = "instrument";
                    keyValue = QString::number(sensor.toInt());
                    visDef->addKey(keyName, keyValue);

                    keyName  = "scaledValueOfFirstFixedSurface";
                    keyValue = channel;
                    visDef->addKey(keyName, keyValue);

                    keyName  = "observationDiagnostic";
                    keyValue = statId[statCnt];
                    visDef->addKey(keyName, keyValue);

                    visDef->addVisDef(vDefLst[0]);
                    visDef->addVisDef(vDefLst[1]);

                    qDebug() << visDef->keys();
                    qDebug() << visDef->visDefs();
                }

                statCnt++;
            }
        }
    }

    file.close();

    collectKeys();
}

MvRequest MvQObstatVisDefManager::visDefRequest(MvKeyProfile* prof, int index)
{
    QMap<QString, QString> messageKeys;
    for (vector<MvKey*>::iterator it = prof->begin(); it != prof->end(); it++) {
        QString name      = QString::fromStdString((*it)->name());
        QString val       = QString::fromStdString((*it)->value().at(index));
        messageKeys[name] = val;
    }

    qDebug() << messageKeys;

    bool found;
    foreach (MvQVisDef* item, items_) {
        QMapIterator<QString, QStringList> it(item->keys());

        while (it.hasNext() == true) {
            it.next();

            qDebug() << "key:" << it.key() << it.value();

            found = false;
            if (messageKeys.contains(it.key()) == true &&
                it.value().contains(messageKeys[it.key()]) == true) {
                found = true;
            }
            else
                break;
        }
        if (found == true) {
            qDebug() << "visdef:" << item->visDefs();
            QStringList vd = item->visDefs();
            MvRequest r    = baseRequest_;

            if (vd[0] != "-99") {
                r("CONTOUR_MIN_LEVEL") = vd[0].toStdString().c_str();
            }
            r("CONTOUR_INTERVAL") = vd[1].toStdString().c_str();

            return r;
        }
    }

    return MvRequest();
}


/*void  MvQVisDefManager::createDefaultProfile(MvKeyProfile *prof)
{
	if(keyType_ == GribType)
	{
		prof->addKey(new MvKey("count","Index"));	
		prof->addKey(new MvKey("mars.date","Date"));
		prof->addKey(new MvKey("mars.time","Time"));
		prof->addKey(new MvKey("mars.step","Step"));
		prof->addKey(new MvKey("mars.param","Param"));
		prof->addKey(new MvKey("dataRepresentationType","Rep"));
		prof->addKey(new MvKey("mars.levelist","Level"));
		prof->addKey(new MvKey("mars.levtype","Levtype"));
	}
	else if(keyType_ == BufrType)
	{
		MvKey *key;

		key=new MvKey("editionNumber","Edition","BUFR Edition Number");
		key->setMetaData("section","1");
		prof->addKey(key);	

 		key=new MvKey("masterTable","Master Table","Master table");
		key->setMetaData("section","1");
		prof->addKey(key);

		key=new MvKey("masterTableVersion","Master Table Version Number","Master table version");
		key->setMetaData("section","1");
		prof->addKey(key);

		key=new MvKey("localTableVersion","Local Table Version Number","Local table version");
		key->setMetaData("section","1");
		prof->addKey(key);

		key=new MvKey("messageType","Message type","Message type");
		key->setMetaData("section","1");
		prof->addKey(key);

		key=new MvKey("messageSubType","Message subtype","Message sub type");
		key->setMetaData("section","1");
		prof->addKey(key);

		key=new MvKey("originatingCentre","Originating Centre","Originating centre");
		key->setMetaData("section","1");
		prof->addKey(key);

		key=new MvKey("msgSubsetCount","msgSubsetCount","msgSubsetCount");
		key->setMetaData("section","1");
		prof->addKey(key);

		key=new MvKey("date","Date","Date");
		key->setMetaData("section","2");
		prof->addKey(key);

	}
} */
