/***************************************************************************
 *   Copyright (c) 1996-2002 the kicker authors. (fuzzy logic)             *
 *   Copyright (C) 2007 by Riccardo Iaconelli <ruphy@fsfe.org>             *
 *   Copyright (C) 2007 by Sven Burmeister <sven.burmeister@gmx.net>       *
 *                                                                         *
 *   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 .        *
 ***************************************************************************/

#include "fuzzyClock.h"

#include <QFontMetrics>
#include <QPainter>
#include <QFontInfo>

#include <KColorScheme>
#include <KConfigDialog>
#include <KDebug>
#include <KCalendarSystem>

#include <Plasma/Theme>

Clock::Clock(QObject *parent, const QVariantList &args)
    : ClockApplet(parent, args),
      m_oldContentSize(QSizeF (0,0)),
      m_adjustToHeight(1),
      m_useCustomFontColor(false),
      m_fontColor(Qt::white),
      m_fontTimeBold(false),
      m_fontTimeItalic(false),
      m_fontTime(KGlobalSettings::smallestReadableFont()),
      m_showTimezone(false),
      m_showDate(false),
      m_showYear(false),
      m_showDay(false),
      m_layout(0)
{
    KGlobal::locale()->insertCatalog("libplasmaclock");
    KGlobal::locale()->insertCatalog("timezones4");
    setHasConfigurationInterface(true);
    setBackgroundHints(Plasma::Applet::DefaultBackground);
    //If we do not set this, the user has to press CTRL when shrinking the plasmoid on the desktop beyond a certain size.
    setAspectRatioMode(Plasma::IgnoreAspectRatio);
}

Clock::~Clock()
{
}

void Clock::init()
{
    ClockApplet::init();

    initFuzzyTimeStrings();

    m_contentSize = geometry().size();

    kDebug() << "The first content's size [geometry().size()] we get, init() called: " << geometry().size();

    m_locale = KGlobal::locale();

    clockConfigChanged();

    //By default we use the smallest readable font.
    m_fontDate = QFont ( KGlobalSettings::smallestReadableFont() );

    m_margin = 2;
    m_verticalSpacing = 2;

    Plasma::DataEngine* timeEngine = dataEngine("time");
    timeEngine->connectSource(currentTimezone(), this, 6000, Plasma::AlignToMinute);

    connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(updateColors()));
}

void Clock::clockConfigChanged()
{
    KConfigGroup cg = config();

    m_showTimezone = cg.readEntry("showTimezone", false);
    m_showDate = cg.readEntry("showDate", true);
    m_showYear = cg.readEntry("showYear",false);
    m_showDay = cg.readEntry("showDay",true);

    m_fuzzyness = cg.readEntry("fuzzyness", 1);

    m_fontTime = cg.readEntry("fontTime", KGlobalSettings::smallestReadableFont());
    m_useCustomFontColor = cg.readEntry("useCustomFontColor", false);
    if (m_useCustomFontColor){
        m_fontColor = cg.readEntry("fontColor", m_fontColor);
    }else{
        m_fontColor = KColorScheme(QPalette::Active, KColorScheme::View, Plasma::Theme::defaultTheme()->colorScheme()).foreground().color();
    }
    m_fontTimeBold = cg.readEntry("fontTimeBold", true);
    m_fontTimeItalic = cg.readEntry("fontTimeItalic", false);

    m_fontTime.setBold(m_fontTimeBold);
    m_fontTime.setItalic(m_fontTimeItalic);

    m_adjustToHeight = cg.readEntry("adjustToHeight", 1);
}

Qt::Orientations Clock::expandingDirections() const
{
    //This tells the layout whether it's ok to be stretched, even if we do not need that space. Since we would become far too wide on a panel we do not want that.
    return 0;
}

// QSizeF Clock::contentSizeHint() const
// {
//     return contentSize();
// }

void Clock::constraintsEvent(Plasma::Constraints constraints)
{
    kDebug() << "constraintsEvent() called";

    if (constraints & Plasma::SizeConstraint || constraints & Plasma::FormFactorConstraint) {
        if ( (m_oldContentSize.toSize() != geometry().size() && m_oldContentSize.toSize() != QSize (0,0)) || m_configUpdated == true ) { //The size changed or config was updated
            kDebug() << "The content's size [geometry().size()] changed! old: " << m_oldContentSize << "new: " << geometry().size();

            if ( m_configUpdated ) {
                calculateDateString();
                calculateTimeString();
            }

            kDebug() << "Constraints changed: " << constraints;

            if (formFactor() == Plasma::Planar || formFactor() == Plasma::MediaCenter) {
                kDebug() << "######## Other FormFactor";

                calculateSize();
            } else {
                kDebug() << "######## Small FormFactor";

                calculateSize();
            }

            kDebug() << "The new size has been calculated and set.\nneeded m_contenSize (if not in panel): " << m_contentSize << "\nactual content's size [geometry().size()] is: " << geometry().size() << "\nminimumSize() needed (in panel): " << minimumSize();

            m_oldContentSize = geometry().size();
            m_configUpdated = false;

            update();
        }
    }
}

void Clock::dataUpdated(const QString& source, const Plasma::DataEngine::Data &data)
{
    Q_UNUSED(source);
    m_time = data["Time"].toTime();
    m_date = data["Date"].toDate();

    kDebug() << "dataUpdated() was called.";

    if (m_time.minute() == m_lastTimeSeen.minute()) {
        // avoid unnecessary repaints
//         kDebug() << "avoided unnecessary update!";
        return;
    }

    if (Plasma::ToolTipManager::self()->isVisible(this)) {
        updateTipContent();
    }

    updateClockApplet(data);

    m_lastTimeSeen = m_time;

    calculateDateString();
    calculateTimeString();

    //The timestring changed.
    if (m_timeString != m_lastTimeStringSeen || m_dateString != m_lastDateStringSeen) {

        //The size might have changed
        calculateSize();

        m_lastTimeStringSeen = m_timeString;
        m_lastDateStringSeen = m_dateString;

        updateGeometry();

        //request to get painted.
        update();
    }
}

void Clock::createClockConfigurationInterface(KConfigDialog *parent)
{
    QWidget *widget = new QWidget();
    ui.setupUi(widget);
    parent->addPage(widget, i18n("General"), icon());

    ui.fuzzynessSlider->setSliderPosition( m_fuzzyness );
    ui.showTimezone->setChecked( m_showTimezone );
    ui.showDate->setChecked( m_showDate );
    ui.showYear->setChecked( m_showYear );
    ui.showDay->setChecked( m_showDay );
    ui.adjustToHeight->setSliderPosition( m_adjustToHeight );

    ui.fontTimeBold->setChecked(m_fontTimeBold);
    ui.fontTimeItalic->setChecked(m_fontTimeItalic);
    ui.fontTime->setCurrentFont(m_fontTime);
    ui.fontColor->setColor(m_fontColor);
    ui.useCustomFontColor->setChecked(m_useCustomFontColor);

    connect(ui.fontTime, SIGNAL(editTextChanged(QString)), parent, SLOT(settingsModified()));
    connect(ui.fontTimeBold, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
    connect(ui.fontTimeItalic, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
    connect(ui.useThemeColor, SIGNAL(toggled(bool)), parent, SLOT(settingsModified()));
    connect(ui.adjustToHeight, SIGNAL(valueChanged(int)), parent, SLOT(settingsModified()));
    connect(ui.showDate, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
    connect(ui.showDay, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
    connect(ui.showYear, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
    connect(ui.showTimezone, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
    connect(ui.fuzzynessSlider, SIGNAL(valueChanged(int)), parent, SLOT(settingsModified()));
}

void Clock::clockConfigAccepted()
{
    KConfigGroup cg = config();
    QGraphicsItem::update();

    m_fontTime = ui.fontTime->currentFont();
    cg.writeEntry("fontTime", m_fontTime);

    //In case adjustToHeight was disabled we have to reset the point-size of fontTime
    m_fontTime.setPointSize ( m_fontDate.pointSize() );

    m_useCustomFontColor = ui.useCustomFontColor->isChecked();
    cg.writeEntry("useCustomFontColor", m_useCustomFontColor);
    if (m_useCustomFontColor) {
        m_fontColor = ui.fontColor->color();
    } else {
        m_fontColor = KColorScheme(QPalette::Active, KColorScheme::View, Plasma::Theme::defaultTheme()->colorScheme()).foreground().color();
    }
    cg.writeEntry("fontColor", ui.fontColor->color());

    m_fontTimeBold = ui.fontTimeBold->isChecked();
    cg.writeEntry("fontTimeBold", m_fontTimeBold);

    m_fontTimeItalic = ui.fontTimeItalic->isChecked();
    cg.writeEntry("fontTimeItalic", m_fontTimeItalic);

    m_fontTime.setBold(m_fontTimeBold);
    m_fontTime.setItalic(m_fontTimeItalic);

    m_fuzzyness = ui.fuzzynessSlider->value();
    cg.writeEntry("fuzzyness", m_fuzzyness);

    m_showDate = ui.showDate->isChecked();
    cg.writeEntry("showDate", m_showDate);
    m_showYear = ui.showYear->isChecked();
    cg.writeEntry("showYear", m_showYear);
    m_showDay = ui.showDay->isChecked();
    cg.writeEntry("showDay", m_showDay);

    m_adjustToHeight = ui.adjustToHeight->value();
    kDebug() << "adjustToHeight" << m_adjustToHeight;

    cg.writeEntry("adjustToHeight", m_adjustToHeight);

    m_showTimezone = ui.showTimezone->isChecked();
    cg.writeEntry("showTimezone", m_showTimezone);

    dataEngine("time")->connectSource(currentTimezone(), this, 6000, Plasma::AlignToMinute);

    m_configUpdated = true;
    updateConstraints();

    emit configNeedsSaving();
}

void Clock::changeEngineTimezone(const QString &oldTimezone, const QString &newTimezone)
{
    dataEngine("time")->disconnectSource(oldTimezone, this);
    dataEngine("time")->connectSource(newTimezone, this, 6000, Plasma::AlignToMinute);
}

void Clock::calculateDateString()
{
    if (!m_date.isValid() || ( m_showTimezone == false && m_showDate == false) ) {
            return;
        }

    QString day = KGlobal::locale()->calendar()->formatDate(m_date, KLocale::Day, KLocale::ShortNumber);
    QString month = KGlobal::locale()->calendar()->formatDate(m_date, KLocale::Month, KLocale::ShortName);
    QString year = KGlobal::locale()->calendar()->formatDate(m_date, KLocale::Year, KLocale::LongNumber);

    //Copied from the digital-clock
    if (m_showDate) {
        if (m_showYear) {
            m_dateString = i18nc("@label Short date: "
                                "%1 day in the month, %2 short month name, %3 year",
                                "%1 %2 %3", day, month, year);
        }
        else {
            m_dateString = i18nc("@label Short date: "
                                "%1 day in the month, %2 short month name",
                                "%1 %2", day, month);
        }
        if (m_showDay) {
            QString weekday = KGlobal::locale()->calendar()->formatDate(m_date, KLocale::DayOfWeek, KLocale::ShortName);
            m_dateString = i18nc("@label Day of the week with date: "
                                "%1 short day name, %2 short date",
                                "%1, %2", weekday, m_dateString);
        }
    }

//     QString newDateString = m_locale->formatDate ( m_date , m_locale->ShortDate );

//     if( m_showDate == true ) {
//         m_dateString = newDateString;
//     }

    if( m_showTimezone == true ) {
        QString timezonetranslated = i18n( currentTimezone().toUtf8().data());
        timezonetranslated = timezonetranslated.replace('_', ' ');
        m_timezoneString = '(' + timezonetranslated  + ')';
    }
}

void Clock::initFuzzyTimeStrings()
{
    m_hourNames   << i18nc("hour in the messages below","one")
                << i18nc("hour in the messages below","two")
                << i18nc("hour in the messages below","three")
                << i18nc("hour in the messages below","four")
                << i18nc("hour in the messages below","five")
                << i18nc("hour in the messages below","six")
                << i18nc("hour in the messages below","seven")
                << i18nc("hour in the messages below","eight")
                << i18nc("hour in the messages below","nine")
                << i18nc("hour in the messages below","ten")
                << i18nc("hour in the messages below","eleven")
                << i18nc("hour in the messages below","twelve");

    m_normalFuzzy << ki18nc("%1 the hour translated above","%1 o'clock")
                << ki18nc("%1 the hour translated above","five past %1")
                << ki18nc("%1 the hour translated above","ten past %1")
                << ki18nc("%1 the hour translated above","quarter past %1")
                << ki18nc("%1 the hour translated above","twenty past %1")
                << ki18nc("%1 the hour translated above","twenty five past %1")
                << ki18nc("%1 the hour translated above","half past %1")
                << ki18nc("%1 the hour translated above","twenty five to %1")
                << ki18nc("%1 the hour translated above","twenty to %1")
                << ki18nc("%1 the hour translated above","quarter to %1")
                << ki18nc("%1 the hour translated above","ten to %1")
                << ki18nc("%1 the hour translated above","five to %1")
                << ki18nc("%1 the hour translated above","%1 o'clock");

    m_dayTime << i18n("Night")
            << i18n("Early morning") << i18n("Morning") << i18n("Almost noon")
            << i18n("Noon") << i18n("Afternoon") << i18n("Evening")
            << i18n("Late evening");

    m_weekTime << i18n("Start of week")
               << i18n("Middle of week")
               << i18n("End of week")
               << i18n("Weekend!");
}

void Clock::calculateTimeString()
{
    if (!m_time.isValid()) {
        return;
    }

    const int hours = m_time.hour();
// int hours = 1;
    const int minutes = m_time.minute();
// int minutes = 0;

    bool upcaseFirst = i18nc("Whether to uppercase the first letter of "
                             "completed fuzzy time strings above: "
                             "translate as 1 if yes, 0 if no.",
                             "1") != QString('0');

    //Create time-string
    QString newTimeString;

    if (m_fuzzyness == 1 || m_fuzzyness == 2) {
        // NOTE: Time strings are deliberately assembled here with English
        // only in mind: translators are able to script the translation to
        // their liking, and this code provides the least surprise for that.
        // Those inquiring should be directed to kde-i18n-doc mailing list
        // for instructions on how to make it right for their language.

        int sector = 0;
        int realHour = 0;

        if (m_fuzzyness == 1) {
            if (minutes > 2) {
                sector = (minutes - 3) / 5 + 1;
            }
        } else {
            if (minutes > 6) {
                sector = ((minutes - 7) / 15 + 1) * 3;
            }
        }

        int deltaHour = (sector <= 6 ? 0 : 1);
        if ((hours + deltaHour) % 12 > 0) { //there is a modulo
            realHour = (hours + deltaHour) % 12 - 1;
        } else {
            realHour = 12 - ((hours + deltaHour) % 12 + 1);
        }

        newTimeString = m_normalFuzzy[sector].subs(m_hourNames[realHour]).toString();
        if (upcaseFirst) {
            newTimeString.replace(0, 1, QString(newTimeString.at(0).toUpper()));
        }
    } else if (m_fuzzyness == 3) {
        newTimeString = m_dayTime[hours / 3];
    } else {
        //Timezones not yet implemented: int dow = QDateTime::currentDateTime().addSecs(TZoffset).date().dayOfWeek();
        int dow = QDateTime::currentDateTime().date().dayOfWeek();

        int weekStrIdx;
        if (dow == 1) {
            weekStrIdx = 0;
        }
        else if (dow >= 2 && dow <= 4) {
            weekStrIdx = 1;
        }
        else if (dow == 5) {
            weekStrIdx = 2;
        }
        else {
            weekStrIdx = 3;
        }

        newTimeString = m_weekTime[weekStrIdx];
    }

    m_timeString = newTimeString;
}

void Clock::calculateSize()
{
    //Minimal sizes.
    // QFont minimalFontTime = m_fontTime;
    // minimalFontTime.setPointsize ( m_fontDate.pointsize() );
    // QFontMetrics fmMinimalTime ( minimalFontTime );
    //
    // minimalTimeStringSize = QSizeF( minimalFontTime.width( m_timeString ) + m_margin*2,minimalFontTime.height() );

    //In case adjustToHeight was disabled we have to reset the point-size of fontTime
    m_fontTime.setPointSize ( m_fontDate.pointSize() );

    //Actual size, set in config or init
    QFontMetrics m_fmTime ( m_fontTime );
    m_timeStringSize = QSizeF( m_fmTime.width( m_timeString ) + m_margin*2,m_fmTime.height() );

    QFontMetrics m_fmDate ( m_fontDate );

    //The date+timezone are currently hardcoded to the smallestReadableFont
    m_dateStringSize = QSizeF ( m_fmDate.width( m_dateString ), m_fmDate.height() );
    m_timezoneStringSize = QSizeF( m_fmDate.width( m_timezoneString ), m_fmDate.height() );

    int minimumWantedSize = KGlobalSettings::smallestReadableFont().pointSize();
    if (formFactor() == Plasma::Horizontal) {
        QFont font(m_fontTime);
        font.setPixelSize(size().height()/2);
        QFontInfo fi(font);
        minimumWantedSize = fi.pointSize();
    }


    if ( contentsRect().size().width() > m_timeStringSize.width() && (formFactor() == Plasma::Planar || formFactor() == Plasma::MediaCenter)) { //plasmoid wider than timestring
        kDebug() << "Plasmoid wider than the timestring";
        if( m_showDate == true && m_showTimezone == true ) { //date + timezone enabled
            kDebug() << "Date + Timezone enabled";
            if ( contentsRect().size().width() > m_dateStringSize.width() +  m_timezoneStringSize.width() ) { //date + timezone fit -> 2 rows within the plasmoid

                kDebug() << "plasmoid wider than date + timezone in 1 row";
                m_subtitleString = m_dateString + ' ' + m_timezoneString; //Set subtitleString

                //set subtitleSize
                m_subtitleStringSize = QSizeF ( m_fmDate.width ( m_dateString + ' ' + m_timezoneString ) , m_dateStringSize.height()*1 );
            } else { //date + timezone are split into two lines to fit the plasmoid -> 3 rows within the plasmoid
                kDebug() << "Plasmoid not wide enough for date + timezone in 1 row -> 2 rows";
                m_subtitleString = m_dateString + '\n' + m_timezoneString; //Set subtitleString

                //set subtitleSize
                m_subtitleStringSize = QSizeF ( qMax( m_dateStringSize.width(),m_timezoneStringSize.width() ) , m_dateStringSize.height()*2 );
            }
        } else if ( m_showDate == true ) {
            kDebug() << "Only Date enabled";
            m_subtitleString = m_dateString; //Set subtitleString

            //set subtitleSize
            m_subtitleStringSize = QSizeF ( m_dateStringSize.width() , m_dateStringSize.height() );
        } else if ( m_showTimezone == true ) {
            kDebug() << "Only timezone enabled";
            m_subtitleString = m_timezoneString; //Set subtitleString

            //set subtitleSize
            m_subtitleStringSize = QSizeF ( m_timezoneStringSize.width() , m_timezoneStringSize.height() );
        } else { //no subtitle
            kDebug() << "Neither date nor timezone enabled";
            m_subtitleStringSize = QSizeF ( 0,0 );
        }

    //     //If the date/timezone was re-enabled we might have a wide enough, but not high enough plasmoid whose minimumContentSize only fits the timestring. -> increase minimumContentSize
        if ( m_timeStringSize.height() + m_verticalSpacing + m_subtitleStringSize.height() > minimumSize().height() ) {
            kDebug() << "Although the plasmoid is wider than necessary the height is too small -> set new minimum height: " << m_timeStringSize.height() + m_verticalSpacing + m_subtitleStringSize.height();
            setMinimumSize ( QSizeF ( minimumSize().width(),m_timeStringSize.height() + m_verticalSpacing + m_subtitleStringSize.height() ) );

            kDebug() << "New minimumContentSize(): " << minimumSize();
        }

        //Make the timestring fit the plasmoid since it is bigger than minimumWantedSize
        m_fontTime.setPointSize(qMax((int)( geometry().size().height()/1.5), minimumWantedSize) );

        m_fmTime = QFontMetrics( m_fontTime );

        while ( ( m_fmTime.width( m_timeString ) > contentsRect().size().width() - 2*m_margin ||
                m_fmTime.height() > contentsRect().size().height() - m_subtitleStringSize.height() - m_verticalSpacing ) &&
                m_fontTime.pointSize() > minimumWantedSize) {

            //decrease pointSize
            m_fontTime.setPointSize(m_fontTime.pointSize() - 1);

            m_fmTime = QFontMetrics( m_fontTime );

            m_timeStringSize = QSizeF ( m_fmTime.width( m_timeString ),  m_fmTime.height() );
        }

        //Adjust the height to the new horizontal size
        m_contentSize = QSizeF ( contentsRect().width(),m_timeStringSize.height() + m_verticalSpacing + m_subtitleStringSize.height() );

        if ( formFactor() == Plasma::Horizontal ) { //if we are on the panel we are forced to accept the given height.
            kDebug() << "needed height: " << m_contentSize.height() << "fixed height forced on us: " << geometry().size().height();
            //FIXME: it was resizing to size() itself
            //resize ( QSizeF ( m_contentSize.width(),geometry().size().height() ) );
        } else {
            //add margins
            resize(m_contentSize + QSizeF(size()-contentsRect().size()));
            setPreferredSize(m_contentSize + QSizeF(size()-contentsRect().size()));
            resize(preferredSize());
            emit sizeHintChanged(Qt::PreferredSize);
            emit appletTransformedItself();
        }

    } else { //in a panel or timestring wider than plasmoid -> change size to the minimal needed space, i.e. the timestring will not increase in point-size OR plasmoid in Panel.

        kDebug() << "Plasmoid is in a panel or too small for the timestring, we are using minimumWantedSize as pointSize";

        if ( m_showDate == true && m_showTimezone == true ) { //Date + timezone enabled
            kDebug() << "Date + timezone enabled";

            //If the user has set adjustToHeight to true the timezone and date are put into one line. This is a design decision and not based on anything else but the opinion that a slightly increased point-size is not what adjustToHeight is meant for. The latter is meant to replace the need to be able to set a font-size in the settings. Bigger fonts than this and only slightly bigger ones don't make sense on the panel. The desktop-plasmoid is not imfluenced by this.
            if( m_timeStringSize.width() > m_dateStringSize.width() +  m_timezoneStringSize.width() || m_adjustToHeight != 0 ) { //Time wider than date + timezone -> 2 rows in plasmoid
                kDebug() << "timestring is wider than date + timezone in one row -> 1 row.";
                m_subtitleString = m_dateString + ' ' + m_timezoneString; //Set subtitleString

                //set subtitleSize
                m_subtitleStringSize = QSizeF ( m_fmDate.width ( m_dateString + ' ' + m_timezoneString ) , m_dateStringSize.height()*1 );

                //set new minimal width to fit the strings
                m_minimumContentSize = QSizeF ( m_timeStringSize.width(),m_subtitleStringSize.height() + m_verticalSpacing + m_subtitleStringSize.height() );
            } else { //date and timezone have to be split.
                kDebug() << "Date + timezone do not fit into one row -> 2 rows.";
                m_subtitleString = m_dateString + '\n' + m_timezoneString; //Set subtitleString

                //set subtitleSize
                m_subtitleStringSize = QSizeF ( qMax ( m_dateStringSize.width(),m_timezoneStringSize.width() ), m_dateStringSize.height()*2 );

                kDebug() << "max: " << qMax ( m_timeStringSize.width(),qMax ( m_dateStringSize.width(),m_timezoneStringSize.width() ) ) << " timestring: " << m_timeStringSize.width() << "date: " << m_dateStringSize.width() << "timezone: " << m_timezoneStringSize.width();

                //set new minimal width to fit widest string and adjust the height
                m_minimumContentSize = QSizeF ( qMax ( m_timeStringSize.width(),qMax ( m_dateStringSize.width(),m_timezoneStringSize.width() ) ),m_timeStringSize.height() + m_verticalSpacing + m_subtitleStringSize.height() );
            }
        } else if ( m_showDate == true ) {
            kDebug() << "Only date is enabled";
            m_subtitleString = m_dateString; //Set subtitleString

            //set subtitleSize
            m_subtitleStringSize = QSizeF ( m_dateStringSize.width(), m_dateStringSize.height() );

            //set new minimal width to fit the widest string
            m_minimumContentSize = QSizeF ( qMax ( m_dateStringSize.width(),m_timeStringSize.width() ),m_timeStringSize.height() + m_verticalSpacing + m_subtitleStringSize.height() );
        } else if ( m_showTimezone == true ) {
            kDebug() << "Only timezone is enabled";
            m_subtitleString = m_timezoneString; //Set subtitleString

            //set subtitleSize
            m_subtitleStringSize = QSizeF ( m_timezoneStringSize.width(), m_timezoneStringSize.height() );

            //set new size to fit the strings
            m_minimumContentSize = QSizeF ( qMax ( m_timezoneStringSize.width(),m_timeStringSize.width() ),m_timeStringSize.height() + m_verticalSpacing + m_subtitleStringSize.height() );
        } else { //no subtitle
            kDebug() << "Neither timezone nor date are enabled";
            //set subtitleSize
            m_subtitleStringSize = QSizeF ( 0,0 );

            m_minimumContentSize = QSizeF ( m_timeStringSize.width(),m_timeStringSize.height() );//set new minimal width
        }

        float heightToUse = 0;

        //Use x of the available height for the timstring
        if ( m_adjustToHeight == 1 ) {
            heightToUse = (float)2/3;
            kDebug() << "We will use 2/3 of the panel's height for the time: " << heightToUse;
        } else if ( m_adjustToHeight == 2 ) {
            kDebug() << "We will use all of the panel's height for the time.";
            heightToUse = 1;
        }

        //If the user enabled adjustToHeight we increase the point-size until the height is fully used. 40 as limit to avoid an endless loop.
        if ( m_adjustToHeight != 0 ) {
            kDebug() << "We try to find a larger font that fits the size:";

            //FIXME: if the clock is the only applet on a vertical panel and returns 0 via expandingDirections(), it still gets the full height of the panel as recommended height, i.e. on a vertical panel width a height of 800, geometry().size().height() does not return 48 but some huge value. Unless this is fixed in plasma, the while-loop will take a while.

            //Make the timestring fit the plasmoid since it is bigger than minimumWantedSize
            m_fontTime.setPointSize(qMax((int)( geometry().size().height()/1.5), minimumWantedSize) );
        
            m_fmTime = QFontMetrics( m_fontTime );
        
            kDebug() << "Starting with a point size of: " << m_fontTime.pointSize();

            kDebug() << "We want to have: \nwidth: < " << geometry().size().width() - 2*m_margin << "\nheight < " << (geometry().size().height() - m_subtitleStringSize.height() - m_verticalSpacing)*heightToUse;

            while ( ( ( m_fmTime.width( m_timeString ) > geometry().size().width() - 2*m_margin && formFactor() != Plasma::Horizontal ) ||
                    m_fmTime.height() > (geometry().size().height() - m_subtitleStringSize.height() - m_verticalSpacing)*heightToUse ) &&
                    m_fontTime.pointSize() > minimumWantedSize) {
        
                //decrease pointSize
                m_fontTime.setPointSize(m_fontTime.pointSize() - 1);

                kDebug() << "new point size: " << m_fontTime.pointSize();
        
                m_fmTime = QFontMetrics( m_fontTime );
        
                m_timeStringSize = QSizeF ( m_fmTime.width( m_timeString ),  m_fmTime.height() );
            }
        }

        //Adjust the width to the new size, including margins, will be reverted, if the panel is vertical
        m_minimumContentSize = QSizeF ( m_timeStringSize.width() + m_margin*2,m_minimumContentSize.height() );

        kDebug() << "Set new minimumSize: geometry().size() " << geometry().size() << "\nm_minimumContentSize: " << m_minimumContentSize;

        //if the width given by the panel is too wide, e.g. when switching from panel at the right to panel at the bottom we get some 600 as width
        //However: If we are in a vertical panel, we should use the width given.
        if( m_timeStringSize.width() + m_margin*2 < geometry().size().width() && formFactor() != Plasma::Vertical ) {
                kDebug() << "The width we got was too big, we need less, so lets resize.";
                setMinimumSize ( m_minimumContentSize + (size() - contentsRect().size()) );
            }

        if ( formFactor() == Plasma::Horizontal ) { //if we are on the panel we are forced to accept the given height.
            kDebug() << "needed height: " << m_minimumContentSize.height() << "[horizontal panel] fixed height forced on us: " << geometry().size().height() << " adding margin-left/-right of: " << m_margin << "width is going to be set resize( " << m_minimumContentSize.width() << "," << geometry().size().height() << ")";

            setMinimumSize(QSizeF(m_minimumContentSize.width(), 0));
            //Expand the panel as necessary
            setPreferredSize(minimumSize());
            emit sizeHintChanged(Qt::PreferredSize);
        } else if ( formFactor() == Plasma::Vertical ) {
            kDebug() << "needed width: " << m_minimumContentSize.width() << "[vertical panel] fixed width forced on us: " << geometry().size().width() << " adding margin left/right of: " << m_margin;

            setMinimumSize ( QSizeF(0, m_minimumContentSize.height()) );
            //Expand the panel as necessary
            setPreferredSize(minimumSize());
            emit sizeHintChanged(Qt::PreferredSize);
        }else { //FIXME: In case this height does not fit the content -> disable timezone (and date)
            //if the minimal width is larger than the actual size -> force minimal needed width
            if( m_fontTime.pointSize() <= m_fontDate.pointSize() ) {
                setMinimumSize ( m_minimumContentSize + (size() - contentsRect().size()) );
            }

            //we use the minimal height here, since the user has given us too much height we cannot use for anything useful. minimal width because we are in a panel.
            kDebug() << "we set the minimum size needed as the size we want";
            setPreferredSize ( QSizeF ( m_minimumContentSize.width() + m_margin*2,m_minimumContentSize.height() ) + (size() - contentsRect().size()) );
            resize(preferredSize());
            emit sizeHintChanged(Qt::PreferredSize);
            emit appletTransformedItself();
        }
    }
}

void Clock::paintInterface(QPainter *p, const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
{
    Q_UNUSED( option );

    kDebug() << "We get painted!";

    if( m_showDate == true || m_showTimezone == true ) {

        m_fontDate = QFont( KGlobalSettings::smallestReadableFont() );
        QFontMetrics m_fmDate( m_fontDate );
        p->setPen(QPen(m_fontColor));
        p->setFont( m_fontDate );

        kDebug() << "date + timezone [" << m_subtitleString << "] gets painted. y: " << -m_subtitleStringSize.height() + contentsRect.size().height() << "width: " << contentsRect.size().width() << "[needed: " << m_fmDate.width( m_subtitleString ) << "] " << "height:" << m_subtitleStringSize.height();

        if( m_showDate == true || m_showTimezone == true ) {
        //Draw the subtitle
        p->drawText( QRectF(contentsRect.x(),
                contentsRect.y() - m_subtitleStringSize.height() + contentsRect.size().height(),
                contentsRect.size().width(),
                m_subtitleStringSize.height()) ,
            m_subtitleString,
            QTextOption(Qt::AlignHCenter)
            );
        }
    }

        QFontMetrics m_fmTime ( m_fontTime );

        kDebug() << "timestrings [" << m_timeString << "] gets painted. width: " << contentsRect.size().width() << "[needed: " << m_fmTime.width( m_timeString ) << "] " << "height: " << m_timeStringSize.height();

        p->setFont( m_fontTime );
        p->setPen(QPen(m_fontColor));
        p->setRenderHint(QPainter::SmoothPixmapTransform);
        p->setRenderHint(QPainter::Antialiasing);

        p->drawText( QRectF(contentsRect.x(),
                contentsRect.y(),
                contentsRect.size().width(),
                m_timeStringSize.height()) ,
            m_timeString,
            QTextOption(Qt::AlignHCenter)
            );
}

void Clock::updateColors()
{
    if (!m_useCustomFontColor) {
        m_fontColor = KColorScheme(QPalette::Active, KColorScheme::View, Plasma::Theme::defaultTheme()->colorScheme()).foreground().color();
        update();
    }
}

#include "fuzzyClock.moc"
