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

#include <iostream>
#include <sstream>

#include "MvMiscellaneous.h"

#include <QDebug>

//#define _UI_BufrFlatDataItem_DEBUG

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

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

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

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

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

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

    return 0;
}

QString BufrFlatDataItem::key() const
{
    return key_;
}


QString BufrFlatDataItem::getValue(int subset, bool includeCount) const
{
    if (valueArray_.count() == 0 || key() == "unexpandedDescriptors")
        return value_;
    else if (subset >= 0 && subset < valueArray_.count()) {
        auto v = valueArray_[subset];
        if (includeCount) {
            v += " (" + QString::number(valueArray_.count()) + " items)";
        }
        return v;
    }
    return {};
}

BufrFlatDataItem* BufrFlatDataItem::loadDump(const std::string& dump, QString&)
{
    auto* rootItem = new BufrFlatDataItem();

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

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

    BufrFlatDataItem *currentSubsetItem = nullptr;

    std::istringstream f(dump);
    std::string line;
    std::string key;
    std::string value;
    bool isArrayVal = false;
    while (std::getline(f, line)) {
        std::size_t pos = line.find("=");
        if (pos != std::string::npos) {
            if (!key.empty()) {
                if (inHeader) {
                    addItem(key, value, isArrayVal, headerItem, inHeader);
                    if (key == "unexpandedDescriptors") {
                        inHeader = false;
                    }
                } else {
                    if (key ==  "subsetNumber") {
                        currentSubsetItem  = addSubsetItem(key, value, dataItem);
                    } else {
                        if (currentSubsetItem) {
                            addItem(key, value, isArrayVal, currentSubsetItem, inHeader);
                        } else {
                            addItem(key, value, isArrayVal, dataItem, inHeader);
                        }
                    }
                }
            }
            key.clear();
            value.clear();
            isArrayVal = false;

            if (pos+1 <= line.length()) {
                key = line.substr(0, pos);
                value = line.substr(pos+1);
                if (value[0] == '{' ||  value.substr(0,2) == " {") {
                    isArrayVal = true;
                    value = metview::simplified(value);
                }
            }
        } else if(isArrayVal) {
            value += metview::simplified(line);
        }
    }

    // last item
    if (!key.empty()) {
        if (inHeader) {
            addItem(key, value, isArrayVal, headerItem, inHeader);
            if (key == "unexpandedDescriptors") {
                inHeader = false;
            }
        } else {
            if (key ==  "subsetNumber") {
                currentSubsetItem  = addSubsetItem(key, value, dataItem);
            } else {
                if (currentSubsetItem) {
                    addItem(key, value, isArrayVal, currentSubsetItem, inHeader);
                } else {
                    addItem(key, value, isArrayVal, dataItem, inHeader);
                }
            }
        }
    }

    return rootItem;
}


BufrFlatDataItem* BufrFlatDataItem::addItem(const std::string& key, const std::string& value,
                                            bool isArrayValue, BufrFlatDataItem* parent, bool inHeader)
{
    auto* item = new BufrFlatDataItem(parent);
    item->key_ = QString::fromStdString(key);

    if (isArrayValue) {
        auto s = QString::fromStdString(value);
        auto lst = parseArray(s);
        item->value_ = beautify(lst, inHeader);

        if (!inHeader) {
            item->valueArray_ = lst;
        }
    } else {
        item->value_ = QString::fromStdString(value);
    }

    return item;


#ifdef _UI_BufrFlatDataItem_DEBUG
    qDebug() << "object -->";
    qDebug() << "  parent" << parent;
    qDebug() << "  keys: " << o.keys();
#endif
}

BufrFlatDataItem* BufrFlatDataItem::addSubsetItem(const std::string& key, const std::string& value, BufrFlatDataItem* parent)
{
    auto* item = new BufrFlatDataGroupItem(parent);
    item->key_ = QString::fromStdString(key);
    item->value_ =  QString::fromStdString(value);
    item->title_ = item->key_ + ": ";
    return item;
}

QStringList BufrFlatDataItem::parseArray(QString value)
{
    if (value.startsWith("{") && value.endsWith("}")) {
        auto lst = value.mid(1,value.size()-2).split(",");
        return lst;
    }
    return {};
}

QString BufrFlatDataItem::beautify(QStringList val, bool inHeader)
{
    QString s;

    if (inHeader) {
        s = val.join(",");
        s = "[" + s + "]";
    } else {
        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 BufrFlatDataGroupItem::title(int subset) const
{
    return title_ + value(subset);
}
