/*
 * opt_theme.cpp
 * Copyright (C) 2010-2017  Sergey Ilinykh, Vitaly Tonkacheyev
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 */

#include "opt_theme.h"

#include "psicon.h"
#include "psiiconset.h"
#include "psithememanager.h"
#include "psithememodel.h"
#include "ui_opt_theme.h"

#include <QDialog>
#include <QSortFilterProxyModel>
#include <QTimer>
#include <QToolButton>

#define SCREEN_PREFIX "scb_"

class OptAppearanceThemeUI : public QWidget, public Ui::OptAppearanceTheme {
public:
    OptAppearanceThemeUI() : QWidget() { setupUi(this); }
};

OptionsTabAppearanceThemes::OptionsTabAppearanceThemes(QObject *parent) :
    MetaOptionsTab(parent, "themes", "", tr("Themes"), tr("Configure themes"))
{
}

void OptionsTabAppearanceThemes::setData(PsiCon *psi, QWidget *w)
{
    const auto &providers = psi->themeManager()->registeredProviders();
    for (PsiThemeProvider *provider : providers) {
        addTab(new OptionsTabAppearanceTheme(this, provider));
    }
    MetaOptionsTab::setData(psi, w);
}

//----------------------------------------------------------------------------
// OptionsTabAppearanceTheme
//----------------------------------------------------------------------------

OptionsTabAppearanceTheme::OptionsTabAppearanceTheme(QObject *parent, PsiThemeProvider *provider_) :
    OptionsTab(parent, provider_->type(), "", provider_->optionsName(), provider_->optionsDescription()), w(nullptr),
    provider(provider_)
{
}

OptionsTabAppearanceTheme::~OptionsTabAppearanceTheme() { }

QWidget *OptionsTabAppearanceTheme::widget()
{
    if (w)
        return nullptr;

    w                       = new OptAppearanceThemeUI();
    OptAppearanceThemeUI *d = static_cast<OptAppearanceThemeUI *>(w);

    unsortedModel = new PsiThemeModel(provider, this);

    themesModel = new QSortFilterProxyModel(this);
    themesModel->setSourceModel(unsortedModel);
    themesModel->setSortCaseSensitivity(Qt::CaseInsensitive);

    d->themeView->setModel(themesModel);
    d->themeView->sortByColumn(0, Qt::AscendingOrder);

    connect(d->themeView->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)),
            SLOT(themeSelected(QModelIndex, QModelIndex)));

    connect(themesModel, SIGNAL(rowsInserted(QModelIndex, int, int)), SLOT(modelRowsInserted(QModelIndex, int, int)));
    connect(d->cmb_style, qOverload<int>(&QComboBox::currentIndexChanged), this, [this](int) { emit dataChanged(); });

    QTimer::singleShot(0, unsortedModel, &PsiThemeModel::load);

    return w;
}

void OptionsTabAppearanceTheme::themeSelected(const QModelIndex &current, const QModelIndex &previous)
{
    updateStyles(current);
    if (!previous.isValid()) {
        return; // Psi won't start if it's impossible to load any theme. So we always have previous.
    }
    emit dataChanged();
}

void OptionsTabAppearanceTheme::modelRowsInserted(const QModelIndex &parent, int first, int last)
{
    if (!parent.isValid() || !w) {
        OptAppearanceThemeUI *d = static_cast<OptAppearanceThemeUI *>(w);
        // const QSize buttonSize = QSize(21,21);
        for (int i = first; i <= last; i++) {
            const QModelIndex index = themesModel->index(i, 0);
            if (themesModel->data(index, PsiThemeModel::IsCurrent).toBool()) {
                d->themeView->setCurrentIndex(index);
                updateStyles(index);
            }
#if 0
            const QString id    = themesModel->data(index, PsiThemeModel::IdRole).toString();
            const QString themeName = themesModel->data(index, PsiThemeModel::TitleRole).toString();
            bool isPsi = id.startsWith("psi");
            const QPixmap client = isPsi ? IconsetFactory::iconPtr("clients/psi")->icon()
                             : IconsetFactory::iconPtr("clients/adium")->icon();
            const QString clientName = isPsi ? tr("Psi Theme") : tr("Adium Theme");
            QToolButton *screenshotButton = new QToolButton(d->themeView);
            screenshotButton->setIcon(QIcon(IconsetFactory::iconPtr("psi/eye")->icon())));
            screenshotButton->resize(buttonSize);
            screenshotButton->setObjectName(SCREEN_PREFIX + id);
            screenshotButton->setToolTip(tr("Show theme screenshot"));
            connect(screenshotButton, SIGNAL(clicked()), this, SLOT(showThemeScreenshot()));

            QLabel *typeLabel = new QLabel(d->themeView);
            typeLabel->setPixmap(client);
            typeLabel->setToolTip(clientName);

            QLabel *nameLabel = new QLabel(themeName, d->themeView);

            QWidget *itemWidget = new QWidget(d->themeView);

            QBoxLayout *box = new QBoxLayout(QBoxLayout::LeftToRight, d->themeView);
            box->addWidget(typeLabel);
            box->addWidget(nameLabel);
            box->addStretch();
            box->addWidget(screenshotButton);
            itemWidget->setLayout(box);
            //itemWidget->setAutoFillBackground(true); // from recommendation of indexWidget but does not work as expected

            d->themeView->setIndexWidget(index, itemWidget);
#endif
        }
    }
}

void OptionsTabAppearanceTheme::showThemeScreenshot()
{
    if (!w || !sender()->inherits("QToolButton"))
        return;
    OptAppearanceThemeUI *d   = static_cast<OptAppearanceThemeUI *>(w);
    QToolButton          *btn = static_cast<QToolButton *>(sender());
    if (btn) {
        if (screenshotDialog)
            delete (screenshotDialog);

        const QSize minSize(300, 100);
        screenshotDialog = new QDialog(d);
        screenshotDialog->setMinimumSize(minSize);

        const int         row   = unsortedModel->themeRow(getThemeId(btn->objectName()));
        const QModelIndex index = unsortedModel->index(row, 0);
        const QString     name_ = unsortedModel->data(index, PsiThemeModel::TitleRole).toString();
        const QPixmap     scr   = unsortedModel->data(index, PsiThemeModel::HasPreviewRole).value<QPixmap>();

        screenshotDialog->setWindowTitle(tr("%1 Screenshot").arg(name_));
        screenshotDialog->setWindowIcon(QIcon(IconsetFactory::iconPtr("psi/logo_128")->icon()));

        QBoxLayout *box   = new QBoxLayout(QBoxLayout::LeftToRight, screenshotDialog);
        QLabel     *image = new QLabel(screenshotDialog);
        if (!scr.isNull()) {
            image->setPixmap(scr);
        } else {
            image->setText(tr("No Image"));
        }
        box->addWidget(image);

        screenshotDialog->setAttribute(Qt::WA_DeleteOnClose);
        screenshotDialog->show();
    }
}

QString OptionsTabAppearanceTheme::getThemeId(const QString &objName) const
{
    const int index = objName.indexOf("_", 0);
    return (index > 0 ? objName.right(objName.length() - index - 1) : QString());
}

void OptionsTabAppearanceTheme::updateStyles(const QModelIndex &index)
{
    auto                  styles = themesModel->data(index, PsiThemeModel::StylesListRole).toStringList();
    OptAppearanceThemeUI *d      = static_cast<OptAppearanceThemeUI *>(w);
    d->cmb_style->blockSignals(true);
    d->cmb_style->clear();
    for (auto const &s : std::as_const(styles)) {
        d->cmb_style->addItem(s);
    }
    d->cmb_style->setCurrentText(themesModel->data(index, PsiThemeModel::CurrentStyleRole).toString());
    d->cmb_style->blockSignals(false);
}

void OptionsTabAppearanceTheme::applyOptions()
{
    if (!w)
        return;

    OptAppearanceThemeUI *d = static_cast<OptAppearanceThemeUI *>(w);
    themesModel->setData(d->themeView->currentIndex(), d->cmb_style->currentText(), PsiThemeModel::IsCurrent);
}

void OptionsTabAppearanceTheme::restoreOptions()
{
#if 0
    if ( !w )
        return;

    OptAppearanceThemeUI *d = static_cast<OptAppearanceThemeUI *>(w);
#endif
}
