/*
Copyright 2014 Canonical Ltd.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License, version 3
as published by the Free Software Foundation.

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 Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this program.  If not, see
<http://www.gnu.org/licenses/>.
*/

#include "postal-client.h"
#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusMessage>
#include <QtDBus/QDBusPendingCall>
#include <QtDBus/QDBusPendingReply>
#include <QTimer>

#define POSTAL_SERVICE "com.lomiri.Postal"
#define POSTAL_PATH "/com/lomiri/Postal"
#define POSTAL_IFACE "com.lomiri.Postal"

PostalClient::PostalClient(QString appId)
{
    this->m_appId = appId;
    this->m_pkgName = appId.split("_").at(0);
    this->m_pkgName = m_pkgName.replace(".", "_2e").replace("-", "_2d");
}

void PostalClient::clearPersistent(const QStringList &tags)
{
    // 24.04-1.1 and later: `ClearPersistentList` accepts a list
    //                      `ClearPersistent` accepts single argument only (godbus/dbus limitation)
    // 24.04.1.0:           `ClearPersistentList` doesn't exists
    //                      `ClearPersistent` accepts a list (broken interim state)
    // 20.04:               `ClearPersistent` accepts multiple arguments

    switch (m_clearPersistentMode) {
        case ClearPersistentList_List:
            return call_clearPersistentList_list(tags);
        case ClearPersistent_MultiArgs:
            return call_clearPersistent_multiArgs(tags);
        case ClearPersistent_List:
            return call_clearPersistent_list(tags);
    }
}

void PostalClient::call_clearPersistentList_list(const QStringList &tags)
{
    QDBusConnection bus = QDBusConnection::sessionBus();
    QString path(POSTAL_PATH);
    path += "/" + m_pkgName;
    QDBusMessage message = QDBusMessage::createMethodCall(
            POSTAL_SERVICE, path, POSTAL_IFACE, "ClearPersistentList"); // no-i18n
    message << m_appId;
    message << tags;

    QDBusPendingCall pcall = bus.asyncCall(message);
    QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this);

    connect(watcher, &QDBusPendingCallWatcher::finished,
            this, [this, tags] (QDBusPendingCallWatcher *watcher) {
                this->clearPersistentList_list_finished(watcher, tags);
            });
}

void PostalClient::clearPersistentList_list_finished(QDBusPendingCallWatcher *watcher, const QStringList & tags)
{
    QDBusPendingReply<void> reply = *watcher;

    if (reply.isError()) {
        if (reply.error().name() ==
                QStringLiteral("org.freedesktop.DBus.Error.UnknownMethod")) // no-i18n
        {
            m_clearPersistentMode = ClearPersistent_MultiArgs;
            call_clearPersistent_multiArgs(tags);
        } else {
            //qWarning() << reply.error().message();
        }
    }
    watcher->deleteLater();
}

void PostalClient::call_clearPersistent_multiArgs(const QStringList &tags)
{
    QDBusConnection bus = QDBusConnection::sessionBus();
    QString path(POSTAL_PATH);
    path += "/" + m_pkgName;
    QDBusMessage message = QDBusMessage::createMethodCall(
            POSTAL_SERVICE, path, POSTAL_IFACE, "ClearPersistent"); // no-i18n
    message << m_appId;
    for (const QString & tag : tags) {
        message << tag;
    }

    QDBusPendingCall pcall = bus.asyncCall(message);
    QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this);
        connect(watcher, &QDBusPendingCallWatcher::finished,
            this, [this, tags] (QDBusPendingCallWatcher *watcher) {
                this->clearPersistent_multiArgs_finished(watcher, tags);
            });
}

void PostalClient::clearPersistent_multiArgs_finished(QDBusPendingCallWatcher *watcher, const QStringList & tags)
{
    QDBusPendingReply<void> reply = *watcher;

    if (reply.isError()) {
        if (reply.error().name() ==
                QStringLiteral("org.freedesktop.DBus.Error.InvalidArgs")) // no-i18n
        {
            m_clearPersistentMode = ClearPersistent_List;
            call_clearPersistent_list(tags);
        } else {
            //qWarning() << reply.error().message();
        }
    }
    watcher->deleteLater();
}

void PostalClient::call_clearPersistent_list(const QStringList &tags)
{
    QDBusConnection bus = QDBusConnection::sessionBus();
    QString path(POSTAL_PATH);
    path += "/" + m_pkgName;
    QDBusMessage message = QDBusMessage::createMethodCall(
            POSTAL_SERVICE, path, POSTAL_IFACE, "ClearPersistent"); // no-i18n
    message << m_appId;
    message << tags;

    QDBusPendingCall pcall = bus.asyncCall(message);
    QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this);

    connect(watcher, &QDBusPendingCallWatcher::finished,
            this, &PostalClient::clearPersistent_list_finished);
}

void PostalClient::clearPersistent_list_finished(QDBusPendingCallWatcher *watcher)
{
    QDBusPendingReply<void> reply = *watcher;

    if (reply.isError()) {
        //qWarning() << reply.error().message();
    }
    watcher->deleteLater();
}

void PostalClient::setCount(int count)
{
    QDBusConnection bus = QDBusConnection::sessionBus();
    QString path(POSTAL_PATH);
    bool visible = count != 0;
    path += "/" + m_pkgName;
    QDBusMessage message = QDBusMessage::createMethodCall(POSTAL_SERVICE, path, POSTAL_IFACE, "SetCounter"); // no-i18n
    message << m_appId << count << visible;
    QDBusPendingCall pcall = bus.asyncCall(message);
    QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this);
    connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)),
            this, SLOT(setCountFinished(QDBusPendingCallWatcher *)));
}

void PostalClient::setCountFinished(QDBusPendingCallWatcher *watcher)
{
    QDBusPendingReply<void> reply = *watcher;
    if (reply.isError()) {
        //qWarning() << reply.error().message();
    }
    watcher->deleteLater();
}
