/*
 *  SPDX-FileCopyrightText: 2007-2008 Cyrille Berger <cberger@cberger.net>
 *  SPDX-FileCopyrightText: 2009 Boudewijn Rempt <boud@valdyas.org>
 *
 *  SPDX-License-Identifier: GPL-2.0-or-later
 *
 */

#include "kis_filter_selector_widget.h"

#include <QHeaderView>
#include <QTreeView>
#include <QLabel>
#include <QComboBox>
#include <QPushButton>
#include <QScrollArea>
#include <QLayout>
#include <QDialogButtonBox>
#include <QPlainTextEdit>
#include <QDomDocument>
#include <QDomElement>

#include "ui_wdgfilterselector.h"

#include <kis_layer.h>
#include <kis_paint_device.h>
#include <filter/kis_filter.h>
#include <kis_config_widget.h>
#include <filter/kis_filter_configuration.h>
#include "kis_default_bounds.h"
#include <KisKineticScroller.h>
#include <KisGlobalResourcesInterface.h>

// From krita/ui
#include "kis_bookmarked_configurations_editor.h"
#include "kis_bookmarked_filter_configurations_model.h"
#include "kis_filters_model.h"
#include "kis_config.h"

#include <kstandardguiitem.h>

class ThumbnailBounds : public KisDefaultBounds {
public:
    ThumbnailBounds() : KisDefaultBounds() {}
    ~ThumbnailBounds() override {}

    QRect bounds() const override
    {
        return QRect(0, 0, 100, 100);
    }
private:
    Q_DISABLE_COPY(ThumbnailBounds)
};


struct KisFilterSelectorWidget::Private {
    QWidget *currentCentralWidget {0};
    KisConfigWidget *currentFilterConfigurationWidget {0};
    KisFilterSP currentFilter;
    KisPaintDeviceSP paintDevice;
    Ui_FilterSelector uiFilterSelector;
    KisPaintDeviceSP thumb;
    KisBookmarkedFilterConfigurationsModel *currentBookmarkedFilterConfigurationsModel {0};
    KisFiltersModel *filtersModel {};
    QGridLayout *widgetLayout {};
    KisViewManager *view{};
    bool showFilterGallery {true};
    bool usedForMask {false};
};

KisFilterSelectorWidget::KisFilterSelectorWidget(QWidget* parent)
    : d(new Private)
{
    Q_UNUSED(parent);
    setObjectName("KisFilterSelectorWidget");
    d->uiFilterSelector.setupUi(this);

    d->widgetLayout = new QGridLayout(d->uiFilterSelector.centralWidgetHolder);
    d->widgetLayout->setContentsMargins(0,0,0,0);
    d->widgetLayout->setHorizontalSpacing(0);

    showFilterGallery(false);

    connect(d->uiFilterSelector.filtersSelector, SIGNAL(clicked(QModelIndex)), SLOT(setFilterIndex(QModelIndex)));
    connect(d->uiFilterSelector.filtersSelector, SIGNAL(activated(QModelIndex)), SLOT(setFilterIndex(QModelIndex)));

    connect(d->uiFilterSelector.comboBoxPresets, SIGNAL(activated(int)),SLOT(slotBookmarkedFilterConfigurationSelected(int)));
    connect(d->uiFilterSelector.pushButtonEditPresets, SIGNAL(pressed()), SLOT(editConfigurations()));
    connect(d->uiFilterSelector.btnXML, SIGNAL(clicked()), this, SLOT(showXMLdialog()));

    KisConfig cfg(true);
    d->uiFilterSelector.chkRememberPreset->setChecked(cfg.readEntry<bool>("filterdialog/rememberlastpreset", false));

}

KisFilterSelectorWidget::~KisFilterSelectorWidget()
{
    KisConfig cfg(false);
    cfg.writeEntry<bool>("filterdialog/rememberlastpreset", d->uiFilterSelector.chkRememberPreset->isChecked());
    delete d->filtersModel;
    delete d->currentBookmarkedFilterConfigurationsModel;
    delete d->currentCentralWidget;
    delete d->widgetLayout;
    delete d;
}

void KisFilterSelectorWidget::setView(KisViewManager *view)
{
    d->view = view;
}

void KisFilterSelectorWidget::setPaintDevice(bool showAll, KisPaintDeviceSP _paintDevice)
{
    if (!_paintDevice) return;

    if (d->filtersModel) delete d->filtersModel;

    d->usedForMask = !showAll;
    d->paintDevice = _paintDevice;
    d->thumb = d->paintDevice->createThumbnailDevice(100, 100);
    d->thumb->setDefaultBounds(new ThumbnailBounds());
    d->filtersModel = new KisFiltersModel(showAll, d->thumb);

    d->uiFilterSelector.filtersSelector->setFilterModel(d->filtersModel);
    d->uiFilterSelector.filtersSelector->header()->setVisible(false);

    KisConfig cfg(true);
    QModelIndex idx = d->filtersModel->indexForFilter(cfg.readEntry<QString>("FilterSelector/LastUsedFilter", "levels"));

    if (!idx.isValid()) {
        idx = d->filtersModel->indexForFilter("levels");
    }

    if (d->usedForMask && isFilterGalleryVisible()) {
        d->uiFilterSelector.filtersSelector->activateFilter(idx);
    }

}

void KisFilterSelectorWidget::showFilterGallery(bool visible)
{
    if (d->showFilterGallery == visible) {
        return;
    }

    d->showFilterGallery = visible;
    update();
    emit sigFilterGalleryToggled(visible);
    emit sigSizeChanged();
}

void KisFilterSelectorWidget::showXMLdialog()
{
    if (currentFilter()->showConfigurationWidget()) {
        QDialog *xmlDialog = new QDialog(qApp->activeWindow());
        xmlDialog->setMinimumWidth(500);
        xmlDialog->setWindowTitle(i18n("Filter configuration XML"));
        QVBoxLayout *xmllayout = new QVBoxLayout(xmlDialog);
        QPlainTextEdit *text = new QPlainTextEdit(xmlDialog);
        KisFilterConfigurationSP config = configuration();
        text->setPlainText(config->toXML());
        xmllayout->addWidget(text);
        QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel, xmlDialog);
        KGuiItem::assign(buttons->button(QDialogButtonBox::Ok), KStandardGuiItem::ok());
        KGuiItem::assign(buttons->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel());
        connect(buttons, SIGNAL(accepted()), xmlDialog, SLOT(accept()));
        connect(buttons, SIGNAL(rejected()), xmlDialog, SLOT(reject()));
        xmllayout->addWidget(buttons);
        if (xmlDialog->exec()==QDialog::Accepted) {
            QDomDocument doc;
            doc.setContent(text->toPlainText());
            config->fromXML(doc.documentElement());
            if (config) {
                d->currentFilterConfigurationWidget->setConfiguration(config);
            }
        }
    }
}

bool KisFilterSelectorWidget::isFilterGalleryVisible() const
{
    return d->showFilterGallery;
}

KisFilterSP KisFilterSelectorWidget::currentFilter() const
{
    return d->currentFilter;
}

void KisFilterSelectorWidget::setFilter(KisFilterSP f, KisFilterConfigurationSP overrideDefaultConfig)
{
    Q_ASSERT(f);
    Q_ASSERT(d->filtersModel);
    setWindowTitle(f->name());
    dbgKrita << "setFilter: " << f;
    d->currentFilter = f;
    delete d->currentCentralWidget;

    {
        bool v = d->uiFilterSelector.filtersSelector->blockSignals(true);
        d->uiFilterSelector.filtersSelector->setCurrentIndex(d->filtersModel->indexForFilter(f->id()));
        d->uiFilterSelector.filtersSelector->blockSignals(v);
    }

    KisConfigWidget* widget =
            d->currentFilter->createConfigurationWidget(d->uiFilterSelector.centralWidgetHolder, d->paintDevice, d->usedForMask);

    if (!widget) { // No widget, so display a label instead
        d->uiFilterSelector.comboBoxPresets->setEnabled(false);
        d->uiFilterSelector.pushButtonEditPresets->setEnabled(false);
        d->uiFilterSelector.btnXML->setEnabled(false);

        d->currentFilterConfigurationWidget = 0;
        d->currentCentralWidget = new QLabel(i18n("No configuration options"),
                                             d->uiFilterSelector.centralWidgetHolder);
        d->uiFilterSelector.scrollArea->setMinimumSize(d->currentCentralWidget->sizeHint());
        qobject_cast<QLabel*>(d->currentCentralWidget)->setAlignment(Qt::AlignCenter);
    } else {
        KisFilterConfigurationSP defaultConfiguration =
            overrideDefaultConfig ?
            overrideDefaultConfig :
            d->currentFilter->defaultConfiguration(KisGlobalResourcesInterface::instance());

        d->uiFilterSelector.comboBoxPresets->setEnabled(true);
        d->uiFilterSelector.pushButtonEditPresets->setEnabled(true);
        d->uiFilterSelector.btnXML->setEnabled(true);

        d->currentFilterConfigurationWidget = widget;
        d->currentCentralWidget = widget;
        widget->layout()->setContentsMargins(0,0,0,0);
        d->currentFilterConfigurationWidget->setView(d->view);
        d->currentFilterConfigurationWidget->blockSignals(true);
        d->currentFilterConfigurationWidget->setConfiguration(defaultConfiguration);
        d->currentFilterConfigurationWidget->blockSignals(false);
        d->uiFilterSelector.scrollArea->setContentsMargins(0,0,0,0);
        d->uiFilterSelector.scrollArea->setMinimumWidth(widget->sizeHint().width() + 18);
        connect(d->currentFilterConfigurationWidget, SIGNAL(sigConfigurationUpdated()), this, SIGNAL(configurationChanged()));
    }

    // Change the list of presets
    delete d->currentBookmarkedFilterConfigurationsModel;
    d->currentBookmarkedFilterConfigurationsModel = new KisBookmarkedFilterConfigurationsModel(d->thumb, f);
    d->uiFilterSelector.comboBoxPresets->setModel(d->currentBookmarkedFilterConfigurationsModel);

    // Add the widget to the layout
    d->currentCentralWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
    d->widgetLayout->addWidget(d->currentCentralWidget, 0 , 0);

    if (d->uiFilterSelector.chkRememberPreset->isChecked()) {
        int lastBookmarkedFilterConfiguration = KisConfig(true).readEntry<int>("lastBookmarkedFilterConfiguration/" + f->id(), 0);
        if (d->uiFilterSelector.comboBoxPresets->count() > lastBookmarkedFilterConfiguration) {
            d->uiFilterSelector.comboBoxPresets->setCurrentIndex(lastBookmarkedFilterConfiguration);
            slotBookmarkedFilterConfigurationSelected(lastBookmarkedFilterConfiguration);
        }
    }

    update();
}

void KisFilterSelectorWidget::setFilterIndex(const QModelIndex& idx)
{
    if (!idx.isValid()) return;

    Q_ASSERT(d->filtersModel);
    KisFilter* filter = const_cast<KisFilter*>(d->filtersModel->indexToFilter(idx));
    if (filter) {
        setFilter(filter, 0);
    }
    else {
        if (d->currentFilter) {
            bool v = d->uiFilterSelector.filtersSelector->blockSignals(true);
            QModelIndex idx = d->filtersModel->indexForFilter(d->currentFilter->id());
            d->uiFilterSelector.filtersSelector->setCurrentIndex(idx);
            d->uiFilterSelector.filtersSelector->scrollTo(idx);
            d->uiFilterSelector.filtersSelector->blockSignals(v);
        }
    }

    slotBookMarkCurrentFilter();
    emit(configurationChanged());
}

void KisFilterSelectorWidget::slotBookMarkCurrentFilter() {
    KisConfig cfg(false);
    cfg.writeEntry<QString>("FilterSelector/LastUsedFilter", d->currentFilter->id());
}

void KisFilterSelectorWidget::slotBookmarkedFilterConfigurationSelected(int index)
{
    if (d->currentFilterConfigurationWidget) {
        QModelIndex modelIndex = d->currentBookmarkedFilterConfigurationsModel->index(index, 0);
        KisFilterConfigurationSP config  = d->currentBookmarkedFilterConfigurationsModel->configuration(modelIndex);
        d->currentFilterConfigurationWidget->setConfiguration(config);
        if (d->currentFilter && index != KisConfig(true).readEntry<int>("lastBookmarkedFilterConfiguration/" + d->currentFilter->id(), 0)) {
            KisConfig(false).writeEntry<int>("lastBookmarkedFilterConfiguration/" + d->currentFilter->id(), index);
        }
    }
}

void KisFilterSelectorWidget::editConfigurations()
{
    KisSerializableConfigurationSP config =
            d->currentFilterConfigurationWidget ? d->currentFilterConfigurationWidget->configuration() : 0;
    KisBookmarkedConfigurationsEditor editor(this, d->currentBookmarkedFilterConfigurationsModel, config);
    editor.exec();
}

void KisFilterSelectorWidget::update()
{
    d->uiFilterSelector.filtersSelector->setVisible(d->showFilterGallery);
    if (d->showFilterGallery) {
        setMinimumWidth(qMax(sizeHint().width(), 700));
        d->uiFilterSelector.scrollArea->setMinimumHeight(400);
        setMinimumHeight(d->uiFilterSelector.verticalLayout->sizeHint().height());
        if (d->currentFilter) {
            bool v = d->uiFilterSelector.filtersSelector->blockSignals(true);
            d->uiFilterSelector.filtersSelector->setCurrentIndex(d->filtersModel->indexForFilter(d->currentFilter->id()));
            d->uiFilterSelector.filtersSelector->blockSignals(v);
        }
    }
    else {
        if (d->currentCentralWidget) {
            d->uiFilterSelector.scrollArea->setMinimumHeight(qMin(400, d->currentCentralWidget->sizeHint().height()));
        }
        setMinimumSize(d->uiFilterSelector.verticalLayout->sizeHint());
    }
}

KisFilterConfigurationSP KisFilterSelectorWidget::configuration()
{
    if (d->currentFilterConfigurationWidget) {
        KisFilterConfigurationSP config = dynamic_cast<KisFilterConfiguration*>(d->currentFilterConfigurationWidget->configuration().data());
        if (config) {
            return config;
        }
    } else if (d->currentFilter) {
        return d->currentFilter->defaultConfiguration(KisGlobalResourcesInterface::instance());
    }
    return 0;

}

void KisFilterTree::setFilterModel(QAbstractItemModel *model)
{
    m_model = model;

}

void KisFilterTree::activateFilter(QModelIndex idx)
{
    setModel(m_model);
    selectionModel()->select(idx, QItemSelectionModel::SelectCurrent);
    expand(idx);
    scrollTo(idx);
    emit activated(idx);
}

void KisFilterSelectorWidget::setVisible(bool visible)
{
    QWidget::setVisible(visible);
    if (visible) {
        update();
    }
}

