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

// Qt
#include <QMetaType>
#include <QPainter>
#include <QtTest>

// KDE
#include <qtest_kde.h>
#include <KDebug>

// libindicate-qt
#include <qindicatelistener.h>
#include <qindicateindicator.h>
#include <qindicateserver.h>

const QString SERVER_TYPE = "message";
const QString APP_NAME = "An application using libindicate";

QTEST_KDEMAIN(ListenerModelTest, GUI)

Q_DECLARE_METATYPE(QModelIndex);

void ListenerModelTest::initTestCase()
{
    qRegisterMetaType<QIndicate::Listener::Server*>("QIndicate::Listener::Server*");
    qRegisterMetaType<QIndicate::Listener::Indicator*>("QIndicate::Listener::Indicator*");
    qRegisterMetaType<QModelIndex>("QModelIndex");
}

void ListenerModelTest::init()
{
    mListener = new QIndicate::Listener();

    mModel = new ListenerModel(mListener, QRegExp('^' + SERVER_TYPE));

    mServer = QIndicate::Server::defaultInstance();
    const QString desktopFile = KDESRCDIR "test.desktop";

    mServer->setType(SERVER_TYPE);
    mServer->setDesktopFile(desktopFile);
}

void ListenerModelTest::cleanup()
{
    delete mListener;
    mListener = 0;
    delete mModel;
    mModel = 0;
    delete mServer;
    mServer = 0;
}

void ListenerModelTest::testAddServers()
{
    QCOMPARE(mModel->rowCount(), 0);
    mServer->show();
    QTest::qWait(500);

    QCOMPARE(mModel->rowCount(), 1);
    QString text = mModel->data(mModel->index(0, 0)).toString();
    QCOMPARE(text, APP_NAME);
    QString type = mModel->data(mModel->index(0, 0), ListenerModel::ServerTypeRole).toString();
    QCOMPARE(type, SERVER_TYPE);

    mServer->hide();
    // Probably the same problem as ListenerTest::testServerAddedRemoved
    #if 0
    QTest::qWait(500);
    QCOMPARE(mModel->rowCount(), 0);
    #endif
}

static QImage generateTestImage()
{
    QImage image(22, 22, QImage::Format_RGB32);
    QPainter painter(&image);
    painter.fillRect(image.rect(), Qt::blue);
    painter.fillRect(image.rect().adjusted(4, 4, -4, -4), Qt::black);
    return image;
}

void ListenerModelTest::testAddIndicators()
{
    QImage testImage = generateTestImage();

    // Show server
    mServer->show();
    QTest::qWait(500);

    QCOMPARE(mModel->rowCount(), 1);
    QModelIndex serverIndex = mModel->index(0, 0);
    QCOMPARE(mModel->rowCount(serverIndex), 0);

    // Show an indicator
    QIndicate::Indicator indicator;
    indicator.setIndicatorProperty("name", "John Doe");
    indicator.setIndicatorProperty("icon", testImage);
    indicator.show();
    QTest::qWait(500);

    QCOMPARE(mModel->rowCount(serverIndex), 1);
    QModelIndex indicatorIndex = mModel->index(0, 0, serverIndex);

    // Check text
    QString text = indicatorIndex.data().toString();
    QCOMPARE(text, QString("John Doe"));

    // Check icon
    QVariant variant = indicatorIndex.data(Qt::DecorationRole);
    QCOMPARE(variant.type(), QVariant::Icon);
    QIcon icon = qvariant_cast<QIcon>(variant);
    QImage image = icon.pixmap(testImage.size()).toImage();
    // NOTE: image comes from a QPixmap, so make sure image.depth() and
    // testImage.depth() are the same by creating testImage with the
    // appropriate depth
    QCOMPARE(image, testImage);

    // Hide the indicator, there should not be any row for it anymore
    indicator.hide();
    QTest::qWait(500);
    QCOMPARE(mModel->rowCount(serverIndex), 0);
}

void ListenerModelTest::testAddIndicatorsAfterModel()
{
    // A bit ugly: destroy our server, we will recreate it after
    delete mServer;
    mServer = 0;
    QTest::qWait(500);
    QCOMPARE(mModel->rowCount(), 0);

    // Create server and indicator
    mServer = QIndicate::Server::defaultInstance();
    const QString desktopFile = KDESRCDIR "test.desktop";
    mServer->setType(SERVER_TYPE);
    mServer->setDesktopFile(desktopFile);
    mServer->show();

    QIndicate::Indicator indicator;
    indicator.setIndicatorProperty("name", "John Doe");
    indicator.show();

    QTest::qWait(500);

    // Check server
    QCOMPARE(mModel->rowCount(), 1);
    QModelIndex serverIndex = mModel->index(0, 0);
    QVERIFY(serverIndex.isValid());

    QString text = serverIndex.data().toString();
    QCOMPARE(text, APP_NAME);

    // Check indicator
    QCOMPARE(mModel->rowCount(serverIndex), 1);
    QModelIndex indicatorIndex = mModel->index(0, 0, serverIndex);
    QVERIFY(indicatorIndex.isValid());

    text = indicatorIndex.data().toString();
    QCOMPARE(text, QString("John Doe"));
}

static void getProxies(const QSignalSpy& spy, QIndicate::Listener::Server** server, QIndicate::Listener::Indicator** indicator)
{
    QCOMPARE(spy.count(), 1);
    QVariantList args = spy.first();
    *server = args[0].value<QIndicate::Listener::Server*>();
    *indicator = args[1].value<QIndicate::Listener::Indicator*>();
}

void ListenerModelTest::testGetProxiesFromIndex()
{
    QSignalSpy addedSpy(mListener, SIGNAL(indicatorAdded(QIndicate::Listener::Server*, QIndicate::Listener::Indicator*)));

    // Show server
    mServer->show();

    // Show an indicator
    QIndicate::Indicator indicator;
    indicator.setIndicatorProperty("name", "John Doe");
    indicator.show();
    QTest::qWait(500);

    // Get proxies
    QIndicate::Listener::Server* expectedServer = 0;
    QIndicate::Listener::Indicator* expectedIndicator = 0;
    getProxies(addedSpy, &expectedServer, &expectedIndicator);
    QVERIFY(expectedServer);
    QVERIFY(expectedIndicator);

    // Get indexes
    QModelIndex serverIndex = mModel->index(0, 0);
    QModelIndex indicatorIndex = mModel->index(0, 0, serverIndex);

    QIndicate::Listener::Server* serverProxy = 0;
    QIndicate::Listener::Indicator* indicatorProxy = 0;

    mModel->getProxiesForIndex(QModelIndex(), &serverProxy, &indicatorProxy);
    QVERIFY(!serverProxy);
    QVERIFY(!indicatorProxy);

    mModel->getProxiesForIndex(serverIndex, &serverProxy, &indicatorProxy);
    QCOMPARE(serverProxy, expectedServer);
    QVERIFY(!indicatorProxy);

    mModel->getProxiesForIndex(indicatorIndex, &serverProxy, &indicatorProxy);
    QCOMPARE(serverProxy, expectedServer);
    QCOMPARE(indicatorProxy, expectedIndicator);
}

static QDateTime indicatorDateTime(const QModelIndex& index)
{
    QVariant value = index.data(ListenerModel::IndicatorDateTimeRole);
    if (!value.canConvert(QVariant::DateTime)) {
        return QDateTime();
    }
    return value.toDateTime();
}

static bool indicatorDrawAttention(const QModelIndex& index)
{
    QVariant value = index.data(ListenerModel::IndicatorDrawAttentionRole);
    return value.canConvert(QVariant::Bool) ? value.toBool() : false;
}

static int indicatorCount(const QModelIndex& index)
{
    QVariant value = index.data(ListenerModel::CountRole);
    return value.canConvert(QVariant::Int) ? value.toInt() : 0;
}

void ListenerModelTest::testUpdateIndicator()
{
    QDate day = QDate(2006, 4, 1);
    QSignalSpy drawAttentionSpy(mModel, SIGNAL(drawAttentionChanged(const QModelIndex&)));

    // Show server
    mServer->show();

    // Show an indicator
    QIndicate::Indicator indicator;
    indicator.setIndicatorProperty("name", "John Doe");
    indicator.setIndicatorProperty("time", QDateTime(day, QTime(1, 23, 45)));
    indicator.show();
    QTest::qWait(500);

    // Get indexes
    QModelIndex serverIndex = mModel->index(0, 0);
    QModelIndex indicatorIndex = mModel->index(0, 0, serverIndex);

    QCOMPARE(indicatorIndex.data().toString(), QString("John Doe"));
    QCOMPARE(indicatorDateTime(indicatorIndex), QDateTime(day, QTime(1, 23, 45)));
    QCOMPARE(indicatorCount(indicatorIndex), 0);
    QVERIFY(!indicatorDrawAttention(indicatorIndex));
    QCOMPARE(drawAttentionSpy.count(), 0);

    indicator.setIndicatorProperty("name", "Bruce Wayne");
    indicator.setIndicatorProperty("time", QDateTime(day, QTime(12, 34, 56)));
    indicator.setDrawAttentionProperty(true);
    indicator.setCountProperty(5);
    QTest::qWait(500);

    QCOMPARE(indicatorIndex.data().toString(), QString("Bruce Wayne"));
    QCOMPARE(indicatorDateTime(indicatorIndex), QDateTime(day, QTime(12, 34, 56)));
    QCOMPARE(indicatorCount(indicatorIndex), 5);
    QVERIFY(indicatorDrawAttention(indicatorIndex));
    QCOMPARE(drawAttentionSpy.count(), 1);
    QVariantList args = drawAttentionSpy.takeFirst();
    QCOMPARE(args.count(), 1);
    QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), indicatorIndex);
}

#include "listenermodeltest.moc"
