/* This file is part of the KDE project

   Copyright (C) 2004 Dario Massarin <nekkar@libero.it>
   Copyright (C) 2009-2010 Matthias Fuchs <mat69@gmx.net>

   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.
*/

#include "kiodownload.h"
// #ifdef HAVE_NEPOMUK
// #include "core/nepomukhandler.h"
// #endif //HAVE_NEPOMUK

// #include <kiconloader.h>
// #include <klocale.h>
#include <kdebug.h>

#include <QtCore/QFile>
// #include <QDomElement>

KioDownload::KioDownload(const KUrl &src, const KUrl &dest, QObject *parent)
    : QObject(parent),
      m_tryResume(true),
      m_source(src),
      m_dest(dest),
      m_file(0),
      m_getJob(0),
      m_resumeJob(0),
      m_isResumeable(false),
      m_movingFile(false),
      m_processedSize(0),
      m_totalSize(0),
      m_offset(0)
{
    kDebug(5001);
}

KioDownload::~KioDownload()
{
    killJob();
}

// bool KioDownload::setNewDestination(const KUrl &newDestination)
// {
//     if (isResumable() && newDestination.isValid() && (newDestination != dest()))
//     {
//         KUrl oldPath = KUrl(m_dest.path() + ".part");
//         if (oldPath.isValid() && QFile::exists(oldPath.pathOrUrl()))
//         {
//             m_movingFile = true;
//             stop();
//             setStatus(Job::Stopped, i18nc("changing the destination of the file", "Changing destination"), SmallIcon("media-playback-pause"));
//             setTransferChange(Tc_Status, true);
// 
//             m_dest = newDestination;
// #ifdef HAVE_NEPOMUK
//             nepomukHandler()->setNewDestination(m_dest);
// #endif //HAVE_NEPOMUK
// 
//             KIO::Job *move = KIO::file_move(oldPath, KUrl(newDestination.path() + ".part"), -1, KIO::HideProgressInfo);
//             connect(move, SIGNAL(result(KJob *)), this, SLOT(newDestResult(KJob *)));
//             connect(move, SIGNAL(infoMessage(KJob *, const QString &)), this, SLOT(slotInfoMessage(KJob *, const QString &)));
//             connect(move, SIGNAL(percent(KJob *, unsigned long)), this, SLOT(slotPercent(KJob *, unsigned long)));
// 
//             return true;
//         }
//     }
//     return false;
// }

// void KioDownload::newDestResult(KJob *result)
// {
//     Q_UNUSED(result)//TODO handle errors etc.!
//     m_movingFile = false;
//     start();
//     setTransferChange(Tc_FileName);
// }
void KioDownload::slotInfoMessage(KJob* kioJob, const QString& msg)
{
    Q_UNUSED(kioJob)

    kDebug(5001) << "Infomessage:" << msg;
}

void KioDownload::start()
{
    kDebug(5001);
    if (!m_movingFile)
    {
        if (!m_file)
        {
            m_file = new QFile(m_dest.pathOrUrl(), this);
            if (!m_file->open(QIODevice::ReadWrite))
            {
                delete m_file;
                m_file = 0;
            }
        }
        m_stopped = false;
        if(!m_getJob)
        {
            createJob();
        }
    }
}

void KioDownload::stop()
{
    m_stopped = true;
    killJob();
    if (m_file)
    {
        m_file->close();
        m_file = 0;
    }
}

bool KioDownload::isResumable() const
{
    return m_isResumeable;
}

// void KioDownload::deinit()
// {
//     if (status() != Job::Finished)//if the transfer is not finished, we delete the *.part-file
//     {
//         KIO::Job *del = KIO::del(m_dest.path() + ".part", KIO::HideProgressInfo);
//         KIO::NetAccess::synchronousRun(del, NULL);
//     }//TODO: Ask the user if he/she wants to delete the *.part-file? To discuss (boom1992)
// }

//NOTE: INTERNAL METHODS

void KioDownload::createJob()
{
    if (!m_getJob)//TODO delete when not stopped, how? test
    {
        kDebug(5001);
        m_getJob = KIO::get(m_source, KIO::Reload, KIO::HideProgressInfo);
        m_getJob->suspend();
        m_getJob->addMetaData("errorPage", "false");
        m_getJob->addMetaData("AllowCompressedPage", "false");

        connect(m_getJob, SIGNAL(data(KIO::Job *, const QByteArray&)), this, SLOT(slotData(KIO::Job *, const QByteArray&)));
        connect(m_getJob, SIGNAL(result(KJob *)), this, SLOT(slotResult( KJob *)));
        connect(m_getJob, SIGNAL(infoMessage(KJob *, const QString &)), this, SLOT(slotInfoMessage(KJob *, const QString &)));
        connect(m_getJob, SIGNAL(percent(KJob *, unsigned long)), this, SLOT(slotPercent(KJob *, unsigned long)));
        connect(m_getJob, SIGNAL(totalSize(KJob *, qulonglong)), this, SLOT(slotTotalSize(KJob*, qulonglong)));
        connect(m_getJob, SIGNAL(speed(KJob *, unsigned long)), this, SLOT(slotSpeed(KJob*,ulong)));
    }
}

void KioDownload::killJob()
{
    if (m_getJob) {
        m_getJob->kill(KJob::Quietly);
        m_getJob = 0;
    }
    killResumeJob();
}

void KioDownload::killResumeJob()
{
    if (m_resumeJob) {
        m_resumeJob->kill(KJob::Quietly);
        m_resumeJob = 0;
    }
}
void KioDownload::slotCanResume(KIO::Job* job, KIO::filesize_t size)
{
    Q_UNUSED(job)
    Q_UNUSED(size)
    kDebug(5001);
    m_isResumeable = true;
    m_tryResume = false;
    killResumeJob();
    if (m_totalSize) {
        emit totalSize(m_totalSize);
    }
}

void KioDownload::slotResult(KJob *kioJob)
{
    //resume job failed, probably only one connection supported
    if (kioJob == m_resumeJob) {
        m_resumeJob = 0;
        m_tryResume = false;
        if (m_totalSize) {
            emit totalSize(m_totalSize);
        }
        return;
    }

    const int err = kioJob->error();
    m_getJob = 0;
    switch (err)
    {
        case 0:                            //The download has finished
            kDebug(5001) << "Finished" << m_source;
            emit finished();
            break;
        case KIO::ERR_FILE_ALREADY_EXIST:  //The file has already been downloaded.
//             setStatus(Job::Finished, i18nc("transfer state: finished", "Finished"), SmallIcon("dialog-ok"));
//         // "ok" icon should probably be "dialog-success", but we don't have that icon in KDE 4.0
//             m_percent = 100;
//             m_downloadSpeed = 0;
//             m_downloadedSize = m_totalSize;
//             setTransferChange(Tc_Percent | Tc_DownloadSpeed);
//             break;
        default:
            //There has been an error
            kDebug(5001) << "Error" << err << "for" << m_source;

            emit error();

//             if (!m_stopped)
//                 setStatus(Job::Aborted, i18n("Aborted"), SmallIcon("dialog-error"));
            break;
    }
//     // when slotResult gets called, the m_copyjob has already been deleted!
//     setTransferChange(Tc_Status, true);
}

// void KioDownload::slotInfoMessage( KJob * kioJob, const QString & msg )
// {
//   Q_UNUSED(kioJob)
//     m_log.append(QString(msg));
// }
// 
void KioDownload::slotPercent(KJob *kioJob, unsigned long percentDown)
{
    Q_UNUSED(kioJob)
    emit percent(percentDown);
}
// 
void KioDownload::slotTotalSize(KJob *kioJob, qulonglong size)
{
    Q_UNUSED(kioJob)

    kDebug(5001) << size;
    m_totalSize = size;

    //no need to wait for resumeJob
    if (!m_tryResume) {
        emit totalSize(m_totalSize);
    }
}

void KioDownload::slotSpeed(KJob *kioJob, unsigned long bytes_per_second)
{
    Q_UNUSED(kioJob)

    emit speed(bytes_per_second);
}

void KioDownload::slotData(KIO::Job *job, const QByteArray &data)
{
    if (job == m_getJob) {
        if (m_file) {
            m_file->seek(m_offset);
            m_file->write(data);
            m_offset += data.size();

            m_processedSize += data.size();
            emit processedSize(m_processedSize);

            //create a job that checks if the server supports resumeing, after we already received data
            if (!m_resumeJob && m_tryResume) {
                m_resumeJob = KIO::get(m_source, KIO::Reload, KIO::HideProgressInfo);
                m_resumeJob->suspend();
                m_resumeJob->addMetaData("errorPage", "false");
                m_resumeJob->addMetaData("AllowCompressedPage", "false");
                m_resumeJob->addMetaData("resume", KIO::number(100));
                connect(m_resumeJob, SIGNAL(canResume(KIO::Job*,KIO::filesize_t)), this, SLOT(slotCanResume(KIO::Job*,KIO::filesize_t)));

                connect(m_resumeJob, SIGNAL(data(KIO::Job *, const QByteArray&)), this, SLOT(slotData(KIO::Job *, const QByteArray&)));
                connect(m_resumeJob, SIGNAL(result(KJob *)), this, SLOT(slotResult( KJob *)));
            }
        }
    } else if (m_resumeJob && (job == m_resumeJob)) {
        m_processedResumeSize += data.size();
        //only download 100 bytes for the resume job to try if resuming is supported
        if (m_processedResumeSize > 100) {
            m_tryResume = false;
            killResumeJob();
            if (m_totalSize) {
                emit totalSize(m_totalSize);
            }
        }
    }
    //QString fileName = job->metaData().value("content-disposition-filename");
    //if (!fileName.isEmpty())
    //    emit suggestedFileName(fileName);
}

#include "kiodownload.moc"
