/***************************** 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 1;
}

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 QVariant();

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

    return QVariant();
}

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);

    return role == Qt::DisplayRole && section == 0 ? "Matching layers" : QVariant();
}

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

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

    return QModelIndex();
}

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

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(Qt::UserRole);
    sortModel_->setSortRole(MvQEcLayerModel::SortRole);
    sortModel_->setSourceModel(model_);

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

    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");
