/***************************** 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 <QColor>
#include <QDebug>
#include <QBrush>

#include "MvQCheckBoxCombo.h"
#include "MvQKeyFilterModel.h"
#include "MvKeyProfile.h"


MvQKeyFilterDelegate::MvQKeyFilterDelegate(QWidget* parent) :
    QStyledItemDelegate(parent)
{
}

void MvQKeyFilterDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option,
                                 const QModelIndex& index) const
{
    QStyledItemDelegate::paint(painter, option, index);
}


QWidget* MvQKeyFilterDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option,
                                            const QModelIndex& index) const
{
    if (index.column() == 2) {
        MvQCheckBoxCombo* combo = new MvQCheckBoxCombo(parent);

        // connect(combo,SIGNAL(toggled(bool)),this,SLOT(setFilter(bool)));
        // connect(bAdvd_,SIGNAL(toggled(bool)), wt, SLOT(setVisible(bool)));
        // connect(bAdvd_,SIGNAL(clicked(bool)), this, SLOT(slotAdvancedButton(bool)));

        connect(combo, SIGNAL(editingFinished()),
                this, SLOT(commmitAndCloseEditor()));

        return combo;
    }
    else {
        return QStyledItemDelegate::createEditor(parent, option, index);
    }
}

void MvQKeyFilterDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
{
    if (index.column() == 2) {
        MvQCheckBoxCombo* combo = static_cast<MvQCheckBoxCombo*>(editor);

        // Get current value from model
        QStringList values = index.data(Qt::UserRole).toStringList();
        QStringList filters = index.data(Qt::DisplayRole).toString().split("/", QString::SkipEmptyParts);

        if (filters.contains(tr("Any"))) {
            foreach (QString item, values) {
                combo->addItem(item, true);
            }
        }
        else {
            foreach (QString item, values) {
                if (filters.contains(item)) {
                    combo->addItem(item, true);
                }
                else {
                    combo->addItem(item, false);
                }
            }
        }
    }
    else {
        QStyledItemDelegate::setEditorData(editor, index);
    }
}

void MvQKeyFilterDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index)
{
    editor->setGeometry(option.rect);
}


void MvQKeyFilterDelegate::commmitAndCloseEditor()
{
    MvQCheckBoxCombo* combo = static_cast<MvQCheckBoxCombo*>(sender());
    emit commitData(combo);
    emit closeEditor(combo);
}

void MvQKeyFilterDelegate::setModelData(QWidget* editor, QAbstractItemModel* model,
                                        const QModelIndex& index) const
{
    if (index.column() == 2) {
        MvQCheckBoxCombo* combo = static_cast<MvQCheckBoxCombo*>(editor);

        // Get filters
        QStringList filters = combo->getSelectedValues();
        if (filters.size() == combo->count()) {
            QString value("Any");
            model->setData(index, value, Qt::DisplayRole);
        }
        else {
            QString value;
            for (unsigned int i = 0; i < filters.size(); i++) {
                value += filters[i];
                if (i != filters.size() - 1) {
                    value += "/";
                }
            }
            model->setData(index, value, Qt::DisplayRole);
        }
    }
    else {
        QStyledItemDelegate::setModelData(editor, model, index);
    }
}


MvQKeyFilterModel::MvQKeyFilterModel()
{
    profile_ = 0;
}

bool MvQKeyFilterModel::isDataSet() const
{
    return (profile_ == 0) ? false : true;
}

void MvQKeyFilterModel::setKeyProfile(MvKeyProfile* prof)
{
    profile_ = prof;

    setupKeyFilter();

    // Reset the model (views will be notified)
    // reset();  NOT in Qt 5
    beginResetModel();
    endResetModel();
}

void MvQKeyFilterModel::setupKeyFilter()
{
    filter_.clear();

    for (unsigned int i = 0; i < profile_->size(); i++) {
        MvKey* key = profile_->at(i);
        QString keyName(key->name().c_str());

        for (map<std::string, int>::iterator it = key->counter().begin();
             it != key->counter().end(); it++) {
            filter_[keyName].push_back(QString(it->first.c_str()));
        }
    }
}


int MvQKeyFilterModel::columnCount(const QModelIndex& /* parent */) const
{
    if (!isDataSet())
        return 0;

    return 3;
}

int MvQKeyFilterModel::rowCount(const QModelIndex& parent) const
{
    if (!isDataSet())
        return 0;

    // Non-root
    if (!parent.isValid()) {
        return profile_->size();
    }
    else {
        return 0;
    }
}

Qt::ItemFlags MvQKeyFilterModel::flags(const QModelIndex& index) const
{
    if (index.column() != 2)
        return Qt::ItemIsEnabled |
               Qt::ItemIsSelectable;
    else
        return Qt::ItemIsEnabled |
               Qt::ItemIsSelectable |
               Qt::ItemIsEditable;
}

QVariant MvQKeyFilterModel::data(const QModelIndex& index, int role) const
{
    if (!index.isValid()) {
        return QVariant();
    }
    else if (role == Qt::UserRole && index.column() == 2) {
        MvKey* key = profile_->at(index.row());
        QString keyName(key->name().c_str());

        QStringList str;
        for (map<std::string, int>::iterator it = key->counter().begin();
             it != key->counter().end(); it++) {
            str.push_back(QString(it->first.c_str()));
        }
        return str;
    }
    else if (role != Qt::DisplayRole) {
        return QVariant();
    }

    return label(index.row(), index.column());
}

bool MvQKeyFilterModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
    if (!index.isValid()) {
        return false;
    }

    if (role == Qt::DisplayRole && index.column() == 2) {
        QStringList str = value.toStringList();
        QString keyName(profile_->at(index.row())->name().c_str());

        filter_[keyName] = str;

        emit dataChanged(index, index);
        emit filterUpdate(filter_);

        return true;
    }

    return false;
}


QVariant MvQKeyFilterModel::headerData(const int section, const Qt::Orientation orient, const int role) const
{
    if (!isDataSet() || orient != Qt::Horizontal ||
        (role != Qt::DisplayRole && role != Qt::ToolTipRole) ||
        section < 0 || section >= static_cast<int>(profile_->size())) {
        return QAbstractItemModel::headerData(section, orient, role);
    }

    if (section < 0 || section >= profile_->size()) {
        return QVariant();
    }

    if (role == Qt::DisplayRole) {
        switch (section) {
            case 0:
                return QString("Key name\n (Examiner)");
                break;
            case 1:
                return QString("Key name\n (ecCodes)");
                break;
            case 2:
                return QString("Filter values");
                break;
            default:
                return QVariant();
                break;
        }
    }

    return QVariant();
}

QString MvQKeyFilterModel::label(const int row, const int column) const
{
    if (!isDataSet() || row < 0 || row >= profile_->valueNum(0) || column < 0 || column >= profile_->size()) {
        return QString();
    }

    switch (column) {
        case 0:
            return QString(profile_->at(row)->shortName().c_str());
            break;
        case 1:
            return QString(profile_->at(row)->name().c_str());
            break;
        case 2: {
            QString keyName(profile_->at(row)->name().c_str());
            QStringList items = filter_[keyName];

            if (items.size() == profile_->at(row)->counter().size()) {
                return QString(tr("Any"));
            }
            else {
                QString s;
                for (unsigned int i = 0; i < static_cast<int>(items.size()); i++) {
                    s += items[i];
                    if (i != items.size() - 1) {
                        s += "/";
                    }
                }
                return s;
            }
        } break;
        default:
            return QString();
            break;
    }

    return QString();
}


QModelIndex MvQKeyFilterModel::index(int row, int column, const QModelIndex& parent) const
{
    if (!isDataSet()) {
        return QModelIndex();
    }

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


QModelIndex MvQKeyFilterModel::parent(const QModelIndex& index) const
{
    return QModelIndex();

    /*QObject* obj = mapModelIndex2QObject(index);
    QObject* parent = obj->parent();
    if ( parent == 0 )
        return QModelIndex();

    QObject* grandParent = parent->parent();
    int row = children( grandParent ).indexOf( parent );
    return createIndex( row, 0, grandParent );*/
}
