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

 Copyright 2018 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 "MvQEcLayerHelp.h"

#include <QDebug>
#include <QtGlobal>
#include <QApplication>
#include <QComboBox>
#include <QCompleter>
#include <QGridLayout>
#include <QLabel>
#include <QLineEdit>
#include <QPainter>
#include <QSortFilterProxyModel>
#include <QToolButton>
#include <QTreeView>
#include <QVBoxLayout>

#include "MvQEcLayerDb.h"
#include "MvQEcLayerLine.h"
#include "MvQEcLayerTreeWidget.h"

#include "MvMiscellaneous.h"

#include "HelpFactory.h"

//=====================================================
//
//  MvQEcLayerModel
//
//=====================================================

MvQEcLayerModel::MvQEcLayerModel(QObject* parent) :
    QAbstractItemModel(parent)
{
}

MvQEcLayerModel::~MvQEcLayerModel() = default;

int MvQEcLayerModel::columnCount(const QModelIndex& /*parent */) const
{
    return 2;
}

int MvQEcLayerModel::rowCount(const QModelIndex& parent) const
{
    // Parent is the root:
    if (!parent.isValid()) {
        return MvQEcLayerDb::instance()->items().count();
    }

    return 0;
}

QVariant MvQEcLayerModel::data(const QModelIndex& index, int role) const
{
    int row = index.row();
    if (row < 0 || row >= MvQEcLayerDb::instance()->items().count())
        return {};

    if (role == Qt::DisplayRole) {
        if (index.column() == 0) {
            //            return  MvQEcLayerDb::instance()->items()[row]->name();
            return QString();
        }
        else if (index.column() == 1) {
            return MvQEcLayerDb::instance()->items()[row]->title();
        }
    }
    else if (role == Qt::UserRole) {
        if (index.column() == 0) {
            return row;
        }
    }
    //    else if (role == NameRole) {
    //        if (index.column() == 0) {
    //            return  MvQEcLayerDb::instance()->items()[row]->name();
    //        }
    //    }
    else if (role == Qt::ForegroundRole) {
        if (index.column() == 0) {
            return QColor(Qt::transparent);
        }
    }
    else if (role == FilterRole) {
        return (isFiltered(MvQEcLayerDb::instance()->items()[row]) == true) ? "1" : "0";
    }
    else if (role == SortRole) {
        if (index.column() == 0) {
            return MvQEcLayerDb::instance()->items()[row]->name();
        }
        else if (index.column() == 1) {
            return MvQEcLayerDb::instance()->items()[row]->title();
        }
    }

    return {};
}

QVariant MvQEcLayerModel::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 (role == Qt::DisplayRole) {
        if (section == 0) {
            return "Name";
        }
        else if (section == 1) {
            return "Title";
        }
    }
    return {};
}

QModelIndex MvQEcLayerModel::index(int row, int column, const QModelIndex& parent) const
{
    if (row < 0 || column < 0) {
        return {};
    }

    // When parent is the root this index refers to a node or server
    if (!parent.isValid()) {
        return createIndex(row, column);
    }

    return {};
}

QModelIndex MvQEcLayerModel::parent(const QModelIndex& /*child*/) const
{
    return {};
}

void MvQEcLayerModel::setFilter(QString s)
{
    filter_ = s;
}

void MvQEcLayerModel::clearFilter()
{
    filter_.clear();
}

bool MvQEcLayerModel::isFiltered(MvQEcLayerDbItem* item) const
{
    if (!filter_.isEmpty()) {
        if (item->name().contains(filter_, Qt::CaseInsensitive))
            return true;

        if (item->title().contains(filter_, Qt::CaseInsensitive))
            return true;

        if (item->keywordMatch(filter_, Qt::CaseInsensitive))
            return true;

        if (item->group().contains(filter_, Qt::CaseInsensitive))
            return true;

        return false;
    }

    return true;
}

//=====================================================
//
// MvQEcLayerSelectionWidget
//
//=====================================================

MvQEcLayerSelectionWidget::MvQEcLayerSelectionWidget(QWidget* parent) :
    QWidget(parent),
    ignoreFilterChanged_(false)
{
    auto* vb = new QVBoxLayout(this);

    nameLe_ = new QLineEdit(this);
    nameLe_->setPlaceholderText("Filter");
#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
    nameLe_->setClearButtonEnabled(true);
#endif

    QStringList allNames = MvQEcLayerDb::instance()->names();
    allNames << MvQEcLayerDb::instance()->titleWords() << MvQEcLayerDb::instance()->keywords() << MvQEcLayerDb::instance()->groups();

    auto* nameCompleter = new QCompleter(allNames, this);
    nameCompleter->setCaseSensitivity(Qt::CaseInsensitive);
#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
    nameCompleter->setFilterMode(Qt::MatchContains);
#endif
    nameLe_->setCompleter(nameCompleter);

    vb->addWidget(nameLe_);

    // tree view and model

    browser_ = new MvQEcLayerTreeWidget(this);
    vb->addWidget(browser_, 1);

    model_ = new MvQEcLayerModel(this);
    sortModel_ = new QSortFilterProxyModel(this);
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
    sortModel_->setFilterRegularExpression("1");
#else
    sortModel_->setFilterRegExp("1");
#endif

    sortModel_->setFilterRole(MvQEcLayerModel::FilterRole);
    sortModel_->setSortRole(MvQEcLayerModel::SortRole);
    sortModel_->setSourceModel(model_);

    browser_->tree()->setModel(sortModel_);
    browser_->tree()->resizeColumnToContents(0);

    connect(nameLe_, SIGNAL(textChanged(QString)),
            this, SLOT(slotNameFilter(QString)));

    connect(browser_->tree()->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)),
            this, SLOT(slotItemSelected(QModelIndex, QModelIndex)));
}

void MvQEcLayerSelectionWidget::slotNameFilter(QString s)
{
    if (ignoreFilterChanged_)
        return;

    if (s == "Filter")
        s.clear();
    model_->setFilter(s);
    sortModel_->invalidate();
}

void MvQEcLayerSelectionWidget::slotClearFilter()
{
    ignoreFilterChanged_ = true;
    nameLe_->clear();
    ignoreFilterChanged_ = false;

    model_->clearFilter();
    sortModel_->invalidate();
}

void MvQEcLayerSelectionWidget::slotItemSelected(const QModelIndex& current, const QModelIndex& /*previous*/)
{
    QModelIndex idxSrc = sortModel_->mapToSource(current);
    if (idxSrc.isValid()) {
        int row = idxSrc.row();
        emit itemSelected(row);

        if (row >= 0 && row < MvQEcLayerDb::instance()->items().count()) {
            MvQEcLayerDbItem* item = MvQEcLayerDb::instance()->items()[row];
            Q_ASSERT(item);
            browser_->setLayer(item);
        }
    }
}


void MvQEcLayerSelectionWidget::setCurrent(const std::string& name)
{
    QModelIndex idxSrc = sortModel_->mapToSource(browser_->tree()->currentIndex());
    if (idxSrc.isValid()) {
        int row = idxSrc.row();
        if (row >= 0 && row < MvQEcLayerDb::instance()->items().size() &&
            MvQEcLayerDb::instance()->items()[row]->name().toStdString() == name)
            return;
    }

    slotClearFilter();
    int row = MvQEcLayerDb::instance()->indexOf(name);
    if (row >= 0) {
        QModelIndex idxSrc = model_->index(row, 0);
        if (idxSrc.isValid()) {
            browser_->tree()->setCurrentIndex(sortModel_->mapFromSource(idxSrc));

            int row = idxSrc.row();
            emit itemSelected(row);

            if (row >= 0 && row < MvQEcLayerDb::instance()->items().count()) {
                MvQEcLayerDbItem* item = MvQEcLayerDb::instance()->items()[row];
                Q_ASSERT(item);
                browser_->setLayer(item);
            }
        }
    }
}

//==================================================
//
//  MvQEcLayerHelp
//
//==================================================

MvQEcLayerHelp::MvQEcLayerHelp(RequestPanel& owner, const MvIconParameter& param) :
    MvQRequestPanelHelp(owner, param)
{
    selector_ = new MvQEcLayerSelectionWidget(parentWidget_);

    connect(selector_, SIGNAL(itemSelected(int)),
            this, SLOT(slotSelected(int)));
}

void MvQEcLayerHelp::slotSelected(int idx)
{
    if (idx >= 0 && idx < MvQEcLayerDb::instance()->items().count()) {
        if (MvQEcLayerDb::instance()->items()[idx]->name() != oriName_) {
            std::vector<std::string> vs;
            vs.push_back(std::to_string(idx));
            emit edited(vs);
            oriName_.clear();
        }
    }
}

void MvQEcLayerHelp::refresh(const std::vector<std::string>& values)
{
    if (values.size() == 0)
        return;

    oriName_ = QString::fromStdString(values[0]);
    selector_->setCurrent(values[0]);
}

static HelpMaker<MvQEcLayerHelp> maker2("help_eclayer");
