/*
  Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org>
  Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>

  Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
  Author: Kevin Krammer, krake@kdab.com

  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, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/
#include "prefs.h"
#include "prefs_base.h"

#include <KSystemTimeZone>
#include "calendarview_debug.h"
#include <QFontDatabase>

using namespace EventViews;

QSet<EventViews::EventView::ItemIcon> iconArrayToSet(const QByteArray &array)
{
    QSet<EventViews::EventView::ItemIcon> set;
    for (int i = 0; i < array.count(); ++i) {
        if (i >= EventViews::EventView::IconCount) {
            qCWarning(CALENDARVIEW_LOG) << "Icon array is too big: " << array.count();
            return set;
        }
        if (array[i] != 0) {
            set.insert(static_cast<EventViews::EventView::ItemIcon>(i));
        }
    }
    return set;
}

QByteArray iconSetToArray(const QSet<EventViews::EventView::ItemIcon> &set)
{
    QByteArray array;
    for (int i = 0; i < EventViews::EventView::IconCount; ++i) {
        const bool contains = set.contains(static_cast<EventViews::EventView::ItemIcon>(i));
        array.append(contains ? 1 : 0);
    }

    return array;
}

QByteArray agendaViewIconDefaults()
{
    QByteArray iconDefaults;

    iconDefaults[EventViews::EventView::CalendarCustomIcon] = 1;
    iconDefaults[EventViews::EventView::TaskIcon]           = 1;
    iconDefaults[EventViews::EventView::JournalIcon]        = 1;
    iconDefaults[EventViews::EventView::RecurringIcon]      = 1;
    iconDefaults[EventViews::EventView::ReminderIcon]       = 1;
    iconDefaults[EventViews::EventView::ReadOnlyIcon]       = 1;
    iconDefaults[EventViews::EventView::ReplyIcon]          = 0;

    return iconDefaults;
}

QByteArray monthViewIconDefaults()
{
    QByteArray iconDefaults;

    iconDefaults[EventViews::EventView::CalendarCustomIcon] = 1;
    iconDefaults[EventViews::EventView::TaskIcon]           = 1;
    iconDefaults[EventViews::EventView::JournalIcon]        = 1;
    iconDefaults[EventViews::EventView::RecurringIcon]      = 0;
    iconDefaults[EventViews::EventView::ReminderIcon]       = 0;
    iconDefaults[EventViews::EventView::ReadOnlyIcon]       = 1;
    iconDefaults[EventViews::EventView::ReplyIcon]          = 0;

    return iconDefaults;
}

class BaseConfig : public PrefsBase
{
public:
    BaseConfig();

    void setResourceColor(const QString &resource, const QColor &color);

    void setTimeScaleTimezones(const QStringList &timeZones);
    QStringList timeScaleTimezones() const;

public:
    QHash<QString, QColor> mResourceColors;
    QColor mDefaultResourceColor;

    QFont mDefaultMonthViewFont;
    QFont mDefaultAgendaTimeLabelsFont;

    QStringList mTimeScaleTimeZones;

    QSet<EventViews::EventView::ItemIcon> mAgendaViewIcons;
    QSet<EventViews::EventView::ItemIcon> mMonthViewIcons;

protected:
    void usrSetDefaults() override;
    void usrRead() override;
    bool usrSave() override;
};

BaseConfig::BaseConfig() : PrefsBase()
{
    mDefaultResourceColor = QColor(); //Default is a color invalid

    mDefaultAgendaTimeLabelsFont = QFontDatabase::systemFont(QFontDatabase::GeneralFont);
    // make a large default time bar font, at least 16 points.
    mDefaultAgendaTimeLabelsFont.setPointSize(
        qMax(mDefaultAgendaTimeLabelsFont.pointSize() + 4, 16));

    mDefaultMonthViewFont = QFontDatabase::systemFont(QFontDatabase::GeneralFont);
    // make it a bit smaller
    mDefaultMonthViewFont.setPointSize(
        qMax(mDefaultMonthViewFont.pointSize() - 2, 6));

    agendaTimeLabelsFontItem()->setDefaultValue(mDefaultAgendaTimeLabelsFont);
    agendaTimeLabelsFontItem()->setDefault();
    monthViewFontItem()->setDefaultValue(mDefaultMonthViewFont);
    monthViewFontItem()->setDefault();
}

void BaseConfig::setResourceColor(const QString &resource, const QColor &color)
{
    mResourceColors.insert(resource, color);
}

void BaseConfig::setTimeScaleTimezones(const QStringList &list)
{
    mTimeScaleTimeZones = list;
}

QStringList BaseConfig::timeScaleTimezones() const
{
    return mTimeScaleTimeZones;
}

void BaseConfig::usrSetDefaults()
{
    setAgendaTimeLabelsFont(mDefaultAgendaTimeLabelsFont);
    setMonthViewFont(mDefaultMonthViewFont);

    PrefsBase::usrSetDefaults();
}

void BaseConfig::usrRead()
{
    // Note that the [Category Colors] group was removed after 3.2 due to
    // an algorithm change. That's why we now use [Category Colors2]
    // Resource colors
    KConfigGroup rColorsConfig(config(), "Resources Colors");
    const QStringList colorKeyList = rColorsConfig.keyList();

    QStringList::ConstIterator it3;
    QStringList::ConstIterator end3(colorKeyList.end());
    for (it3 = colorKeyList.begin(); it3 != end3; ++it3) {
        QColor color = rColorsConfig.readEntry(*it3, mDefaultResourceColor);
        //qCDebug(CALENDARVIEW_LOG) << "key:" << (*it3) << "value:" << color;
        setResourceColor(*it3, color);
    }

#if 0
    config()->setGroup("FreeBusy");
    if (mRememberRetrievePw) {
        mRetrievePassword =
            KStringHandler::obscure(config()->readEntry("Retrieve Server Password"));
    }
#endif

    KConfigGroup timeScaleConfig(config(), "Timescale");
    setTimeScaleTimezones(timeScaleConfig.readEntry("Timescale Timezones", QStringList()));

    KConfigGroup monthViewConfig(config(), "Month View");
    KConfigGroup agendaViewConfig(config(), "Agenda View");
    const QByteArray agendaIconArray =
        agendaViewConfig.readEntry<QByteArray>("agendaViewItemIcons", agendaViewIconDefaults());
    const QByteArray monthIconArray =
        monthViewConfig.readEntry<QByteArray>("monthViewItemIcons", monthViewIconDefaults());

    mAgendaViewIcons = iconArrayToSet(agendaIconArray);
    mMonthViewIcons = iconArrayToSet(monthIconArray);

    KConfigSkeleton::usrRead();
}

bool BaseConfig::usrSave()
{
    KConfigGroup generalConfig(config(), "General");

    KConfigGroup rColorsConfig(config(), "Resources Colors");
    QHash<QString, QColor>::const_iterator i = mResourceColors.constBegin();
    QHash<QString, QColor>::const_iterator end(mResourceColors.constEnd());
    while (i != end) {
        rColorsConfig.writeEntry(i.key(), i.value());
        ++i;
    }

#if 0
    if (mRememberRetrievePw) {
        config()->writeEntry("Retrieve Server Password",
                             KStringHandler::obscure(mRetrievePassword));
    } else {
        config()->deleteEntry("Retrieve Server Password");
    }
#endif

    KConfigGroup timeScaleConfig(config(), "Timescale");
    timeScaleConfig.writeEntry("Timescale Timezones", timeScaleTimezones());

    KConfigGroup monthViewConfig(config(), "Month View");
    KConfigGroup agendaViewConfig(config(), "Agenda View");

    const QByteArray agendaIconArray = iconSetToArray(mAgendaViewIcons);
    const QByteArray monthIconArray = iconSetToArray(mMonthViewIcons);

    agendaViewConfig.writeEntry<QByteArray>("agendaViewItemIcons", agendaIconArray);
    monthViewConfig.writeEntry<QByteArray>("monthViewItemIcons", monthIconArray);

    return KConfigSkeleton::usrSave();
}

class Q_DECL_HIDDEN Prefs::Private
{
public:
    Private(Prefs *parent) : mAppConfig(nullptr), q(parent) {}
    Private(Prefs *parent, KCoreConfigSkeleton *appConfig)
        : mAppConfig(appConfig), q(parent) {}

    KConfigSkeletonItem *appConfigItem(const KConfigSkeletonItem *baseConfigItem) const;

    void setBool(KCoreConfigSkeleton::ItemBool *baseConfigItem, bool value);
    bool getBool(const KCoreConfigSkeleton::ItemBool *baseConfigItem) const;

    void setInt(KCoreConfigSkeleton::ItemInt *baseConfigItem, int value);
    int getInt(const KCoreConfigSkeleton::ItemInt *baseConfigItem) const;

    void setString(KCoreConfigSkeleton::ItemString *baseConfigItem, const QString &value);
    QString getString(const KCoreConfigSkeleton::ItemString *baseConfigItem) const;

    void setDateTime(KCoreConfigSkeleton::ItemDateTime *baseConfigItem, const QDateTime &value);
    QDateTime getDateTime(const KCoreConfigSkeleton::ItemDateTime *baseConfigItem) const;

    void setStringList(KCoreConfigSkeleton::ItemStringList *baseConfigItem,
                       const QStringList &value);
    QStringList getStringList(const KCoreConfigSkeleton::ItemStringList *baseConfigItem) const;

    void setColor(KConfigSkeleton::ItemColor *baseConfigItem, const QColor &value);
    QColor getColor(const KConfigSkeleton::ItemColor *baseConfigItem) const;

    void setFont(KConfigSkeleton::ItemFont *baseConfigItem, const QFont &value);
    QFont getFont(const KConfigSkeleton::ItemFont *baseConfigItem) const;

public:
    BaseConfig mBaseConfig;
    KCoreConfigSkeleton *mAppConfig;

private:
    Prefs *q;
};

KConfigSkeletonItem *Prefs::Private::appConfigItem(
    const KConfigSkeletonItem *baseConfigItem) const
{
    Q_ASSERT(baseConfigItem);

    if (mAppConfig) {
        return mAppConfig->findItem(baseConfigItem->name());
    }

    return nullptr;
}

void Prefs::Private::setBool(KCoreConfigSkeleton::ItemBool *baseConfigItem, bool value)
{
    KConfigSkeletonItem *appItem = appConfigItem(baseConfigItem);
    if (appItem) {
        KCoreConfigSkeleton::ItemBool *item = dynamic_cast<KCoreConfigSkeleton::ItemBool *>(appItem);
        if (item) {
            item->setValue(value);
        } else {
            qCCritical(CALENDARVIEW_LOG) << "Application config item" << appItem->name() << "is not of type Bool";
        }
    } else {
        baseConfigItem->setValue(value);
    }
}

bool Prefs::Private::getBool(const KCoreConfigSkeleton::ItemBool *baseConfigItem) const
{
    KConfigSkeletonItem *appItem = appConfigItem(baseConfigItem);
    if (appItem) {
        KCoreConfigSkeleton::ItemBool *item = dynamic_cast<KCoreConfigSkeleton::ItemBool *>(appItem);
        if (item) {
            return item->value();
        }
        qCCritical(CALENDARVIEW_LOG) << "Application config item" << appItem->name() << "is not of type Bool";
    }
    return baseConfigItem->value();
}

void Prefs::Private::setInt(KCoreConfigSkeleton::ItemInt *baseConfigItem, int value)
{
    KConfigSkeletonItem *appItem = appConfigItem(baseConfigItem);
    if (appItem) {
        KCoreConfigSkeleton::ItemInt *item = dynamic_cast<KCoreConfigSkeleton::ItemInt *>(appItem);
        if (item) {
            item->setValue(value);
        } else {
            qCCritical(CALENDARVIEW_LOG) << "Application config item" << appItem->name() << "is not of type Int";
        }
    } else {
        baseConfigItem->setValue(value);
    }
}

int Prefs::Private::getInt(const KCoreConfigSkeleton::ItemInt *baseConfigItem) const
{
    KConfigSkeletonItem *appItem = appConfigItem(baseConfigItem);
    if (appItem) {
        KCoreConfigSkeleton::ItemInt *item = dynamic_cast<KCoreConfigSkeleton::ItemInt *>(appItem);
        if (item) {
            return item->value();
        }
        qCCritical(CALENDARVIEW_LOG) << "Application config item" << appItem->name() << "is not of type Int";
    }
    return baseConfigItem->value();
}

void Prefs::Private::setString(KCoreConfigSkeleton::ItemString *baseConfigItem,
                               const QString &value)
{
    KConfigSkeletonItem *appItem = appConfigItem(baseConfigItem);
    if (appItem) {
        KCoreConfigSkeleton::ItemString *item =
            dynamic_cast<KCoreConfigSkeleton::ItemString *>(appItem);

        if (item) {
            item->setValue(value);
        } else {
            qCCritical(CALENDARVIEW_LOG) << "Application config item" << appItem->name() << "is not of type String";
        }
    } else {
        baseConfigItem->setValue(value);
    }
}

QString Prefs::Private::getString(const KCoreConfigSkeleton::ItemString *baseConfigItem) const
{
    KConfigSkeletonItem *appItem = appConfigItem(baseConfigItem);
    if (appItem) {
        KCoreConfigSkeleton::ItemString *item =
            dynamic_cast<KCoreConfigSkeleton::ItemString *>(appItem);

        if (item) {
            return item->value();
        }
        qCCritical(CALENDARVIEW_LOG) << "Application config item" << appItem->name() << "is not of type String";
    }
    return baseConfigItem->value();
}

void Prefs::Private::setDateTime(KCoreConfigSkeleton::ItemDateTime *baseConfigItem,
                                 const QDateTime &value)
{
    KConfigSkeletonItem *appItem = appConfigItem(baseConfigItem);
    if (appItem) {
        KCoreConfigSkeleton::ItemDateTime *item =
            dynamic_cast<KCoreConfigSkeleton::ItemDateTime *>(appItem);

        if (item) {
            item->setValue(value);
        } else {
            qCCritical(CALENDARVIEW_LOG) << "Application config item" << appItem->name() << "is not of type DateTime";
        }
    } else {
        baseConfigItem->setValue(value);
    }
}

QDateTime Prefs::Private::getDateTime(
    const KCoreConfigSkeleton::ItemDateTime *baseConfigItem) const
{
    KConfigSkeletonItem *appItem = appConfigItem(baseConfigItem);
    if (appItem) {
        KCoreConfigSkeleton::ItemDateTime *item =
            dynamic_cast<KCoreConfigSkeleton::ItemDateTime *>(appItem);

        if (item) {
            return item->value();
        }
        qCCritical(CALENDARVIEW_LOG) << "Application config item" << appItem->name() << "is not of type DateTime";
    }
    return baseConfigItem->value();
}

void Prefs::Private::setStringList(KCoreConfigSkeleton::ItemStringList *baseConfigItem,
                                   const QStringList &value)
{
    KConfigSkeletonItem *appItem = appConfigItem(baseConfigItem);
    if (appItem) {
        KCoreConfigSkeleton::ItemStringList *item =
            dynamic_cast<KCoreConfigSkeleton::ItemStringList *>(appItem);

        if (item) {
            item->setValue(value);
        } else {
            qCCritical(CALENDARVIEW_LOG) << "Application config item" << appItem->name() << "is not of type StringList";
        }
    } else {
        baseConfigItem->setValue(value);
    }
}

QStringList Prefs::Private::getStringList(
    const KCoreConfigSkeleton::ItemStringList *baseConfigItem) const
{
    KConfigSkeletonItem *appItem = appConfigItem(baseConfigItem);
    if (appItem) {
        KCoreConfigSkeleton::ItemStringList *item =
            dynamic_cast<KCoreConfigSkeleton::ItemStringList *>(appItem);

        if (item) {
            return item->value();
        }
        qCCritical(CALENDARVIEW_LOG) << "Application config item" << appItem->name() << "is not of type StringList";
    }
    return baseConfigItem->value();
}

void Prefs::Private::setColor(KConfigSkeleton::ItemColor *baseConfigItem, const QColor &value)
{
    KConfigSkeletonItem *appItem = appConfigItem(baseConfigItem);
    if (appItem) {
        KConfigSkeleton::ItemColor *item = dynamic_cast<KConfigSkeleton::ItemColor *>(appItem);
        if (item) {
            item->setValue(value);
        } else {
            qCCritical(CALENDARVIEW_LOG) << "Application config item" << appItem->name() << "is not of type Color";
        }
    } else {
        baseConfigItem->setValue(value);
    }
}

QColor Prefs::Private::getColor(const KConfigSkeleton::ItemColor *baseConfigItem) const
{
    KConfigSkeletonItem *appItem = appConfigItem(baseConfigItem);
    if (appItem) {
        KConfigSkeleton::ItemColor *item = dynamic_cast<KConfigSkeleton::ItemColor *>(appItem);
        if (item) {
            return item->value();
        }
        qCCritical(CALENDARVIEW_LOG) << "Application config item" << appItem->name() << "is not of type Color";
    }
    return baseConfigItem->value();
}

void Prefs::Private::setFont(KConfigSkeleton::ItemFont *baseConfigItem, const QFont &value)
{
    KConfigSkeletonItem *appItem = appConfigItem(baseConfigItem);
    if (appItem) {
        KConfigSkeleton::ItemFont *item = dynamic_cast<KConfigSkeleton::ItemFont *>(appItem);
        if (item) {
            item->setValue(value);
        } else {
            qCCritical(CALENDARVIEW_LOG) << "Application config item" << appItem->name() << "is not of type Font";
        }
    } else {
        baseConfigItem->setValue(value);
    }
}

QFont Prefs::Private::getFont(const KConfigSkeleton::ItemFont *baseConfigItem) const
{
    KConfigSkeletonItem *appItem = appConfigItem(baseConfigItem);
    if (appItem) {
        KConfigSkeleton::ItemFont *item = dynamic_cast<KConfigSkeleton::ItemFont *>(appItem);
        if (item) {
            return item->value();
        }
        qCCritical(CALENDARVIEW_LOG) << "Application config item" << appItem->name() << "is not of type Font";
    }
    return baseConfigItem->value();
}

Prefs::Prefs() : d(new Private(this))
{
}

Prefs::Prefs(KCoreConfigSkeleton *appConfig) : d(new Private(this, appConfig))
{
}

Prefs::~Prefs()
{
    delete d;
}

void Prefs::readConfig()
{
    d->mBaseConfig.load();
    if (d->mAppConfig) {
        d->mAppConfig->load();
    }
}

void Prefs::writeConfig()
{
    d->mBaseConfig.save();
    if (d->mAppConfig) {
        d->mAppConfig->save();
    }
}

void Prefs::setMarcusBainsShowSeconds(bool showSeconds)
{
    d->setBool(d->mBaseConfig.marcusBainsShowSecondsItem(), showSeconds);
}

bool Prefs::marcusBainsShowSeconds() const
{
    return d->getBool(d->mBaseConfig.marcusBainsShowSecondsItem());
}

void Prefs::setAgendaMarcusBainsLineLineColor(const QColor &color)
{
    d->setColor(d->mBaseConfig.agendaMarcusBainsLineLineColorItem(), color);
}

QColor Prefs::agendaMarcusBainsLineLineColor() const
{
    return d->getColor(d->mBaseConfig.agendaMarcusBainsLineLineColorItem());
}

void Prefs::setMarcusBainsEnabled(bool enabled)
{
    d->setBool(d->mBaseConfig.marcusBainsEnabledItem(), enabled);
}

bool Prefs::marcusBainsEnabled() const
{
    return d->getBool(d->mBaseConfig.marcusBainsEnabledItem());
}

void Prefs::setAgendaMarcusBainsLineFont(const QFont &font)
{
    d->setFont(d->mBaseConfig.agendaMarcusBainsLineFontItem(), font);
}

QFont Prefs::agendaMarcusBainsLineFont() const
{
    return d->getFont(d->mBaseConfig.agendaMarcusBainsLineFontItem());
}

void Prefs::setHourSize(int size)
{
    d->setInt(d->mBaseConfig.hourSizeItem(), size);
}

int Prefs::hourSize() const
{
    return d->getInt(d->mBaseConfig.hourSizeItem());
}

void Prefs::setDayBegins(const QDateTime &dateTime)
{
    d->setDateTime(d->mBaseConfig.dayBeginsItem(), dateTime);
}

QDateTime Prefs::dayBegins() const
{
    return d->getDateTime(d->mBaseConfig.dayBeginsItem());
}

void Prefs::setWorkingHoursStart(const QDateTime &dateTime)
{
    d->setDateTime(d->mBaseConfig.workingHoursStartItem(), dateTime);
}

QDateTime Prefs::workingHoursStart() const
{
    return d->getDateTime(d->mBaseConfig.workingHoursStartItem());
}

void Prefs::setWorkingHoursEnd(const QDateTime &dateTime)
{
    d->setDateTime(d->mBaseConfig.workingHoursEndItem(), dateTime);
}

QDateTime Prefs::workingHoursEnd() const
{
    return d->getDateTime(d->mBaseConfig.workingHoursEndItem());
}

void Prefs::setSelectionStartsEditor(bool startEditor)
{
    d->setBool(d->mBaseConfig.selectionStartsEditorItem(), startEditor);
}

bool Prefs::selectionStartsEditor() const
{
    return d->getBool(d->mBaseConfig.selectionStartsEditorItem());
}

void Prefs::setAgendaGridWorkHoursBackgroundColor(const QColor &color)
{
    d->setColor(d->mBaseConfig.agendaGridWorkHoursBackgroundColorItem(), color);
}

QColor Prefs::agendaGridWorkHoursBackgroundColor() const
{
    return d->getColor(d->mBaseConfig.agendaGridWorkHoursBackgroundColorItem());
}

void Prefs::setAgendaGridHighlightColor(const QColor &color)
{
    d->setColor(d->mBaseConfig.agendaGridHighlightColorItem(), color);
}

QColor Prefs::agendaGridHighlightColor() const
{
    return d->getColor(d->mBaseConfig.agendaGridHighlightColorItem());
}

void Prefs::setAgendaGridBackgroundColor(const QColor &color)
{
    d->setColor(d->mBaseConfig.agendaGridBackgroundColorItem(), color);
}

QColor Prefs::agendaGridBackgroundColor() const
{
    return d->getColor(d->mBaseConfig.agendaGridBackgroundColorItem());
}

void Prefs::setEnableAgendaItemIcons(bool enable)
{
    d->setBool(d->mBaseConfig.enableAgendaItemIconsItem(), enable);
}

bool Prefs::enableAgendaItemIcons() const
{
    return d->getBool(d->mBaseConfig.enableAgendaItemIconsItem());
}

void Prefs::setTodosUseCategoryColors(bool useColors)
{
    d->setBool(d->mBaseConfig.todosUseCategoryColorsItem(), useColors);
}

bool Prefs::todosUseCategoryColors() const
{
    return d->getBool(d->mBaseConfig.todosUseCategoryColorsItem());
}

void Prefs::setAgendaHolidaysBackgroundColor(const QColor &color) const
{
    d->setColor(d->mBaseConfig.agendaHolidaysBackgroundColorItem(), color);
}

QColor Prefs::agendaHolidaysBackgroundColor() const
{
    return d->getColor(d->mBaseConfig.agendaHolidaysBackgroundColorItem());
}

void Prefs::setAgendaViewColors(int colors)
{
    d->setInt(d->mBaseConfig.agendaViewColorsItem(), colors);
}

int Prefs::agendaViewColors() const
{
    return d->getInt(d->mBaseConfig.agendaViewColorsItem());
}

void Prefs::setAgendaViewFont(const QFont &font)
{
    d->setFont(d->mBaseConfig.agendaViewFontItem(), font);
}

QFont Prefs::agendaViewFont() const
{
    return d->getFont(d->mBaseConfig.agendaViewFontItem());
}

void Prefs::setMonthViewFont(const QFont &font)
{
    d->setFont(d->mBaseConfig.monthViewFontItem(), font);
}

QFont Prefs::monthViewFont() const
{
    return d->getFont(d->mBaseConfig.monthViewFontItem());
}

QColor Prefs::monthGridBackgroundColor() const
{
    return d->getColor(d->mBaseConfig.monthGridBackgroundColorItem());
}

void Prefs::setMonthGridBackgroundColor(const QColor &color)
{
    d->setColor(d->mBaseConfig.monthGridBackgroundColorItem(), color);
}

QColor Prefs::monthGridWorkHoursBackgroundColor() const
{
    return d->getColor(d->mBaseConfig.monthGridWorkHoursBackgroundColorItem());
}

void Prefs::monthGridWorkHoursBackgroundColor(const QColor &color)
{
    d->setColor(d->mBaseConfig.monthGridWorkHoursBackgroundColorItem(), color);
}

int Prefs::monthViewColors() const
{
    return d->getInt(d->mBaseConfig.monthViewColorsItem());
}

void Prefs::setMonthViewColors(int colors) const
{
    d->setInt(d->mBaseConfig.monthViewColorsItem(), colors);
}

void Prefs::setEnableMonthItemIcons(bool enable)
{
    d->setBool(d->mBaseConfig.enableMonthItemIconsItem(), enable);
}

bool Prefs::enableMonthItemIcons() const
{
    return d->getBool(d->mBaseConfig.enableMonthItemIconsItem());
}

bool Prefs::showTimeInMonthView() const
{
    return d->getBool(d->mBaseConfig.showTimeInMonthViewItem());
}

void Prefs::setShowTimeInMonthView(bool show)
{
    d->setBool(d->mBaseConfig.showTimeInMonthViewItem(), show);
}

bool Prefs::showTodosMonthView() const
{
    return d->getBool(d->mBaseConfig.showTodosMonthViewItem());
}

void Prefs::setShowTodosMonthView(bool enable)
{
    d->setBool(d->mBaseConfig.showTodosMonthViewItem(), enable);
}

bool Prefs::showJournalsMonthView() const
{
    return d->getBool(d->mBaseConfig.showJournalsMonthViewItem());
}

void Prefs::setShowJournalsMonthView(bool enable)
{
    d->setBool(d->mBaseConfig.showJournalsMonthViewItem(), enable);
}

bool Prefs::fullViewMonth() const
{
    return d->getBool(d->mBaseConfig.fullViewMonthItem());
}

void Prefs::setFullViewMonth(bool fullView)
{
    d->setBool(d->mBaseConfig.fullViewMonthItem(), fullView);
}

bool Prefs::sortCompletedTodosSeparately() const
{
    return d->getBool(d->mBaseConfig.sortCompletedTodosSeparatelyItem());
}

void Prefs::setSortCompletedTodosSeparately(bool enable)
{
    d->setBool(d->mBaseConfig.sortCompletedTodosSeparatelyItem(), enable);
}

void Prefs::setEnableToolTips(bool enable)
{
    d->setBool(d->mBaseConfig.enableToolTipsItem(), enable);
}

bool Prefs::enableToolTips() const
{
    return d->getBool(d->mBaseConfig.enableToolTipsItem());
}

void Prefs::setShowTodosAgendaView(bool show)
{
    d->setBool(d->mBaseConfig.showTodosAgendaViewItem(), show);
}

bool Prefs::showTodosAgendaView() const
{
    return d->getBool(d->mBaseConfig.showTodosAgendaViewItem());
}

void Prefs::setAgendaTimeLabelsFont(const QFont &font)
{
    d->setFont(d->mBaseConfig.agendaTimeLabelsFontItem(), font);
}

QFont Prefs::agendaTimeLabelsFont() const
{
    return d->getFont(d->mBaseConfig.agendaTimeLabelsFontItem());
}

KDateTime::Spec Prefs::timeSpec() const
{
    return KSystemTimeZones::local();
}

QTimeZone Prefs::timeZone() const
{
    return QTimeZone::systemTimeZone();
}

bool Prefs::colorAgendaBusyDays() const
{
    return d->getBool(d->mBaseConfig.colorBusyDaysEnabledItem());
}

bool Prefs::colorMonthBusyDays() const
{
    return d->getBool(d->mBaseConfig.colorMonthBusyDaysEnabledItem());
}

QColor Prefs::viewBgBusyColor() const
{
    return d->getColor(d->mBaseConfig.viewBgBusyColorItem());
}

void Prefs::setViewBgBusyColor(const QColor &color)
{
    d->mBaseConfig.mViewBgBusyColor = color;
}

QColor Prefs::holidayColor() const
{
    return d->getColor(d->mBaseConfig.holidayColorItem());
}

void Prefs::setHolidayColor(const QColor &color)
{
    d->mBaseConfig.mHolidayColor = color;
}

QColor Prefs::agendaViewBackgroundColor() const
{
    return d->getColor(d->mBaseConfig.agendaBgColorItem());
}

void Prefs::setAgendaViewBackgroundColor(const QColor &color)
{
    d->mBaseConfig.mAgendaBgColor = color;
}

QColor Prefs::workingHoursColor() const
{
    return d->getColor(d->mBaseConfig.workingHoursColorItem());
}

void Prefs::setWorkingHoursColor(const QColor &color)
{
    d->mBaseConfig.mWorkingHoursColor = color;
}

QColor Prefs::todoDueTodayColor() const
{
    return d->getColor(d->mBaseConfig.todoDueTodayColorItem());
}

void Prefs::setTodoDueTodayColor(const QColor &color)
{
    d->mBaseConfig.mTodoDueTodayColor = color;
}

QColor Prefs::todoOverdueColor() const
{
    return d->getColor(d->mBaseConfig.todoOverdueColorItem());
}

void Prefs::setTodoOverdueColor(const QColor &color)
{
    d->mBaseConfig.mTodoOverdueColor = color;
}

void Prefs::setColorAgendaBusyDays(bool enable)
{
    d->mBaseConfig.mColorBusyDaysEnabled = enable;
}

void Prefs::setColorMonthBusyDays(bool enable)
{
    d->mBaseConfig.mColorMonthBusyDaysEnabled = enable;
}

void Prefs::setResourceColor(const QString &cal, const QColor &color)
{
    d->mBaseConfig.setResourceColor(cal, color);
}
#define USE_RANDOM
void Prefs::createNewColor(QColor &defColor, int seed)
{
#ifdef USE_RANDOM
    Q_UNUSED(seed);
    QColor col = QColor(qrand() % 256, qrand() % 256, qrand() % 256);
    defColor = col;
#else
    int h, s, v;
    defColor.getHsv(&h, &s, &v);
    h = (seed % 12) * 30;
    s -= s * static_cast<int>(((seed / 12) % 2) * 0.5);
    defColor.setHsv(h, s, v);
#endif
}

QColor Prefs::resourceColorKnown(const QString &cal) const
{
    QColor color;
    if (!cal.isEmpty()  &&
            d->mBaseConfig.mResourceColors.contains(cal)) {
        color = d->mBaseConfig.mResourceColors.value(cal);
    }
    return color;
}

QColor Prefs::resourceColor(const QString &cal)
{
    if (cal.isEmpty()) {
        return d->mBaseConfig.mDefaultResourceColor;
    }

    QColor color = resourceColorKnown(cal);

    // assign default color if enabled
    if (!color.isValid() &&
            d->getBool(d->mBaseConfig.assignDefaultResourceColorsItem())) {
        QColor defColor(0x37, 0x7A, 0xBC);
        const int seed = d->getInt(d->mBaseConfig.defaultResourceColorSeedItem());
        const QStringList colors = d->getStringList(d->mBaseConfig.defaultResourceColorsItem());
        if (seed > 0 && seed - 1 < (int)colors.size()) {
            defColor = QColor(colors[seed - 1]);
        } else {
            createNewColor(defColor, seed);
        }
        d->setInt(d->mBaseConfig.defaultResourceColorSeedItem(), (seed + 1));
        d->mBaseConfig.setResourceColor(cal, defColor);
        color = d->mBaseConfig.mResourceColors[cal];
    }
    if (color.isValid()) {
        return color;
    } else {
        return d->mBaseConfig.mDefaultResourceColor;
    }
}

QStringList Prefs::timeScaleTimezones() const
{
    return d->mBaseConfig.timeScaleTimezones();
}

void Prefs::setTimeScaleTimezones(const QStringList &list)
{
    d->mBaseConfig.setTimeScaleTimezones(list);
}

KConfigSkeleton::ItemFont *Prefs::fontItem(const QString &name) const
{
    KConfigSkeletonItem *item = d->mAppConfig ? d->mAppConfig->findItem(name) : nullptr;

    if (!item) {
        item = d->mBaseConfig.findItem(name);
    }

    return dynamic_cast<KConfigSkeleton::ItemFont *>(item);
}

QStringList Prefs::selectedPlugins() const
{
    return d->mBaseConfig.mSelectedPlugins;
}

QStringList Prefs::decorationsAtAgendaViewTop() const
{
    return d->mBaseConfig.decorationsAtAgendaViewTop();
}

QStringList Prefs::decorationsAtAgendaViewBottom() const
{
    return d->mBaseConfig.decorationsAtAgendaViewBottom();
}

void Prefs::setSelectedPlugins(const QStringList &plugins)
{
    d->mBaseConfig.setSelectedPlugins(plugins);
}

void Prefs::setDecorationsAtAgendaViewTop(const QStringList &decorations)
{
    d->mBaseConfig.setDecorationsAtAgendaViewTop(decorations);
}

void Prefs::setDecorationsAtAgendaViewBottom(const QStringList &decorations)
{
    d->mBaseConfig.setDecorationsAtAgendaViewBottom(decorations);
}

QSet<EventViews::EventView::ItemIcon> Prefs::agendaViewIcons() const
{
    return d->mBaseConfig.mAgendaViewIcons;
}

void Prefs::setAgendaViewIcons(const QSet<EventViews::EventView::ItemIcon> &icons)
{
    d->mBaseConfig.mAgendaViewIcons = icons;
}

QSet<EventViews::EventView::ItemIcon> Prefs::monthViewIcons() const
{
    return d->mBaseConfig.mMonthViewIcons;
}

void Prefs::setMonthViewIcons(const QSet<EventViews::EventView::ItemIcon> &icons)
{
    d->mBaseConfig.mMonthViewIcons = icons;
}

void Prefs::setFlatListTodo(bool enable)
{
    d->mBaseConfig.mFlatListTodo = enable;
}

bool Prefs::flatListTodo() const
{
    return d->mBaseConfig.mFlatListTodo;
}

void Prefs::setFullViewTodo(bool enable)
{
    d->mBaseConfig.mFullViewTodo = enable;
}

bool Prefs::fullViewTodo() const
{
    return d->mBaseConfig.mFullViewTodo;
}

bool Prefs::enableTodoQuickSearch() const
{
    return d->mBaseConfig.mEnableTodoQuickSearch;
}

void Prefs::setEnableTodoQuickSearch(bool enable)
{
    d->mBaseConfig.mEnableTodoQuickSearch = enable;
}

bool Prefs::enableQuickTodo() const
{
    return d->mBaseConfig.mEnableQuickTodo;
}

void Prefs::setEnableQuickTodo(bool enable)
{
    d->mBaseConfig.mEnableQuickTodo = enable;
}

bool Prefs::highlightTodos() const
{
    return d->mBaseConfig.mHighlightTodos;
}

void Prefs::setHighlightTodos(bool highlight)
{
    d->mBaseConfig.mHighlightTodos = highlight;
}

KConfig *Prefs::config() const
{
    return d->mAppConfig ? d->mAppConfig->config() : d->mBaseConfig.config();
}
