/*
 * Copyright © 2013 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/>.
 *
 * Authored by: Thomas Voß <thomas.voss@canonical.com>
 */
#ifndef COM_LOMIRI_CONTENT_TRANSFER_P_H_
#define COM_LOMIRI_CONTENT_TRANSFER_P_H_

#include "common.h"
#include "ContentTransferInterface.h"

#include <com/lomiri/content/item.h>
#include <com/lomiri/content/transfer.h>

#include <QObject>
#include <QVector>

namespace com
{
namespace lomiri
{
namespace content
{
class Transfer::Private : public QObject
{
    Q_OBJECT
  public:
    static Transfer* make_transfer(const QDBusObjectPath& transfer, QObject* parent)
    {
        QSharedPointer<Private> d{new Private{transfer, parent}};
        return new Transfer{d, parent};
    }

    Private(const QDBusObjectPath& transfer, QObject* parent)
            : QObject(parent),
              remote_transfer(
                  new com::lomiri::content::dbus::Transfer(
                      HUB_SERVICE_NAME,
                      transfer.path(), 
                      QDBusConnection::sessionBus(), this))
    {
    }

    int id()
    {
        auto reply = remote_transfer->Id();
        reply.waitForFinished();

        return reply.value();
    }

    State state()
    {
        auto reply = remote_transfer->State();
        reply.waitForFinished();

        if (reply.isError()) {
            qWarning() << "Dbus error: " << reply.error();
            return Transfer::aborted;
        }

        return static_cast<Transfer::State>(reply.value());
    }

    bool start()
    {
        auto reply = remote_transfer->Start();
        reply.waitForFinished();
        
        return not reply.isError();
    }

    bool handled()
    {
        auto reply = remote_transfer->Handled();
        reply.waitForFinished();

        return not reply.isError();
    }

    bool abort()
    {
        auto reply = remote_transfer->Abort();
        reply.waitForFinished();
        
        return not reply.isError();
    }

    bool finalize()
    {
        auto reply = remote_transfer->Finalize();
        reply.waitForFinished();

        return not reply.isError();
    }

    bool charge(const QVector<Item>& items)
    {
        QVariantList itemVariants;
        Q_FOREACH(const Item& item, items)
        {   
            itemVariants << QVariant::fromValue(item);
        }
        auto reply = remote_transfer->Charge(itemVariants);
        reply.waitForFinished();

        return not reply.isError();
    }

    QVector<Item> collect()
    {
        QVector<Item> result;

        auto reply = remote_transfer->Collect();
        reply.waitForFinished();
        
        if (reply.isError()) {
            qWarning() << "Dbus error: " << reply.error();
            return result;
        }

        auto items = reply.value();

        Q_FOREACH(const QVariant& itemVariant, items)
        {   
            result << qdbus_cast<Item>(itemVariant);
        }

        return result;
    }

    auto store()
    {
        auto reply = remote_transfer->Store();
        reply.waitForFinished();

        /* FIXME: Return something if it fails */
        /*
        if (reply.isError())
            return new cuc::Store{""};
        */

        //return new Store{reply.value()};
        return std::make_tuple(
            reply.argumentAt<0>(),
            reply.argumentAt<1>(),
            reply.argumentAt<2>()
        );
    }

    QString setStore(Scope scope, const QString& type_id)
    {
        if (scope == Scope::unknown)
            return QString();

        if (type_id != Type::unknown().id() &&
                type_id != Type::Known::documents().id() &&
                type_id != Type::Known::pictures().id() &&
                type_id != Type::Known::music().id() &&
                type_id != Type::Known::contacts().id() &&
                type_id != Type::Known::videos().id() &&
                type_id != Type::Known::links().id() &&
                type_id != Type::Known::ebooks().id() &&
                type_id != Type::Known::text().id() &&
                type_id != Type::Known::events().id())
            return QString();

        auto reply = remote_transfer->SetStore(scope, type_id);
        reply.waitForFinished();

        if (reply.isError()) {
            return QString();
        };

        return reply.value();
    }

    SelectionType selection_type()
    {
        auto reply = remote_transfer->SelectionType();
        reply.waitForFinished();

        /* if SelectionType fails, default to single */
        if (reply.isError()) {
            qWarning() << "Dbus error: " << reply.error();
            return Transfer::SelectionType::single;
        }

        return static_cast<Transfer::SelectionType>(reply.value());
    }

    bool setSelectionType(int type)
    {
        auto reply = remote_transfer->SetSelectionType(type);
        reply.waitForFinished();

        return not reply.isError();
    }

    Direction direction()
    {
        auto reply = remote_transfer->Direction();
        reply.waitForFinished();

        /* if Direction fails, default to import */
        if (reply.isError()) {
            qWarning() << "Dbus error: " << reply.error();
            return Transfer::Direction::Import;
        }

        return static_cast<Transfer::Direction>(reply.value());
    }

    QString downloadId()
    {
        auto reply = remote_transfer->DownloadId();
        reply.waitForFinished();

        if (reply.isError()) {
            qWarning() << "Dbus error: " << reply.error();
            return QString();
        }

        return static_cast<QString>(reply.value());
    }

    bool setDownloadId(QString downloadId)
    {
        auto reply = remote_transfer->SetDownloadId(downloadId);
        reply.waitForFinished();

        return not reply.isError();
    }

    bool download()
    {
        auto reply = remote_transfer->Download();
        reply.waitForFinished();

        return not reply.isError();
    }

    QString contentType()
    {
        auto reply = remote_transfer->ContentType();
        reply.waitForFinished();

        return static_cast<QString>(reply.value());
    }

    QString source()
    {
        auto reply = remote_transfer->source();
        reply.waitForFinished();

        return static_cast<QString>(reply.value());
    }

    QString destination()
    {
        auto reply = remote_transfer->destination();
        reply.waitForFinished();

        return static_cast<QString>(reply.value());
    }

    com::lomiri::content::dbus::Transfer* remote_transfer;
};
}
}
}

#endif // COM_LOMIRI_CONTENT_TRANSFER_P_H_
