/***************************** 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 "MvQBufrDumpModel.h"
#include "BufrMetaData.h"
#include "MvKeyProfile.h"

#include "MvQKeyMimeData.h"

bool MvQBufrDumpSortFilterModel::lessThan(const QModelIndex& left, const QModelIndex& right) const
{
    QString leftData = sourceModel()->data(left).toString();
    QString rightData = sourceModel()->data(right).toString();

    // Sort as int
    if (QString::number(leftData.toInt()) == leftData) {
        return leftData.toInt() < rightData.toInt();
    }
    else {
        return QString::localeAwareCompare(leftData, rightData) < 0;
    }
}


MvQBufrSectionDumpModel::MvQBufrSectionDumpModel()
{
    data_ = 0;
}

void MvQBufrSectionDumpModel::dataIsAboutToChange()
{
    beginResetModel();
}

void MvQBufrSectionDumpModel::setDumpData(BufrSectionDump* dump)
{
    data_ = dump;

    // Reset the model (views will be notified)
    endResetModel();
}

void MvQBufrSectionDumpModel::setAllKeys(QList<MvKeyProfile*>& allKeys)
{
    allKeys_ = allKeys;
}

int MvQBufrSectionDumpModel::columnCount(const QModelIndex& /* parent */) const
{
    return 3;
}

int MvQBufrSectionDumpModel::rowCount(const QModelIndex& parent) const
{
    if (!data_)
        return 0;

    // Non-root
    if (parent.isValid()) {
        int id = parent.internalId();
        if (idToLevel(id) == 0) {
            return data_->section().at(id)->itemNum();
        }
        else {
            return 0;
        }
    }
    // Root
    else {
        return data_->sectionNum();
    }
}

Qt::ItemFlags MvQBufrSectionDumpModel::flags(const QModelIndex& index) const
{
    Qt::ItemFlags defaultFlags;

    defaultFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;

    int id = index.internalId();
    if (idToLevel(id) == 0)
        return defaultFlags;
    else
        return Qt::ItemIsDragEnabled | defaultFlags;
}

QVariant MvQBufrSectionDumpModel::data(const QModelIndex& index, int role) const
{
    if (!index.isValid() || role != Qt::DisplayRole) {
        return QVariant();
    }

    int id = index.internalId();
    if (idToLevel(id) == 0) {
        BufrSection* item = data_->section().at(id);
        return label(item, index.column());
    }
    else if (idToLevel(id) == 1) {
        int parentRow = idToParentRow(id);
        BufrSection* sec = data_->section().at(parentRow);
        BufrSectionItem* item = sec->item().at(index.row());
        return label(item, index.column());
    }

    return QVariant();
}


QVariant MvQBufrSectionDumpModel::headerData(const int section, const Qt::Orientation orient, const int role) const
{
    if (orient != Qt::Horizontal || role != Qt::DisplayRole)
        return QAbstractItemModel::headerData(section, orient, role);

    switch (section) {
        case 0:
            return QObject::tr("Section");
        case 1:
            return QObject::tr("Name");
        case 2:
            return QObject::tr("Value");
    }

    return QVariant();
}


QString MvQBufrSectionDumpModel::label(BufrSection* section, const int column) const
{
    switch (column) {
        case 0: {
            return QString(section->name().c_str());
        }
        default:
            return QString();
    }
}

QString MvQBufrSectionDumpModel::label(BufrSectionItem* item, const int column) const
{
    switch (column) {
        case 0: {
            // return QString(item->pos().c_str());
            return QString();
        }
        case 1: {
            return QString(item->name().c_str());
        }
        case 2: {
            return QString(item->value().c_str());
        }
        default:
            return QString();
    }
}


QModelIndex MvQBufrSectionDumpModel::index(int row, int column, const QModelIndex& parent) const
{
    if (!data_ || row < 0 || column < 0 || parent.column() > 3) {
        return QModelIndex();
    }

    // Parent is non-root -> level-1 items: id is the (parent row number +1)*1000
    if (parent.isValid()) {
        int id = (parent.row() + 1) * 1000;
        return createIndex(row, column, id);
    }
    // Parent is root -> level-0 items: id is the row number
    else {
        return createIndex(row, column, row);
    }
}

QModelIndex MvQBufrSectionDumpModel::parent(const QModelIndex& index) const
{
    if (!index.isValid()) {
        return QModelIndex();
    }

    int id = index.internalId();
    if (idToLevel(id) == 0) {
        return QModelIndex();
    }
    else {
        int parentRow = idToParentRow(id);
        return createIndex(parentRow, 0, parentRow);
    }

    return QModelIndex();
}

int MvQBufrSectionDumpModel::idToLevel(int id) const
{
    if (id >= 0 && id < 1000)
        return 0;
    else
        return 1;
}


int MvQBufrSectionDumpModel::idToParentRow(int id) const
{
    if (idToLevel(id) == 0)
        return -1;
    else
        return id / 1000 - 1;
}

Qt::DropActions MvQBufrSectionDumpModel::supportedDropActions() const
{
    return Qt::CopyAction;
}

QStringList MvQBufrSectionDumpModel::mimeTypes() const
{
    QStringList types;
    types << "metview/mvkey";
    return types;
}

QMimeData* MvQBufrSectionDumpModel::mimeData(const QModelIndexList& indexes) const
{
    MvQKeyMimeData* mimeData = new MvQKeyMimeData(this);

    QList<int> procRows;

    foreach (QModelIndex index, indexes) {
        int id = index.internalId();
        if (idToLevel(id) == 1 && index.isValid() &&
            procRows.indexOf(index.row()) == -1) {
            int parentRow = idToParentRow(id);
            BufrSection* sec = data_->section().at(parentRow);
            BufrSectionItem* item = sec->item().at(index.row());

            std::string dumpId = item->name();

            foreach (MvKeyProfile* prof, allKeys_) {
                bool found = false;
                for (int i = 0; i < static_cast<int>(prof->size()); i++) {
                    MvKey* key = prof->at(i);
                    if (key->metaData("dumpId") == dumpId) {
                        mimeData->addKey(key, index.row());
                        procRows << index.row();
                        found = true;
                        break;
                    }
                }
                if (found)
                    break;
            }
        }
    }

    return mimeData;
}

bool MvQBufrSectionDumpModel::dropMimeData(const QMimeData* /*data*/,
                                           Qt::DropAction /*action*/, int /*row*/, int /*column*/, const QModelIndex& /*parent*/)
{
    return false;
}

//=====================================
//
// MvQBufDataDumpModel
//
//=====================================

MvQBufrDataDumpModel::MvQBufrDataDumpModel()
{
    data_ = 0;
}

void MvQBufrDataDumpModel::dataIsAboutToChange()
{
    beginResetModel();
}


void MvQBufrDataDumpModel::setDumpData(BufrDataDump* dump)
{
    data_ = dump;

    // Reset the model (views will be notified)
    endResetModel();
}


int MvQBufrDataDumpModel::columnCount(const QModelIndex& /* parent */) const
{
    return 5;
}

int MvQBufrDataDumpModel::rowCount(const QModelIndex& parent) const
{
    if (!data_)
        return 0;

    // Non-root
    if (parent.isValid()) {
        return 0;
    }
    // Root
    else {
        return data_->itemNum();
    }
}


QVariant MvQBufrDataDumpModel::data(const QModelIndex& index, int role) const
{
    if (!index.isValid() || role != Qt::DisplayRole) {
        return QVariant();
    }

    BufrDataItem* item = data_->item().at(index.row());
    return label(item, index.row(), index.column());
}


QVariant MvQBufrDataDumpModel::headerData(const int section, const Qt::Orientation orient, const int role) const
{
    if (orient != Qt::Horizontal || role != Qt::DisplayRole)
        return QAbstractItemModel::headerData(section, orient, role);

    switch (section) {
        case 0:
            return QObject::tr("Index");
        case 1:
            return QObject::tr("Descriptor");
        case 2:
            return QObject::tr("Name");
        case 3:
            return QObject::tr("Value");
        case 4:
            return QObject::tr("Units");
    }

    return QVariant();
}


QString MvQBufrDataDumpModel::label(BufrDataItem* item, const int row, const int column) const
{
    switch (column) {
        case 0: {
            return QString::number(row);
        }
        case 1: {
            return QString(item->descriptor().c_str());
        }
        case 2: {
            return QString(item->name().c_str());
        }
        case 3: {
            return QString(item->value().c_str());
        }
        case 4: {
            return QString(item->unit().c_str());
        }

        default:
            return QString();
    }
}


QModelIndex MvQBufrDataDumpModel::index(int row, int column, const QModelIndex& /*parent*/) const
{
    return createIndex(row, column, row);
}

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

//=====================================
//
// MvQBufrBitmapDumpModel
//
//=====================================

MvQBufrBitmapDumpModel::MvQBufrBitmapDumpModel()
{
    data_ = 0;
}

void MvQBufrBitmapDumpModel::dataIsAboutToChange()
{
    beginResetModel();
}


void MvQBufrBitmapDumpModel::setDumpData(BufrBitmapDump* dump)
{
    data_ = dump;

    // Reset the model (views will be notified)
    endResetModel();
}


int MvQBufrBitmapDumpModel::columnCount(const QModelIndex& /* parent */) const
{
    if (data_ && data_->colNum() > 0)
        return data_->colNum() + 1;
    else
        return 0;
}

int MvQBufrBitmapDumpModel::rowCount(const QModelIndex& parent) const
{
    if (!data_)
        return 0;

    // Non-root
    if (parent.isValid()) {
        return 0;
    }
    // Root
    else {
        return data_->itemNum();
    }
}


QVariant MvQBufrBitmapDumpModel::data(const QModelIndex& index, int role) const
{
    if (!index.isValid() || role != Qt::DisplayRole) {
        return QVariant();
    }

    if (index.column() == 0) {
        return QString::number(index.row());
    }
    else if (index.column() < data_->colNum() + 1) {
        return QString::fromStdString(data_->item().at(index.row()).at(index.column() - 1));
    }
    else
        return QVariant();
}


QVariant MvQBufrBitmapDumpModel::headerData(const int section, const Qt::Orientation orient, const int role) const
{
    if (orient != Qt::Horizontal || (role != Qt::DisplayRole && role != Qt::ToolTipRole))
        return QAbstractItemModel::headerData(section, orient, role);


    if (section == 0)
        return QObject::tr("Index");
    else if (section == 1)
        return QObject::tr("Name");
    else if (section == 2)
        return QObject::tr("Units");
    else if (section == 3)
        return QObject::tr("Value");
    else
        return QObject::tr("Appl ") + QString::number(section - 3);

    return QVariant();
}


QModelIndex MvQBufrBitmapDumpModel::index(int row, int column, const QModelIndex& /*parent*/) const
{
    return createIndex(row, column, row);
}

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