/*
 * Plasma applet to display indicators from libindicate
 *
 * Copyright 2009 Canonical Ltd.
 *
 * Authors:
 * - Aurélien Gâteau <aurelien.gateau@canonical.com>
 *
 * License: GPL v3
 */
#include "delegate.h"

// Qt
#include <QApplication>
#include <QDebug>
#include <QPainter>
#include <QTime>
#include <QVariant>

// KDE
#include <KDebug>

// Local
#include "listenermodel.h"
#include "timeutils.h"

static const int SEPARATOR_HEIGHT = 6;
static const int VSPACING = 2;

static const qreal SECONDARY_TEXT_OPACITY = .7;

// Copied from KFileItemDelegate
static QPainterPath roundedRectangle(const QRectF &rect, qreal radius)
{
    QPainterPath path(QPointF(rect.left(), rect.top() + radius));
    path.quadTo(rect.left(), rect.top(), rect.left() + radius, rect.top());         // Top left corner
    path.lineTo(rect.right() - radius, rect.top());                                 // Top side
    path.quadTo(rect.right(), rect.top(), rect.right(), rect.top() + radius);       // Top right corner
    path.lineTo(rect.right(), rect.bottom() - radius);                              // Right side
    path.quadTo(rect.right(), rect.bottom(), rect.right() - radius, rect.bottom()); // Bottom right corner
    path.lineTo(rect.left() + radius, rect.bottom());                               // Bottom side
    path.quadTo(rect.left(), rect.bottom(), rect.left(), rect.bottom() - radius);   // Bottom left corner
    path.closeSubpath();

    return path;
}

Delegate::Delegate(QObject* parent)
: QStyledItemDelegate(parent)
{
}

inline QString timeTextForIndex(const QModelIndex& index)
{
    if (index.parent().isValid()) {
        // Indicator
        QDateTime dateTime = index.data(ListenerModel::IndicatorDateTimeRole).toDateTime();
        if (dateTime.isValid()) {
            return TimeUtils::formatDateTime(dateTime);
        }
    }
    return QString();
}

void Delegate::paint(QPainter* painter, const QStyleOptionViewItem& _option, const QModelIndex& index) const
{
    QStyleOptionViewItem option = _option;

    bool paintSeparator = false;
    if (!index.parent().isValid() && index.row() > 0) {
        paintSeparator = true;
        option.rect.adjust(0, SEPARATOR_HEIGHT, 0, 0);
    }

    QStyledItemDelegate::paint(painter, option, index);
    if (paintSeparator) {
        //painter->drawLine(option.rect.left(), yPos, option.rect.right(), yPos);
    }

    int count = index.data(ListenerModel::CountRole).toInt();
    if (count > 0) {
        paintCount(painter, option, count);
    } else {
        QString timeText = timeTextForIndex(index);
        if (!timeText.isEmpty()) {
            paintTime(painter, option, timeText);
        }
    }
}

void Delegate::paintTime(QPainter* painter, const QStyleOptionViewItem& option, const QString& text) const
{
    painter->save();

    const int outerMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin, &option);
    QRectF rect = option.rect.adjusted(0, 0, -outerMargin, 0);

    QColor fg;
    if (option.state & QStyle::State_Selected) {
        fg = option.palette.color(QPalette::HighlightedText);
    } else {
        fg = option.palette.color(QPalette::Text);
    }
    fg.setAlphaF(SECONDARY_TEXT_OPACITY);

    painter->setPen(fg);
    painter->drawText(rect, Qt::AlignRight | Qt::AlignVCenter, text);

    painter->restore();
}

void Delegate::paintCount(QPainter* painter, const QStyleOptionViewItem& option, int count) const
{
    painter->save();

    QString text = QString::number(count);

    const int outerMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin, &option);
    const qreal radius = option.rect.height() / 2. - 2 * outerMargin;
    const qreal bgWidth = QFontMetrics(option.font).width(text) + 1.618 * radius;
    QRectF rect = QRectF(
        option.rect.right() - outerMargin - bgWidth,
        option.rect.top() + 2 * outerMargin,
        bgWidth,
        2 * radius
        );
    rect.adjust(-.5, -.5, .5, .5);
    const QPainterPath path = roundedRectangle(rect, radius);

    // Colors
    QColor bg, fg;
    bg = QColor::fromRgbF(0, 0, 0, .1);
    if (option.state & QStyle::State_Selected) {
        fg = option.palette.color(QPalette::HighlightedText);
    } else {
        fg = option.palette.color(QPalette::Text);
    }
    fg.setAlphaF(SECONDARY_TEXT_OPACITY);
    QColor borderColor = bg;
    borderColor.setAlphaF(.2);

    // Draw
    painter->setRenderHint(QPainter::Antialiasing);
    painter->fillPath(path, bg);
    painter->setPen(QPen(borderColor, .5));
    painter->drawPath(path);
    painter->setPen(fg);
    painter->drawText(rect, Qt::AlignHCenter | Qt::AlignVCenter, text);
    painter->restore();
}

QSize Delegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
    QSize sh = QStyledItemDelegate::sizeHint(option, index);
    sh.rheight() += VSPACING * 2;

    QString extraText;
    int count = index.data(ListenerModel::CountRole).toInt();
    if (count > 0) {
        extraText = " " + QString::number(count);
    } else {
        extraText = "  " + timeTextForIndex(index);
    }

    if (!extraText.isEmpty()) {
        sh.rwidth() += QFontMetrics(option.font).width(extraText);
    }

    if (!index.parent().isValid() && index.row() != 0) {
        // A server item, but not the first one. Keep room for the separator
        sh.rheight() += SEPARATOR_HEIGHT;
    }
    return sh;
}
