/*
 * Qt wrapper for libindicate
 *
 * Copyright 2009 Canonical Ltd.
 *
 * Authors:
 * - Aurélien Gâteau <aurelien.gateau@canonical.com>
 *
 * License: LGPL v2.1 or LGPL v3
 */
// Self
#include "qindicateindicator.h"

// Qt
#include <QBuffer>
#include <QByteArray>
#include <QDateTime>
#include <QDebug>
#include <QHash>
#include <QImage>
#include <QStringList>

// libindicate
#include <libindicate/indicator.h>
#include <libindicate/indicator-messages.h>

// Local
#include "qindicatedecode.h"

namespace QIndicate
{

static QHash<IndicateIndicator*, Indicator*> sQIndicatorFromGIndicator;

static void displayCallBack(IndicateIndicator* indicator, gpointer data)
{
    Indicator* qIndicator = sQIndicatorFromGIndicator[indicator];
    QMetaObject::invokeMethod(qIndicator, "display", Q_ARG(QIndicate::Indicator*, qIndicator));
}

struct IndicatorPrivate
{
    Indicator* q;
    IndicateIndicator* mGIndicator;

    IndicatorPrivate(Indicator* _q, IndicateIndicator* gIndicator)
    {
        q = _q;
        mGIndicator = gIndicator;
        sQIndicatorFromGIndicator[mGIndicator] = q;
        g_signal_connect(G_OBJECT(mGIndicator), INDICATE_INDICATOR_SIGNAL_DISPLAY, G_CALLBACK(displayCallBack), NULL);
    }
};

Indicator::Indicator(QObject* parent)
: QObject(parent)
, d(new IndicatorPrivate(this, indicate_indicator_new()))
{
}

Indicator::Indicator(IndicateIndicator* gIndicator, QObject* parent)
: QObject(parent)
, d(new IndicatorPrivate(this, gIndicator))
{
}

IndicateIndicator* Indicator::gIndicator()
{
    return d->mGIndicator;
}


Indicator::~Indicator()
{
    sQIndicatorFromGIndicator.remove(d->mGIndicator);
    g_object_unref(d->mGIndicator);
    delete d;
}

void Indicator::setIndicatorProperty(const QString& key, const char* value)
{
    indicate_indicator_set_property(INDICATE_INDICATOR(d->mGIndicator),
        key.toUtf8().data(),
        value);
}

void Indicator::setIndicatorProperty(const QString& key, const QString& value)
{
    indicate_indicator_set_property(INDICATE_INDICATOR(d->mGIndicator),
        key.toUtf8().data(),
        value.toUtf8().data());
}

void Indicator::setIndicatorProperty(const QString& key, const QDateTime& value)
{
    GTimeVal gTime;
    gTime.tv_sec = value.toTime_t();
    gTime.tv_usec = 1000 * value.time().msec();
    indicate_indicator_set_property_time(INDICATE_INDICATOR(d->mGIndicator), key.toUtf8().data(), &gTime);
}

void Indicator::setIndicatorProperty(const QString& key, const QImage& image)
{
    QBuffer buffer;
    buffer.open(QIODevice::WriteOnly);
    image.save(&buffer, "png");
    QByteArray value = buffer.data().toBase64();

    indicate_indicator_set_property(INDICATE_INDICATOR(d->mGIndicator),
        key.toUtf8().data(),
        value.data());
}

void Indicator::setIndicatorProperty(const QString& key, bool value)
{
    indicate_indicator_set_property_bool(
        INDICATE_INDICATOR(d->mGIndicator),
        key.toUtf8().data(), value);
}

void Indicator::setIndicatorProperty(const QString& key, int value)
{
    indicate_indicator_set_property_int(
        INDICATE_INDICATOR(d->mGIndicator),
        key.toUtf8().data(), value);
}

QByteArray Indicator::indicatorProperty(const QString& key) const
{
    const gchar* value = indicate_indicator_get_property(d->mGIndicator, key.toUtf8().data());
    return QByteArray(value);
}

QDateTime Indicator::dateTimeIndicatorProperty(const QString& key) const
{
    GVariant* variant = indicate_indicator_get_property_variant(d->mGIndicator, key.toUtf8().data());
    return variant ? Decode::dateTimeFromValue(g_variant_get_string(variant, 0)): QDateTime();
}

int Indicator::intIndicatorProperty(const QString& key, int defaultValue) const
{
    GVariant* variant = indicate_indicator_get_property_variant(d->mGIndicator, key.toUtf8().data());
    return variant ? g_variant_get_int32(variant) : defaultValue;
}

bool Indicator::boolIndicatorProperty(const QString& key, bool defaultValue) const
{
    GVariant* variant = indicate_indicator_get_property_variant(d->mGIndicator, key.toUtf8().data());
    return variant ? g_variant_get_boolean(variant) : defaultValue;
}

static void propertyList_helper(gchar* _item, QStringList* list)
{
    *list << QString::fromUtf8(_item);
    g_free(_item);
}

QStringList Indicator::propertyList() const
{
    GPtrArray* array = indicate_indicator_list_properties(d->mGIndicator);
    QStringList list;
    g_ptr_array_foreach(array, GFunc(propertyList_helper), &list);
    g_ptr_array_free(array, TRUE);
    return list;
}

void Indicator::show()
{
    indicate_indicator_show(d->mGIndicator);
}

void Indicator::hide()
{
    indicate_indicator_hide(d->mGIndicator);
}

uint Indicator::id() const
{
    return indicate_indicator_get_id(d->mGIndicator);
}

QImage Indicator::iconProperty() const
{
    return Decode::imageFromValue(indicatorProperty(INDICATE_INDICATOR_MESSAGES_PROP_ICON));
}

void Indicator::setIconProperty(const QImage& value)
{
    setIndicatorProperty(INDICATE_INDICATOR_MESSAGES_PROP_ICON, value);
}

QDateTime Indicator::timeProperty() const
{
    return dateTimeIndicatorProperty(INDICATE_INDICATOR_MESSAGES_PROP_TIME);
}

void Indicator::setTimeProperty(const QDateTime& value)
{
    setIndicatorProperty(INDICATE_INDICATOR_MESSAGES_PROP_TIME, value);
}

QString Indicator::nameProperty() const
{
    return Decode::stringFromValue(indicatorProperty(INDICATE_INDICATOR_MESSAGES_PROP_NAME));
}

void Indicator::setNameProperty(const QString& value)
{
    setIndicatorProperty(INDICATE_INDICATOR_MESSAGES_PROP_NAME, value);
}

int Indicator::countProperty() const
{
    return intIndicatorProperty(INDICATE_INDICATOR_MESSAGES_PROP_COUNT);
}

void Indicator::setCountProperty(int value)
{
    setIndicatorProperty(INDICATE_INDICATOR_MESSAGES_PROP_COUNT, (value == 0 ? "" : QString::number(value)));
}

void Indicator::setDrawAttentionProperty(bool value)
{
    setIndicatorProperty(INDICATE_INDICATOR_MESSAGES_PROP_ATTENTION, value);
}

bool Indicator::drawAttentionProperty() const
{
    return boolIndicatorProperty(INDICATE_INDICATOR_MESSAGES_PROP_ATTENTION);
}

void Indicator::emitDisplay()
{
    uint timestamp = QDateTime::currentDateTime().toTime_t();
    indicate_indicator_user_display(d->mGIndicator, timestamp);
}

} // namespace

#include "qindicateindicator.moc"
