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

 Copyright 2017 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 "BufrCompDataWidget.h"
#include "BufrMetaData.h"
#include "MvKeyProfile.h"

#include "MvQKeyProfileModel.h"
#include "MvQKeyProfileTree.h"

#include <QtGlobal>

BufrDataKeyFilterModel::BufrDataKeyFilterModel(QObject* parent) :
    QSortFilterProxyModel(parent)
{
}

bool BufrDataKeyFilterModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
{
    if (filterStr_.isEmpty() || filterStr_[0].simplified().isEmpty())
        return true;

    if (source_parent.isValid())
        return true;

    if (source_row == 0)  //the subset index is always visible
        return true;

    QModelIndex idx = sourceModel()->index(source_row, 0, source_parent);
    QString s       = sourceModel()->data(idx).toString();
    if (!s.isEmpty()) {
        foreach (QString str, filterStr_) {
            if (s.contains(str, Qt::CaseInsensitive))
                return true;
        }
    }

    return false;
}

void BufrDataKeyFilterModel::setFilter(QStringList lst)
{
    filterStr_ = lst;
    invalidate();
}


BufrDataKeyModel::BufrDataKeyModel(QObject* parent) :
    QAbstractItemModel(parent),
    prof_(0)
{
}

BufrDataKeyModel::~BufrDataKeyModel()
{
    if (prof_)
        delete prof_;
}

void BufrDataKeyModel::clear()
{
    beginResetModel();
    if (prof_)
        delete prof_;

    prof_ = 0;
    endResetModel();
}

void BufrDataKeyModel::setKeyProfile(MvKeyProfile* prof)
{
    beginResetModel();

    if (prof_ != prof) {
        if (prof_)
            delete prof_;
    }

    prof_ = prof;
    endResetModel();
}

int BufrDataKeyModel::rowCount(const QModelIndex& parent) const
{
    if (!parent.isValid())
        if (prof_)
            return prof_->size();

    return 0;
}

int BufrDataKeyModel::columnCount(const QModelIndex& parent) const
{
    return 1;
}

QVariant BufrDataKeyModel::data(const QModelIndex& index, int role) const
{
    if (!index.isValid() || !prof_ || index.row() >= static_cast<int>(prof_->size()))
        return QVariant();

    if (role == Qt::DisplayRole) {
        return QString::fromStdString(prof_->at(index.row())->name());
    }
    else if (role == Qt::CheckStateRole) {
        return (prof_->at(index.row())->metaData("f") == "1") ? QVariant(Qt::Checked) : QVariant(Qt::Unchecked);
    }

    return QVariant();
}

bool BufrDataKeyModel::setData(const QModelIndex& idx, const QVariant& value, int role)
{
    if (!prof_ || idx.row() >= static_cast<int>(prof_->size()))
        return false;

    if (role == Qt::CheckStateRole) {
        MvKey* key = prof_->at(idx.row());
        Q_ASSERT(key);

        bool checked = (value.toInt() == Qt::Checked) ? true : false;
        key->setMetaData("f", (checked) ? "1" : "0");
        QModelIndex startIdx = index(idx.row(), 0);
        Q_EMIT dataChanged(startIdx, startIdx);
        Q_EMIT filterChanged();
    }

    return false;
}


QVariant BufrDataKeyModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    return QVariant();
}

QModelIndex BufrDataKeyModel::index(int row, int column, const QModelIndex& parent) const
{
    return createIndex(row, column, static_cast<void*>(0));
}

QModelIndex BufrDataKeyModel::parent(const QModelIndex& index) const
{
    return QModelIndex();
}

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

    if (index.row() > 0)
        return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;

    return defaultFlags;
}

void BufrDataKeyModel::selectAll(QString filter)
{
    if (!prof_)
        return;

    if (filter.isEmpty()) {
        for (size_t i = 0; i < prof_->size(); i++)
            prof_->at(i)->setMetaData("f", "1");
    }
    else {
        QStringList lst = filter.split(" ");

        if (prof_->size() > 0)
            prof_->at(0)->setMetaData("f", "1");

        for (size_t i = 1; i < prof_->size(); i++) {
            prof_->at(i)->setMetaData("f", "0");
            QString name = QString::fromStdString(prof_->at(i)->name());
            if (!name.isEmpty()) {
                foreach (QString str, lst) {
                    if (name.contains(str, Qt::CaseInsensitive)) {
                        prof_->at(i)->setMetaData("f", "1");
                        break;
                    }
                }
            }
        }
    }

    Q_EMIT dataChanged(index(0, 0), index(prof_->size() - 1, 0));
    Q_EMIT filterChanged();
}

void BufrDataKeyModel::unselectAll()
{
    if (!prof_)
        return;

    for (size_t i = 1; i < prof_->size(); i++)
        prof_->at(i)->setMetaData("f", "0");

    if (prof_->size() > 0)
        prof_->at(0)->setMetaData("f", "1");

    Q_EMIT dataChanged(index(0, 0), index(prof_->size() - 1, 0));
    Q_EMIT filterChanged();
}

QList<int> BufrDataKeyModel::filtered() const
{
    QList<int> lst;
    for (size_t i = 0; i < prof_->size(); i++)
        if (prof_->at(i)->metaData("f") == "1")
            lst << i;

    return lst;
}

BufrCompDataWidget::BufrCompDataWidget(QWidget* parent) :
    QWidget(parent),
    data_(0)
{
    setupUi(this);

#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
    columnLe_->setClearButtonEnabled(true);
#endif

    //header
    header_->setProperty("panelStyle", "2");
    filterPanelTb_->setProperty("headerStyle", "1");

    model_ = new MvQKeyProfileModel(this);
    model_->setShadeFirstColumn(true);

    sortModel_ = new MvQKeyProfileSortFilterModel(this);
    sortModel_->setSourceModel(model_);
    sortModel_->setDynamicSortFilter(true);
    sortModel_->setFilterRole(Qt::UserRole);
    sortModel_->setFilterFixedString("1");
    sortModel_->setFilterKeyColumn(0);

    tree_->setModels(model_, sortModel_);
    tree_->setUniformRowHeights(true);
    tree_->setProperty("mvStyle", 11);
    tree_->setAlternatingRowColors(false);

    filterPanel_->setProperty("panelStyle", "2");
    filterLabel_->setProperty("panelStyle", "2");

    colModel_       = new BufrDataKeyModel(this);
    colFilterModel_ = new BufrDataKeyFilterModel(this);
    colFilterModel_->setSourceModel(colModel_);
    colList_->setModel(colFilterModel_);

    splitter_->setCollapsible(1, false);
    splitter_->setStretchFactor(0, 6);
    splitter_->setStretchFactor(1, 1);

    connect(colModel_, SIGNAL(filterChanged()),
            this, SLOT(slotFilterChanged()));
}

void BufrCompDataWidget::init(BufrMetaData* data)
{
    Q_ASSERT(data_ == 0);
    data_ = data;
    Q_ASSERT(data_);
}

void BufrCompDataWidget::clearData()
{
    model_->clear();
    colModel_->clear();
    columnLe_->clear();
}

void BufrCompDataWidget::loadData(int msgNum, int subsetNum)
{
    Q_ASSERT(data_);
    MvKeyProfile* prof = new MvKeyProfile("comp");
    data_->readCompressedData(prof, msgNum, subsetNum);

    //The model will take ownership of the profile
    model_->setKeyProfile(prof);

    //This model will take ownership of its profile
    colModel_->setKeyProfile(prof->clone());
    colModel_->selectAll(QString());
}

#if 0
void BufrCompDataWidget::on_columnTe__textChanged(QString s)
{
    QStringList lst=s.split(" ");
    sortModel_->setColumnFilter(lst);
}
#endif


void BufrCompDataWidget::on_columnLe__textChanged(QString s)
{
    QStringList lst = s.split(" ");
    colFilterModel_->setFilter(lst);
}

void BufrCompDataWidget::on_selectAllTb__clicked(bool)
{
    colModel_->selectAll(columnLe_->text());
}

void BufrCompDataWidget::on_unselectAllTb__clicked(bool)
{
    colModel_->unselectAll();
}

void BufrCompDataWidget::on_filterPanelTb__toggled(bool b)
{
    filterPanel_->setVisible(b);
}

void BufrCompDataWidget::slotFilterChanged()
{
    sortModel_->setColumnFilter(colModel_->filtered());
    int n = sortModel_->columnCount() - 1;
    for (int i = 0; i < n; i++)
        tree_->resizeColumnToContents(i);
}
