/*
 * 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 "network.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
#include <QByteArray>
#include <QUrl>
#include <QDebug>

#define URL_APPS "https://myapps.developer.ubuntu.com/dev/api/click-metadata/"
#define URL_PACKAGE "https://search.apps.ubuntu.com/api/v1/package/"

namespace ClickPlugin {

Network::Network(QObject *parent) :
    QObject(parent)
{
    this->_nam = new QNetworkAccessManager(this);
    this->_request = new QNetworkRequest();

    this->_request->setHeader(QNetworkRequest::ContentTypeHeader,
                              "application/json");

    QObject::connect(this->_nam, SIGNAL(finished(QNetworkReply*)),
                     this, SLOT(onReply(QNetworkReply*)));
}

void Network::checkForNewVersions(QHash<QString, Application*> &apps)
{
    this->_apps = apps;

    QJsonObject serializer;
    QJsonArray array;
    foreach(QString id, this->_apps.keys()) {
        array.append(QJsonValue(this->_apps.value(id)->getPackageName()));
    }

    serializer.insert("name", array);
    QJsonDocument doc(serializer);

    QByteArray content = doc.toJson();

    this->_request->setUrl(QUrl(URL_APPS));
    this->_nam->post(*this->_request, content);
}

void Network::onReply(QNetworkReply* reply)
{
    QVariant statusAttr = reply->attribute(
                            QNetworkRequest::HttpStatusCodeAttribute);
    if (!statusAttr.isValid()) {
        emit this->errorOccurred();
        return;
    }

    int httpStatus = statusAttr.toInt();

    qDebug() << "Network::OnReply from " << reply->url()
             << " status: " << httpStatus;

    if (httpStatus == 200 || httpStatus == 201) {
        if (reply->hasRawHeader(X_CLICK_TOKEN)) {
            Application* app = qobject_cast<Application*>(reply->request().originatingObject());
            if(app != NULL) {
                QString header(reply->rawHeader(X_CLICK_TOKEN));
                emit this->clickTokenObtained(app, header);
            }
            reply->deleteLater();
            return;
        }

        QByteArray payload = reply->readAll();
        QJsonDocument document = QJsonDocument::fromJson(payload);
        reply->deleteLater();

        if (document.isArray()) {
            QJsonArray array = document.array();
            int i;
            bool updates = false;
            for(i = 0; i < array.size(); i++) {
                QJsonObject object = array.at(i).toObject();
                QString name = object.value("name").toString();
                QString version = object.value("version").toString();
                QString icon_url = object.value("icon_url").toString();
                int size = object.value("binary_filesize").toVariant().toInt();
                if(this->_apps.contains(name)) {
                    this->_apps[name]->setRemoteVersion(version);
                    this->_apps[name]->setIconUrl(icon_url);
                    this->_apps[name]->setBinaryFilesize(size);
                    if(this->_apps[name]->updateRequired()) {
                        updates = true;
                    }
                }
            }
            if(updates) {
                emit this->updatesFound();
            }else{
                emit this->updatesNotFound();
            }
        } else if (document.isObject()){
            QJsonObject object = document.object();
            QString url = object.value("download_url").toString();
            QString name = object.value("name").toString();
            emit this->downloadUrlFound(name, url);
        } else {
            emit errorOccurred();
        }
    } else {
        emit errorOccurred();
    }

}

void Network::getResourceUrl(const QString& packagename)
{
    this->_request->setUrl(QUrl(URL_PACKAGE + packagename));
    this->_nam->get(*this->_request);
}

void Network::getClickToken(Application* app, const QString& url, const QString& authHeader)
{
    QUrl query(url);
    query.setQuery(authHeader);
    QNetworkRequest request;
    request.setUrl(query);
    request.setOriginatingObject(app);
    this->_nam->head(request);
}

}
