/*
 * 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 "qindicateserver.h"
#include "qindicateindicator.h"

// Qt
#include <QCoreApplication>
#include <QDebug>
#include <QHash>
#include <QPointer>

// libindicate
#include <libindicate/server.h>

namespace QIndicate
{

static QHash<IndicateServer*, Server*> sQServerFromGServer;
static QPointer<Server> sDefaultInstance;

struct ServerPrivate
{
    IndicateServer* mGServer;
};

static void serverShowCB(IndicateServer* server, gchar* _type)
{
    Server* qServer = sQServerFromGServer[server];
    QString type = QString::fromUtf8(_type);
    QMetaObject::invokeMethod(qServer, "serverShow", Q_ARG(QString, type));
}

static void serverHideCB(IndicateServer* server, gchar* _type)
{
    Server* qServer = sQServerFromGServer[server];
    QString type = QString::fromUtf8(_type);
    QMetaObject::invokeMethod(qServer, "serverHide", Q_ARG(QString, type));
}

static void serverDisplayCB(IndicateServer* server, gpointer data)
{
    Server* qServer = sQServerFromGServer[server];
    QMetaObject::invokeMethod(qServer, "serverDisplay");
}

static void interestAddedCB(IndicateServer* server, IndicateInterests interest)
{
    Server* qServer = sQServerFromGServer[server];
    QMetaObject::invokeMethod(qServer, "interestAdded", Q_ARG(QIndicate::Interest, Interest(interest)));
}

static void interestRemovedCB(IndicateServer* server, IndicateInterests interest)
{
    Server* qServer = sQServerFromGServer[server];
    QMetaObject::invokeMethod(qServer, "interestRemoved", Q_ARG(QIndicate::Interest, Interest(interest)));
}

static void indicatorAddedCB(IndicateServer* server, guint id)
{
    Server* qServer = sQServerFromGServer[server];
    QMetaObject::invokeMethod(qServer, "indicatorAdded", Q_ARG(uint, id));
}

static void indicatorRemovedCB(IndicateServer* server, guint id)
{
    Server* qServer = sQServerFromGServer[server];
    QMetaObject::invokeMethod(qServer, "indicatorRemoved", Q_ARG(uint, id));
}

static void indicatorModifiedCB(IndicateServer* server, guint id, gchar* _property)
{
    Server* qServer = sQServerFromGServer[server];
    QString property = QString::fromUtf8(_property);
    QMetaObject::invokeMethod(qServer, "indicatorModified", Q_ARG(uint, id), Q_ARG(QString, property));
}

Server::Server(QObject* parent, const QString &path)
: QObject(parent)
, d(new ServerPrivate)
{
    g_type_init();

    // Set the path property on object creation if given
    // indicate_server_new() does not exist!
    if (!path.isNull()) {
        d->mGServer = (IndicateServer*)g_object_new(INDICATE_TYPE_SERVER, "path", path.toStdString().c_str(), NULL);
    } else {
        d->mGServer = (IndicateServer*)g_object_new(INDICATE_TYPE_SERVER, NULL);
    }

    #define gconnect(gsignal, callback) \
        g_signal_connect(G_OBJECT(d->mGServer), gsignal, G_CALLBACK(callback), NULL)
    gconnect(INDICATE_SERVER_SIGNAL_SERVER_SHOW, serverShowCB);
    gconnect(INDICATE_SERVER_SIGNAL_SERVER_HIDE, serverHideCB);

    gconnect(INDICATE_SERVER_SIGNAL_SERVER_DISPLAY, serverDisplayCB);

    gconnect(INDICATE_SERVER_SIGNAL_INTEREST_ADDED, interestAddedCB);
    gconnect(INDICATE_SERVER_SIGNAL_INTEREST_REMOVED, interestRemovedCB);

    gconnect(INDICATE_SERVER_SIGNAL_INDICATOR_ADDED, indicatorAddedCB);
    gconnect(INDICATE_SERVER_SIGNAL_INDICATOR_REMOVED, indicatorRemovedCB);
    gconnect(INDICATE_SERVER_SIGNAL_INDICATOR_MODIFIED, indicatorModifiedCB);
    #undef gconnect

    sQServerFromGServer[d->mGServer] = this;
}

Server::~Server()
{
    sQServerFromGServer.remove(d->mGServer);
    g_object_unref(d->mGServer);
    delete d;
}

Server* Server::defaultInstance()
{
    if (!sDefaultInstance) {
        QObject* parent = QCoreApplication::instance();
        if (!parent) {
            qWarning() << "No QCoreApplication instance found, the default QIndicate::Server instance may be leaked when leaving";
        }
        setDefaultInstance(new Server(parent));
    }
    return sDefaultInstance;
}

void Server::setDefaultInstance(Server* instance)
{
    delete sDefaultInstance;
    sDefaultInstance = instance;
    if (sDefaultInstance) {
        indicate_server_set_default(instance->d->mGServer);
    }
}

void Server::setType(const QString& type)
{
    indicate_server_set_type(d->mGServer, type.toUtf8().data());
}

void Server::setDesktopFile(const QString& desktopFile)
{
    indicate_server_set_desktop_file(d->mGServer, desktopFile.toUtf8().data());
}

void Server::setCount(int count)
{
    indicate_server_set_count(d->mGServer, count);
}

void Server::show()
{
    indicate_server_show(d->mGServer);
}

void Server::hide()
{
    indicate_server_hide(d->mGServer);
}

void Server::addIndicator(Indicator *indicator)
{
    indicate_server_add_indicator(d->mGServer, indicator->gIndicator());
}

void Server::removeIndicator(Indicator *indicator)
{
    indicate_server_remove_indicator(d->mGServer, indicator->gIndicator());
}


};

#include "qindicateserver.moc"
