/***************************** LICENSE START ***********************************

 Copyright 2019 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 <sstream>
#include <cassert>

#include "BufrExpandDataModel.h"
#include "MvKeyProfile.h"

BufrExpandDataModel::BufrExpandDataModel(QObject* parent) :
    QAbstractItemModel(parent)
{
    templateProf_ = new MvKeyProfile("bufrExpandDump");
    auto* dKey = new MvKey("Descriptor", "Descriptor");
    templateProf_->addKey(dKey);
    auto* kKey = new MvKey("Key", "Key");
    templateProf_->addKey(kKey);
    auto* nKey = new MvKey("Long name", "Long name");
    templateProf_->addKey(nKey);
    auto* uKey = new MvKey("Units", "Units");
    templateProf_->addKey(uKey);
}

BufrExpandDataModel::~BufrExpandDataModel()
{
    delete templateProf_;
    if (prof_)
        delete prof_;
}

void BufrExpandDataModel::clear()
{
    beginResetModel();
    if (prof_) {
        delete prof_;
    }
    prof_ = nullptr;
    endResetModel();
}

bool BufrExpandDataModel::loadDumpData(const std::string& dump, QString& /*err*/)
{
    MvKeyProfile* prof = templateProf_->clone();
    MvKey* dKey = prof->at(0);
    MvKey* kKey = prof->at(1);
    MvKey* nKey = prof->at(2);
    MvKey* uKey = prof->at(3);

    // parse text

    // the format is:
    // descriptor key long_name [units]
    // where bot long_name and units can contain spaces

    std::istringstream f(dump);
    std::string line;
    while (std::getline(f, line)) {
        std::vector<std::string> svec;
        std::istringstream iss(line);
        for (std::string si; iss >> si;)
            svec.push_back(si);

        if (svec.size() >= 3) {
            if (svec[0].find("*") != std::string::npos)
                continue;

            dKey->addValue(" " + svec[0]);
            kKey->addValue(svec[1]);

            // units
            size_t uPosEnd = svec.size() - 1;
            size_t uPosStart = uPosEnd + 1;
            std::string u = svec[uPosEnd];
            if (u.size() > 1 && u[u.size() - 1] == ']') {
                for (size_t i = uPosEnd; i >= 3; i--) {
                    u = svec[i];
                    if (u[0] == '[') {
                        uPosStart = i;
                        break;
                    }
                }
            }

            std::string uVal;
            for (size_t i = uPosStart; i <= uPosEnd; i++) {
                if (!uVal.empty()) {
                    uVal += " ";
                }
                uVal += svec[i];
            }
            if (uVal.empty()) {
                uVal = "N/A";
            }
            else {
                assert(uVal.size() >= 2);
                uVal = uVal.substr(1, uVal.size() - 2);
            }
            uKey->addValue(uVal);

            // long name
            std::string nVal;
            for (size_t i = 2; i < uPosStart; i++) {
                if (!nVal.empty()) {
                    nVal += " ";
                }
                nVal += svec[i];
            }
            nKey->addValue(nVal);
        }
    }

    beginResetModel();
    if (prof_) {
        delete prof_;
    }
    prof_ = prof;
    endResetModel();

    return true;
}

int BufrExpandDataModel::columnCount(const QModelIndex& /* parent */) const
{
    return templateProf_->size();
}

int BufrExpandDataModel::rowCount(const QModelIndex& index) const
{
    if (!prof_)
        return 0;

    if (!index.isValid()) {
        return prof_->valueNum();
    }
    else {
        return 0;
    }
}

QVariant BufrExpandDataModel::data(const QModelIndex& index, int role) const
{
    if (!index.isValid()) {
        return {};
    }

    if (role == Qt::DisplayRole) {
        int row = index.row();
        int column = index.column();

        if (!prof_ || row < 0 || row >= prof_->valueNum() ||
            column < 0 || column >= static_cast<int>(prof_->size())) {
            return {};
        }

        MvKey* key = prof_->at(column);
        return QString::fromStdString(key->stringValue()[row]);
    }

    return {};
}

QVariant BufrExpandDataModel::headerData(const int section, const Qt::Orientation orient, const int role) const
{
    if (orient != Qt::Horizontal ||
        section < 0 || section >= static_cast<int>(templateProf_->size())) {
        return QAbstractItemModel::headerData(section, orient, role);
    }

    if (role == Qt::DisplayRole) {
        if (!templateProf_->at(section)->shortName().empty())
            return QString(templateProf_->at(section)->shortName().c_str());
        else
            return QString(templateProf_->at(section)->name().c_str());
    }

    return {};
}

QModelIndex BufrExpandDataModel::index(int row, int column, const QModelIndex& /*parent*/) const
{
    if (!prof_) {
        return {};
    }

    return createIndex(row, column, (void*)nullptr);
}


QModelIndex BufrExpandDataModel::parent(const QModelIndex& /*index*/) const
{
    return {};
}
