//////////////////////////////////////////////////////////////////////////////
// breezeconfigurationui.cpp
// -------------------
//
// Copyright (c) 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//////////////////////////////////////////////////////////////////////////////

#include "breezeconfigwidget.h"
#include "breezeexceptionlist.h"

#include <KLocalizedString>

#include <QDBusConnection>
#include <QDBusMessage>
#include <QFontDatabase>

namespace Breeze
{

    //_________________________________________________________
    ConfigWidget::ConfigWidget(QObject *parent, const KPluginMetaData &data, const QVariantList & /*args*/):
        KCModule(parent, data),
        m_configuration( KSharedConfig::openConfig( QStringLiteral( "breezerc" ) ) ),
        m_changed( false )
    {

        // configuration
        m_ui.setupUi(widget());

        // track ui changes
        connect(m_ui.titleAlignment, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()));
        connect(m_ui.buttonSize, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()));
        connect(m_ui.buttonStyle, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) );
        connect(m_ui.buttonTheme, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) );
        connect(m_ui.titleMargin, QOverload<int>::of(&QSpinBox::valueChanged), [this](int /*i*/) {updateChanged();});
        connect(m_ui.buttonSpacing, QOverload<int>::of(&QSpinBox::valueChanged), [this](int /*i*/) {updateChanged();});
        connect(m_ui.typeDecoration, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) );
        connect(m_ui.opacity, QOverload<int>::of(&QSpinBox::valueChanged), [this](int /*i*/) {updateChanged();});
        connect(m_ui.gradientIntensity, QOverload<int>::of(&QSpinBox::valueChanged), [this](int /*i*/) {updateChanged();});
        connect(m_ui.roundedCorners, &QAbstractButton::clicked, this, &ConfigWidget::updateChanged);
        connect(m_ui.roundIntensity, QOverload<int>::of(&QSpinBox::valueChanged), [this](int /*i*/) {updateChanged();});

        connect(m_ui.font, &QFontComboBox::currentFontChanged, [this] {updateChanged();});
        connect(m_ui.fontSize, QOverload<int>::of(&QSpinBox::valueChanged), [this](int /*i*/) {updateChanged();});
        connect(m_ui.fontWeight, QOverload<int>::of(&QComboBox::currentIndexChanged), [this] {updateChanged();});
#if (QT_VERSION >= QT_VERSION_CHECK(6,7,0))
        connect(m_ui.italic, &QCheckBox::checkStateChanged, [this] {updateChanged();});
#else
        connect(m_ui.italicCheckBox, &QCheckBox::stateChanged, [this] {updateChanged();});
#endif

        // track animations changes
        connect(m_ui.animationsEnabled, &QAbstractButton::clicked, this, &ConfigWidget::updateChanged);
        connect(m_ui.animationsDuration, SIGNAL(valueChanged(int)), SLOT(updateChanged()));

        // track shadows changes
        connect(m_ui.shadowSize, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()));
        connect(m_ui.shadowStrength, SIGNAL(valueChanged(int)), SLOT(updateChanged()));
        connect(m_ui.shadowColor, &KColorButton::changed, this, &ConfigWidget::updateChanged);
        connect(m_ui.outlineIntensity, SIGNAL(activated(int)), SLOT(updateChanged()));

        // track exception changes
        connect(m_ui.exceptions, &ExceptionListWidget::changed, this, &ConfigWidget::updateChanged);

    }

    //_________________________________________________________
    void ConfigWidget::load()
    {

        // create internal settings and load from rc files
        m_internalSettings = InternalSettingsPtr(new InternalSettings());
        m_internalSettings->load();

        // assign to ui
        m_ui.titleAlignment->setCurrentIndex(m_internalSettings->titleAlignment());
        m_ui.buttonSize->setCurrentIndex(m_internalSettings->buttonSize());
        m_ui.buttonStyle->setCurrentIndex(m_internalSettings->buttonStyle() );
        m_ui.buttonTheme->setCurrentIndex(m_internalSettings->buttonTheme());
        m_ui.titleMargin->setValue(m_internalSettings->extraTitleMargin());
        m_ui.buttonSpacing->setValue(m_internalSettings->buttonSpacing());
        m_ui.typeDecoration->setCurrentIndex(m_internalSettings->typeDecorationWindow());
        m_ui.animationsEnabled->setChecked(m_internalSettings->animationsEnabled());
        m_ui.animationsDuration->setValue(m_internalSettings->animationsDuration());
        m_ui.opacity->setValue(m_internalSettings->backgroundOpacity());
        m_ui.gradientIntensity->setValue(m_internalSettings->backgroundGradientIntensity());
        m_ui.roundedCorners->setChecked(m_internalSettings->roundedCorners());
        m_ui.roundIntensity->setValue(m_internalSettings->roundIntensity());

        QString fontStr = m_internalSettings->titleBarFont();
        if (fontStr.isEmpty())
            fontStr = QLatin1String("Sans,11,-1,5,400,0,0,0,0,0,0,0,0,0,0,1");
        QFont f; f.fromString(fontStr);
        m_ui.font->setCurrentFont(f);
        m_ui.fontSize->setValue(f.pointSize());
        int w = f.weight();
        switch (w) {
            case QFont::Medium:
                m_ui.fontWeight->setCurrentIndex(1);
                break;
            case QFont::DemiBold:
                m_ui.fontWeight->setCurrentIndex(2);
                break;
            case QFont::Bold:
                m_ui.fontWeight->setCurrentIndex(3);
                break;
            case QFont::ExtraBold:
                m_ui.fontWeight->setCurrentIndex(4);
                break;
            case QFont::Black:
                m_ui.fontWeight->setCurrentIndex(5);
                break;
            default:
                m_ui.fontWeight->setCurrentIndex(0);
                break;
        }
        m_ui.italic->setChecked(f.italic());

        // load shadows
        if(m_internalSettings->shadowSize() <= InternalSettings::ShadowVeryLarge)
            m_ui.shadowSize->setCurrentIndex(m_internalSettings->shadowSize());
        else
            m_ui.shadowSize->setCurrentIndex(InternalSettings::ShadowLarge);

        m_ui.shadowStrength->setValue(qRound(qreal(m_internalSettings->shadowStrength()*100)/255));
        m_ui.shadowColor->setColor(m_internalSettings->shadowColor());

        // load outline intensity
        if (m_internalSettings->outlineIntensity() <= InternalSettings::OutlineMaximum) {
            m_ui.outlineIntensity->setCurrentIndex(m_internalSettings->outlineIntensity());
        } else {
            m_ui.outlineIntensity->setCurrentIndex(InternalSettings::OutlineMedium);
        }

        // load exceptions
        ExceptionList exceptions;
        exceptions.readConfig(m_configuration);
        m_ui.exceptions->setExceptions(exceptions.get());
        setNeedsSave(false);

    }

    //_________________________________________________________
    void ConfigWidget::save()
    {

        // create internal settings and load from rc files
        m_internalSettings = InternalSettingsPtr(new InternalSettings());
        m_internalSettings->load();

        // apply modifications from ui
        m_internalSettings->setTitleAlignment(m_ui.titleAlignment->currentIndex());
        m_internalSettings->setButtonSize(m_ui.buttonSize->currentIndex());
        m_internalSettings->setButtonStyle( m_ui.buttonStyle->currentIndex() );
        m_internalSettings->setButtonTheme(m_ui.buttonTheme->currentIndex());
        m_internalSettings->setExtraTitleMargin(m_ui.titleMargin->value());
        m_internalSettings->setButtonSpacing(m_ui.buttonSpacing->value());
        m_internalSettings->setTypeDecorationWindow( m_ui.typeDecoration->currentIndex() );
        m_internalSettings->setAnimationsEnabled(m_ui.animationsEnabled->isChecked());
        m_internalSettings->setAnimationsDuration(m_ui.animationsDuration->value());
        m_internalSettings->setBackgroundOpacity(m_ui.opacity->value());
        m_internalSettings->setBackgroundGradientIntensity(m_ui.gradientIntensity->value());
        m_internalSettings->setRoundedCorners(m_ui.roundedCorners->isChecked());
        m_internalSettings->setRoundIntensity(m_ui.roundIntensity->value());

        QFont f = m_ui.font->currentFont();
        f.setPointSize(m_ui.fontSize->value());
        int indx = m_ui.fontWeight->currentIndex();
        switch (indx) {
            case 1:
                f.setWeight(QFont::Medium);
                break;
            case 2:
                f.setWeight(QFont::DemiBold);
                break;
            case 3:
                f.setWeight(QFont::Bold);
                break;
            case 4:
                f.setWeight(QFont::ExtraBold);
                break;
            case 5:
                f.setWeight(QFont::Black);
                break;
            default:
                f.setBold(false);
                break;
        }
        f.setItalic(m_ui.italic->isChecked());
        m_internalSettings->setTitleBarFont(f.toString());

        m_internalSettings->setShadowSize(m_ui.shadowSize->currentIndex());
        m_internalSettings->setShadowStrength(qRound( qreal(m_ui.shadowStrength->value()*255)/100));
        m_internalSettings->setShadowColor(m_ui.shadowColor->color());
        m_internalSettings->setOutlineIntensity(m_ui.outlineIntensity->currentIndex());

        // save configuration
        m_internalSettings->save();

        // get list of exceptions and write
        InternalSettingsList exceptions(m_ui.exceptions->exceptions());
        ExceptionList(exceptions).writeConfig(m_configuration);

        // sync configuration
        m_configuration->sync();
        setNeedsSave(false);

        // needed to tell kwin to reload when running from external kcmshell
        {
            QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KWin"),
                                                              QStringLiteral("org.kde.KWin"),
                                                              QStringLiteral("reloadConfig"));
            QDBusConnection::sessionBus().send(message);
        }

        // needed for breeze style to reload shadows
        {
            QDBusMessage message(QDBusMessage::createSignal(QStringLiteral("/BreezeDecoration"),
                                                            QStringLiteral("org.kde.Breeze.Style"),
                                                            QStringLiteral("reparseConfiguration")));
            QDBusConnection::sessionBus().send(message);
        }

    }

    //_________________________________________________________
    void ConfigWidget::defaults()
    {

        // create internal settings and load from rc files
        m_internalSettings = InternalSettingsPtr(new InternalSettings());
        m_internalSettings->setDefaults();

        // assign to ui
        m_ui.titleAlignment->setCurrentIndex(m_internalSettings->titleAlignment());
        m_ui.buttonSize->setCurrentIndex(m_internalSettings->buttonSize());
        m_ui.buttonStyle->setCurrentIndex( m_internalSettings->buttonStyle() );
        m_ui.titleMargin->setValue(m_internalSettings->extraTitleMargin());
        m_ui.buttonSpacing->setValue(m_internalSettings->buttonSpacing());
        m_ui.typeDecoration->setCurrentIndex( m_internalSettings->typeDecorationWindow() );
        m_ui.animationsEnabled->setChecked(m_internalSettings->animationsEnabled());
        m_ui.animationsDuration->setValue(m_internalSettings->animationsDuration());
        m_ui.opacity->setValue(m_internalSettings->backgroundOpacity());
        m_ui.gradientIntensity->setValue(m_internalSettings->backgroundGradientIntensity());
        m_ui.roundedCorners->setChecked(m_internalSettings->roundedCorners());
        m_ui.roundIntensity->setValue(m_internalSettings->roundIntensity());

        QFont f; f.fromString(QStringLiteral("Sans,11,-1,5,400,0,0,0,0,0,0,0,0,0,0,1"));
        m_ui.font->setCurrentFont(f);
        m_ui.fontSize->setValue(f.pointSize());
        int w = f.weight();
        switch (w) {
            case QFont::Medium:
                m_ui.fontWeight->setCurrentIndex(1);
                break;
            case QFont::DemiBold:
                m_ui.fontWeight->setCurrentIndex(2);
                break;
            case QFont::Bold:
                m_ui.fontWeight->setCurrentIndex(3);
                break;
            case QFont::ExtraBold:
                m_ui.fontWeight->setCurrentIndex(4);
                break;
            case QFont::Black:
                m_ui.fontWeight->setCurrentIndex(5);
                break;
            default:
                m_ui.fontWeight->setCurrentIndex(0);
                break;
        }
        m_ui.italic->setChecked(f.italic());

        m_ui.shadowSize->setCurrentIndex(m_internalSettings->shadowSize());
        m_ui.shadowStrength->setValue(qRound(qreal(m_internalSettings->shadowStrength()*100)/255));
        m_ui.shadowColor->setColor(m_internalSettings->shadowColor());
        m_ui.outlineIntensity->setCurrentIndex(m_internalSettings->outlineIntensity());

    }

    //_______________________________________________
    void ConfigWidget::updateChanged()
    {

        // check configuration
        if(!m_internalSettings)
            return;

        // track modifications
        bool modified(false);
        QFont f; f.fromString(m_internalSettings->titleBarFont());

        if (m_ui.titleAlignment->currentIndex() != m_internalSettings->titleAlignment())
            modified = true;
        else if (m_ui.buttonSize->currentIndex() != m_internalSettings->buttonSize())
            modified = true;
        else if( m_ui.buttonStyle->currentIndex() != m_internalSettings->buttonStyle() )
            modified = true;
        else if (m_ui.titleMargin->value() != m_internalSettings->extraTitleMargin())
            modified = true;
        else if (m_ui.buttonSpacing->value() != m_internalSettings->buttonSpacing())
            modified = true;
        else if( m_ui.typeDecoration->currentIndex() != m_internalSettings->typeDecorationWindow() )
            modified = true;
        else if (m_ui.opacity->value() != m_internalSettings->backgroundOpacity())
            modified = true;
        else if (m_ui.gradientIntensity->value() != m_internalSettings->backgroundGradientIntensity())
            modified = true;
        else if (m_ui.roundedCorners->isChecked() != m_internalSettings->roundedCorners())
            modified = true;
        else if (m_ui.roundIntensity->value() != m_internalSettings->roundIntensity())
            modified = true;

        // font (also see below)
        else if (m_ui.font->currentFont().toString() != f.family())
            modified = true;
        else if (m_ui.fontSize->value() != f.pointSize())
            modified = true;
        else if (m_ui.italic->isChecked() != f.italic())
            modified = true;

        // animations
        else if (m_ui.animationsEnabled->isChecked() !=  m_internalSettings->animationsEnabled())
            modified = true;
        else if (m_ui.animationsDuration->value() != m_internalSettings->animationsDuration())
            modified = true;

        // shadows
        else if (m_ui.shadowSize->currentIndex() !=  m_internalSettings->shadowSize())
            modified = true;
        else if (qRound(qreal(m_ui.shadowStrength->value()*255)/100) != m_internalSettings->shadowStrength())
            modified = true;
        else if (m_ui.shadowColor->color() != m_internalSettings->shadowColor())
            modified = true;
        else if (m_ui.outlineIntensity->currentIndex() != m_internalSettings->outlineIntensity())
            modified = true;

        // exceptions
        else if (m_ui.exceptions->isChanged())
            modified = true;
        else {
            int indx = m_ui.fontWeight->currentIndex();
            switch (indx) {
                case 1:
                    if (f.weight() != QFont::Medium) modified = true;
                    break;
                case 2:
                    if (f.weight() != QFont::DemiBold) modified = true;
                    break;
                case 3:
                    if (f.weight() != QFont::Bold) modified = true;
                    break;
                case 4:
                    if (f.weight() != QFont::ExtraBold) modified = true;
                    break;
                case 5:
                    if (f.weight() != QFont::Black) modified = true;
                    break;
                default:
                    if (f.bold()) modified = true;
                    break;
            }
        }

        setNeedsSave(modified);

    }

}
