/* This file is part of the Chakra project

   Copyright (C) 2012 Lukas Appelhans <boom1992@chakra-project.org>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
*/

#ifndef AKABEICLIENTDOWNLOADER_H
#define AKABEICLIENTDOWNLOADER_H

#include <QObject>
#include <QTime>
#include <QThread>

#include <akabeierror.h>

namespace AkabeiClient {

/*
 * This little class is used to contain the callbacks we need to pass to CURL in order to receive
 * data and progress information during the transfer.
 * 
 * The callbacks cannot be instance functions, so we made them static instead.
 * headerData is actually used only to ignore header lines, which are otherwise printed on stdout.
 * 
 * NOTE: I need a class so it can be friend of Downloader and access its private functions and variables.
 */
class DownloadHelper
{
public:
    static size_t writeData(void *, size_t, size_t, void *);
    static int reportProgress(void *, double, double, double, double);
    static size_t headerData(void *, size_t, size_t, void *);
}; 
   
/**
 * \class Downloader akabeiclientdownloader.h "akabeiclientdownloader.h"
 *
 * \brief This is used to download files from the internet to a specified destination. This happens in a separated thread.
 *
 * \code
 * Downloader * downloader = new Downloader(url, destination, operation, force option, this);
 * connect(downloader, SIGNAL(finished(bool)), SLOT(finished(bool)));
 * connect(downloader, SIGNAL(progressChanged(int)), SLOT(progressChanged(int)));
 * downloader->start();
 * \endcode
 */
class Downloader : public QThread
{
    Q_OBJECT
public:
    /**
     * Constructs a Downloader object
     * @param url the url to download the content from
     * @param dest the destination file on disk
     * @param op the operation which invokes this downloader (might be 0)
     * @param parent a parent for this class
     */
    Downloader(const QString &url, const QString &dest, Akabei::Operation * op, bool force = false, QObject * parent = 0);
    virtual ~Downloader();

    /**
     * Starts the download.
     * 
     * We first check if the file is already present locally: if this is the case, and force = false (see constructor),
     * nothing happens and the thread exits.
     */
    void run();

    /**
     * @returns the total size of the file to be downloaded
     */
    qint64 totalBytes() const;
    
    /**
     * @returns the size of the file which already got downloaded
     */
    
    qint64 downloadedBytes() const;
    
    /**
     * @returns how fast the download is happening (in bytes)
     */
    ulong speed() const;

    /**
     * @returns the percentage of content which was already downloaded
     */
    int progress() const;

    /**
     * @returns the estimated time (in seconds)
     */
    int eta() const;

    /**
     * @returns a list of errors which have occurred (empty if no errors occurred)
     */
    Akabei::Error::List errors() const;

Q_SIGNALS:
    /**
     * Gets emitted when the total bytes changed
     * @param totalBytes the new total size
     */
    void totalBytesChanged(qint64 totalBytes);
    /**
     * Gets emitted when the downloaded bytes changed
     * @param downloadedBytes the size which already got downloaded
     */
    void downloadedBytesChanged(qint64 downloadedBytes);
    /**
     * Gets emitted when the download speed changes
     * @param speed the new speed the file is downloading
     */
    void speedChanged(ulong speed);
    /**
     * Gets emitted when the download progress changed
     * @param progress the progress which was made
     */
    void progressChanged(int progress);
    /**
     * Gets emitted when the estimated time changed
     * @param eta the estimated time for the download to finish
     */
    void etaChanged(int eta);
    /**
     * Gets emitted when the download finished
     * @param success true if the download was successful, otherwise false
     */
    void finished(bool success);
    
private:
    friend class DownloadHelper;
    class Private;
    Private * d;
};
}

#endif // AKABEICLIENTDOWNLOADER_H
