/***************************** 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 "MvQBufrDataItem.h"

#include <QDebug>
#include <QJsonArray>

//#define _UI_MVQBUFRDATAITEM_DEBUG

MvQBufrDataItem::MvQBufrDataItem(MvQBufrDataItem* parent) :
    parent_(parent)
{
    parent_ = parent;
    if (parent_)
        parent_->addChild(this);
}

MvQBufrDataItem::~MvQBufrDataItem()
{
    qDeleteAll(children_);
}

void MvQBufrDataItem::addChild(MvQBufrDataItem* item)
{
    children_ << item;
}

MvQBufrDataItem* MvQBufrDataItem::childAt(int row)
{
    return children_.value(row);
}

int MvQBufrDataItem::childCount() const
{
    return children_.count();
}

int MvQBufrDataItem::indexInParent() const
{
    if (parent_)
        return parent_->children_.indexOf(const_cast<MvQBufrDataItem*>(this));

    return 0;
}

QString MvQBufrDataItem::data(QString key) const
{
    return data_.value(key);
}

QString MvQBufrDataItem::key() const
{
    return data_.value("key");
}

QString MvQBufrDataItem::value(int subset) const
{
    if (valueArray_.count() == 0 || key() == "unexpandedDescriptors")
        return data_.value("value");
    else if (subset >= 0 && subset < valueArray_.count())
        return valueArray_[subset] + " (" + QString::number(valueArray_.count()) + " items)";

    return QString();
}

MvQBufrDataItem* MvQBufrDataItem::loadDump(QJsonDocument doc, QString& err)
{
    MvQBufrDataItem* rootItem = new MvQBufrDataItem();

    if (doc.isNull() || !doc.isObject())
        return rootItem;

    QJsonValue root(doc.object().value("messages"));
    if (root.isArray() && root.toArray().count() == 1) {
        QJsonArray data = root.toArray().first().toArray();
        if (data.isEmpty()) {
            if (root.toArray().first().isString()) {
                QString msgStr = root.toArray().first().toString();
                if (msgStr.contains("error", Qt::CaseInsensitive))
                    err = msgStr;
            }
            return rootItem;
        }

        //Header
        MvQBufrDataGroupItem* headerItem = new MvQBufrDataGroupItem(rootItem);
        headerItem->title_               = "Header";
        bool inHeader                    = true;

        //Data
        MvQBufrDataGroupItem* dataItem = new MvQBufrDataGroupItem(rootItem);
        dataItem->title_               = "Data";

        foreach (QJsonValue v, data) {
            //It is a header item
            if (!v.isArray()) {
                QJsonObject o = v.toObject();
                if (inHeader)
                    addItem(v.toObject(), headerItem);

                if (o.value("key").toString() == "unexpandedDescriptors")
                    inHeader = false;
            }
            //Data items
            else {
                inHeader = false;
                MvQBufrDataItem::loadDump(v, dataItem);
            }
        }

        //loadDump(data,rootItem);
    }

    return rootItem;
}

void MvQBufrDataItem::loadDump(const QJsonValue& value, MvQBufrDataItem* parent)
{
#if 0
    QStringList excludes;
    excludes << "code" << "reference" << "scale" << "width" << "data" << "position" << "index";

    QHash<QString,QString> headers;

    foreach(QJsonValue v, value.toArray())
    {
        if(!v.isArray())
        {
             foreach(QJsonValue key, v.toObject().keys())
             {
                 if(key.isString())
                 {
                    if(excludes.indexOf(key.toString()) == -1)
                    {
                        headers[key.toString()]="";
                    }
                 }
             }

             qDebug() << " headers" << headers;
        }
    }

    headers.clear();
#endif

    int arrayCnt = 0;
    int keyCnt   = 0;

    foreach (QJsonValue v, value.toArray()) {
        if (v.isArray())
            arrayCnt++;
        else
            keyCnt++;
    }

    foreach (QJsonValue v, value.toArray()) {
        //Normal object
        if (!v.isArray()) {
            QJsonObject o = v.toObject();
            addItem(o, parent);
        }
        //Array
        else {
            //Each will be a group
            if (arrayCnt > 1) {
                MvQBufrDataGroupItem* item = new MvQBufrDataGroupItem(parent);
                loadDump(v, item);

                if (item->childCount() > 0) {
                    item->data_       = item->childAt(0)->data_;
                    item->valueArray_ = item->childAt(0)->valueArray_;
                    item->title_      = item->key() + ": ";
                    //item->title_=item->key() + ": " +item->value();
                }
            }
            else {
                loadDump(v, parent);
            }
        }
    }
}

void MvQBufrDataItem::addItem(QJsonObject o, MvQBufrDataItem* parent)
{
    if (!o.keys().contains("key"))
        return;

#ifdef _UI_MVQBUFRDATAITEM_DEBUG
    qDebug() << "object -->";
    qDebug() << "  parent" << parent;
    qDebug() << "  keys: " << o.keys();
#endif
    MvQBufrDataItem* item = new MvQBufrDataItem(parent);

    foreach (QString key, o.keys()) {
#ifdef _UI_MVQBUFRDATAITEM_DEBUG
        qDebug() << "   --> key:" << key;
#endif
        QJsonValue v = o.value(key);
        if (!v.isObject() && !v.isArray()) {
            QString s = v.toVariant().toString();
            if (key == "value") {
                s = beautify(s);
            }

            item->data_[key] = s;
        }
        else if (v.isArray() && key == "value") {
            QJsonArray vec = v.toArray();
            for (int i = 0; i < vec.size(); i++) {
                item->valueArray_ << vec.at(i).toVariant().toString();
            }
            item->data_[key] = beautify(item->valueArray_);
        }
        else if (v.isObject()) {
            addItem(v.toObject(), item);
        }
    }
#ifdef _UI_MVQBUFRDATAITEM_DEBUG
    qDebug() << "  " << item->data_;
    qDebug() << "<-- object";
#endif
}

QString MvQBufrDataItem::beautify(QString val)
{
    static QHash<QString, QString> beautifiers;
    if (beautifiers.isEmpty()) {
        beautifiers["null"] = "missing";
        beautifiers[""]     = "missing";
    }

    if (beautifiers.contains(val)) {
        return beautifiers.value(val);
    }
    return val;
}

QString MvQBufrDataItem::beautify(QStringList val)
{
    QString s;
    int num = val.size();
    if (num <= 4) {
        s += val.join(",");
    }
    else {
        s = val[0] + ", " + val[1] + ", ..., " + val[num - 2] + ", " + val[num - 1];
    }

    s = "[" + s + "]";

    if (num > 4)
        s += "  (" + QString::number(num) + " items)";

    return s;
}

QString MvQBufrDataItem::extra()
{
    if (isGroup() || childCount() == 0)
        return QString();

    QString s;
    for (int i = 0; i < children_.count(); i++) {
        if (!s.isEmpty())
            s += " ";
        s += "[" + children_.at(i)->key() + "=" + children_.at(i)->value() + "]";
    }

    return s;
}

QString MvQBufrDataGroupItem::title(int subset) const
{
    return title_ + value(subset);
}
