/*
 * Copyright 2013 Canonical Ltd.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of version 3 of the GNU Lesser General Public
 * License 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "clickmanager.h"
#include <QString>
#include <QStringList>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
#include <QDebug>

namespace ClickPlugin {

ClickManager::ClickManager(QQuickItem *parent):
    QQuickItem(parent)
  , m_process(this)
{
    QObject::connect(&m_service, SIGNAL(credentialsFound(const Token&)),
                     this, SLOT(handleCredentialsFound(Token)));
    QObject::connect(&m_service, SIGNAL(credentialsNotFound()),
                     this, SLOT(handleCredentialsNotFound()));
    QObject::connect(&(this->m_process), SIGNAL(finished(int)),
                  this, SLOT(processOutput()));
    QObject::connect(&(this->m_network), SIGNAL(updatesFound()),
                  this, SLOT(processUpdates()));
    QObject::connect(&(this->m_network), SIGNAL(updatesNotFound()),
                  this, SIGNAL(updatesNotFound()));
    QObject::connect(&(this->m_network), SIGNAL(errorOccurred()),
                  this, SIGNAL(errorFound()));
    QObject::connect(&(this->m_network), SIGNAL(clickTokenObtained(Application*, const QString&)),
                  this, SLOT(clickTokenReceived(Application*,const QString&)));
    QObject::connect(&(this->m_network), SIGNAL(downloadUrlFound(QString,QString)),
                  this, SLOT(downloadUrlObtained(QString,QString)));
    QObject::connect(&(this->downloader), SIGNAL(downloadCreated(QString,QString)),
                  this, SLOT(downloadCreated(QString,QString)));
    QObject::connect(&(this->downloader), SIGNAL(downloadNotCreated(QString,QString)),
                  this, SLOT(downloadNotCreated(QString,QString)));
}

ClickManager::~ClickManager()
{
}

void ClickManager::handleCredentialsFound(Token token)
{
    qDebug() << "Credentials found.";
    this->m_token = token;
    QStringList args("list");
    args << "--manifest";
    this->m_process.start("click", args);
}

void ClickManager::handleCredentialsNotFound()
{
    qDebug() << "No credentials were found.";
    emit this->credentialsNotFound();
}

void ClickManager::checkUpdates()
{
    this->m_model.clear();
    emit this->modelChanged();
    this->m_service.getCredentials();
}

void ClickManager::processOutput()
{
    QString output(this->m_process.readAllStandardOutput());

    QJsonDocument document = QJsonDocument::fromJson(output.toUtf8());

    QJsonArray array = document.array();

    int i;
    for(i = 0; i < array.size(); i++) {
        QJsonObject object = array.at(i).toObject();
        QString name = object.value("name").toString();
        QString title = object.value("title").toString();
        QString version = object.value("version").toString();
        Application* app = new Application();
        app->initializeApplication(name, title, version);
        this->m_apps[app->getPackageName()] = app;
    }

    this->m_network.checkForNewVersions(this->m_apps);
}

void ClickManager::processUpdates()
{
    foreach(QString id, this->m_apps.keys()) {
        Application* app = this->m_apps.value(id);
        if(app->updateRequired()) {
            this->m_model.append(QVariant::fromValue(app));
        }
    }

    emit this->modelChanged();
    emit this->updateAvailableFound();
}

void ClickManager::startDownload(QString packagename)
{
    qDebug() << "Download Package:" << packagename;
    this->m_network.getResourceUrl(packagename);
}

void ClickManager::downloadUrlObtained(QString packagename, QString url)
{
    if(this->m_token.isValid()) {
        QString authHeader = this->m_token.signUrl(url, QStringLiteral("HEAD"), true);
        qDebug() << "Download Url:" << url;
        Application* app = this->m_apps[packagename];
        app->setClickUrl(url);
        this->m_network.getClickToken(app, url, authHeader);
    } else {
        Application* app = this->m_apps[packagename];
        app->setError("Invalid User Token");
    }
}

void ClickManager::downloadCreated(QString packagename, QString dbuspath)
{
    qDebug() << "Dbus Path:" << dbuspath;
    this->m_apps[packagename]->setDbusPath(dbuspath);
    this->m_apps[packagename]->setUpdateState(true);
}

void ClickManager::downloadNotCreated(QString packagename, QString error)
{
    qDebug() << "Download not creeated";
    Application* app = this->m_apps[packagename];
    app->setError(error);
}

void ClickManager::clickTokenReceived(Application* app, const QString& clickToken)
{
    app->setError("");
    this->downloader.startDownload(app->getPackageName(), app->getClickUrl(), clickToken);
}

}
