/***************************** 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 <QMimeData>

#include "MvQKeyModel.h"
#include "MvQPixmapCache.h"

#include "MvQKeyMimeData.h"
#include "MvKeyProfile.h"


MvQKeyModel::MvQKeyModel(MvKeyProfile* profile, DisplayMode mode, QObject* parent) :
    QAbstractItemModel(parent),
    profile_(profile),
    mode_(mode)
{
}

MvQKeyModel::MvQKeyModel(DisplayMode mode, QObject* parent) :
    QAbstractItemModel(parent),
    mode_(mode)
{
}

void MvQKeyModel::profileIsAboutToChange()
{
    beginResetModel();
}

void MvQKeyModel::setKeyProfile(MvKeyProfile* profile)
{
    profile_ = profile;

    endResetModel();
}

int MvQKeyModel::columnCount(const QModelIndex& parent) const
{
    switch (mode_) {
        case ProfileContentsMode:
            return 3;
        case AllKeysMode:
            return 2;
        case ShortNameMode:
            return parent.isValid() ? 0 : 1;
        default:
            return 0;
    }
}

int MvQKeyModel::rowCount(const QModelIndex& index) const
{
    if (!index.isValid() && profile_ != nullptr) {
        return profile_->size();
    }
    else {
        return 0;
    }
}

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

    if (mode_ == ProfileContentsMode || mode_ == ShortNameMode) {
        if (index.column() == 0 || !editable_) {
            defaultFlags = Qt::ItemIsEnabled |
                           Qt::ItemIsSelectable;
        }
        else {
            defaultFlags = Qt::ItemIsEnabled |
                           Qt::ItemIsSelectable |
                           Qt::ItemIsEditable;
        }


        if (index.isValid())
            return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
        else
            return Qt::ItemIsDropEnabled | defaultFlags;
    }

    else if (mode_ == AllKeysMode) {
        defaultFlags = Qt::ItemIsEnabled |
                       Qt::ItemIsSelectable;

        return Qt::ItemIsDragEnabled | defaultFlags;
    }

    return defaultFlags;
}

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

    if (role == Qt::DisplayRole || role == Qt::ToolTipRole) {
        MvKey* key = profile_->at(index.row());
        return label(key, index.row(), index.column(), role);
    }
    else if (role == Qt::DecorationRole && index.column() == 0 && pixmaps_) {
        MvKey* key = profile_->at(index.row());
        QString name = QString::fromStdString(key->name());
        return pixmaps_->pixmap(name).toImage().scaled(QSize(24, 24), Qt::KeepAspectRatio, Qt::SmoothTransformation);
    }

    return {};
}

bool MvQKeyModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
    if (!editable_)
        return false;

    if (!index.isValid() || role != Qt::EditRole)
        return false;

    if (mode_ != ProfileContentsMode)
        return false;

    if (index.column() == 1) {
        MvKey* key = profile_->at(index.row());
        QString s = value.toString();
        if (s.isEmpty() == false) {
            key->setName(s.toStdString());
            emit dataChanged(index, index);
            return true;
        }
    }
    else if (index.column() == 2) {
        MvKey* key = profile_->at(index.row());
        QString s = value.toString();
        if (s.isEmpty() == false) {
            key->setShortName(s.toStdString());
            emit dataChanged(index, index);
            return true;
        }
    }

    return false;
}
QVariant MvQKeyModel::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);

    if (mode_ == ProfileContentsMode) {
        switch (section) {
            case 0:
                return tr("Index");
            case 1:
                return tr("Key name");
            case 2:
                return tr("Header name");
            default:
                return {};
        }
    }
    else if (mode_ == AllKeysMode) {
        switch (section) {
            case 0:
                return tr("Key name");
            case 1:
                return tr("Description");
            default:
                return {};
        }
    }

    return {};
}

QString MvQKeyModel::label(MvKey* key, const int row, const int column, int role) const
{
    if (mode_ == ProfileContentsMode) {
        switch (column) {
            case 0:
                return QString::number(row + 1);
            case 1:
                return QString::fromStdString(key->name());
            case 2:
                return QString::fromStdString(key->shortName());
            default:
                return {};
        }
    }
    else if (mode_ == AllKeysMode) {
        switch (column) {
            case 0:
                return QString::fromStdString(key->name());
            case 1: {
                QString desc = QString::fromStdString(key->description());
                QString sec = QString::fromStdString(key->metaData("section"));
                QString s = desc;
                if (!sec.isEmpty()) {
                    QString centre = QString::fromStdString(key->metaData("centre"));
                    s += " (Section: " + sec;
                    if (!centre.isEmpty()) {
                        s += " Centre: " + centre;
                    }
                    s += ")";
                }
                return s;
            }
            default:
                return {};
        }
    }
    else if (mode_ == ShortNameMode) {
        if (column == 0) {
            if (role == Qt::ToolTipRole) {
                std::string cntStr = key->metaData("path_count");
                if (!cntStr.empty())
                    return {};
                else
                    return QString::fromStdString(key->name());
            }
            else
                return QString::fromStdString(key->shortName());
        }
        else {
            return {};
        }
    }


    return {};
}

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


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


void MvQKeyModel::moveUp(const QModelIndex& index)
{
    if (!index.isValid())
        return;

    beginResetModel();
    moveRow(index.row(), index.row() - 1);
    endResetModel();
}

void MvQKeyModel::moveDown(const QModelIndex& index)
{
    if (!index.isValid())
        return;

    beginResetModel();
    moveRow(index.row(), index.row() + 1);
    endResetModel();
}

void MvQKeyModel::moveRow(int sourceRow, int targetRow)
{
    if (sourceRow < 0 || sourceRow >= static_cast<int>(profile_->size()) ||
        targetRow < 0 || targetRow >= static_cast<int>(profile_->size()) ||
        sourceRow == targetRow) {
        return;
    }

    profile_->reposition(sourceRow, targetRow);
}


Qt::DropActions MvQKeyModel::supportedDropActions() const
{
    /*if(!editable_)
        return Qt::IgnoreAction;
    else
        return Qt::CopyAction;*/

    return Qt::CopyAction;
}

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

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

    QList<int> procRows;

    foreach (QModelIndex index, indexes) {
        if (index.isValid() &&
            procRows.indexOf(index.row()) == -1) {
            MvKey* key = profile_->at(index.row());
            mimeData->addKey(key, index.row());
            procRows << index.row();
        }
    }

    return mimeData;
}

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

    if (!profile_)
        return false;

    if (action == Qt::IgnoreAction)
        return true;

    if (!data->hasFormat("metview/mvkey"))
        return false;

    const auto* keyData = qobject_cast<const MvQKeyMimeData*>(data);

    if (!keyData || keyData->keys().isEmpty())
        return false;

    // Dnd from self --> move rows
    if (keyData->model() == this) {
        int targetRow = row;
        if (row != -1)
            targetRow = row;
        else if (parent.isValid())
            targetRow = parent.row();
        else
            targetRow = rowCount(QModelIndex()) - 1;

        beginResetModel();

        QMapIterator<int, MvKey*> it(keyData->keys());
        while (it.hasNext()) {
            it.next();
            int sourceRow = it.key();
            moveRow(sourceRow, targetRow);
            break;
        }

        endResetModel();
    }
    // Dnd from another model --> insert new row
    else {
        beginResetModel();
        QMapIterator<int, MvKey*> it(keyData->keys());
        while (it.hasNext()) {
            it.next();
            MvKey* key = it.value()->clone();
            profile_->addKey(key);
        }
        endResetModel();
    }

    return true;
}
