#include "downloader.h"
#include <QEventLoop>
#include <QApplication>
#include <QDebug>
#include <QTime>

Downloader::Downloader(QObject *parent) :QObject(parent), busy(false)
{
    connect(&m_WebCtrl, SIGNAL(finished(QNetworkReply*)), this, SLOT(onDownloadFinished(QNetworkReply*)));
    bytes_downloaded = 0;
    bytes_total = 0;
    download_speed = 0;
    bytesReceivedBeforeSecond = 0;
    timeElapsedBeforeSecond = 0;
}

Downloader::~Downloader() {
}

QUrl Downloader::getUrl()
{
    return url;
}

void Downloader::setUrl(const QUrl &_url)
{
    url = _url;
}

void Downloader::waitForDownloaded()
{
    if (!busy)
        return;

    QEventLoop loop;
    connect(this, &Downloader::downloadFinished, &loop, &QEventLoop::quit);
    loop.exec();
}

double Downloader::getPercent()
{
    return double(std::ceil(((double)bytes_downloaded/ bytes_total) * 100 * 10)) / 10.0;
}

quint64 Downloader::getBytesTotal()
{
    return bytes_total;
}

quint64 Downloader::getBytesDownloaded()
{
    return bytes_downloaded;
}

quint64 Downloader::getElapsedTime()
{
    return (getBytesTotal() - getBytesDownloaded()) / qMax(quint64(1), getSpeed());
}

quint64 Downloader::getSpeed()
{
    return download_speed;
}

QString Downloader::getSpeedFormatted(quint64 speed_bytes_per_sec)
{
    float speed = speed_bytes_per_sec;

    QString unit;
    if (speed < 1024) {
        unit = "bytes/sec";
    } else if (speed < 1024*1024) {
        speed /= 1024;
        unit = "kB/s";
    } else {
        speed /= 1024*1024;
        unit = "MB/s";
    }
    return QString::number(speed, 'f', 1) + " " + unit;
}

QString Downloader::getSizeFormatted(quint64 bytes)
{
    float size = bytes;
    QString unit;
    if (size < 1024) {
        unit = "байт";
    } else if (size < 1024*1024) {
        size /= 1024;
        unit = "kB";
    } else {
        size /= 1024*1024;
        unit = "MB";
    }
    return QString::number(size, 'f', 1) + " " + unit;
}


QString Downloader::getElapsedTimeFormatted(quint64 elapsed_time_secs)
{
    qint64 secs = elapsed_time_secs;
    qint64 mins = 0;
    qint64 hours = 0;
    qint64 days = 0;

    if (secs > 60) {
        mins = secs / 60;
        secs %= 60;
    }

    if (mins > 60) {
        hours = mins / 60;
        mins %= 60;
    }

    if (hours > 24) {
        days = hours / 24;
        hours %= 24;
    }

    if (days > 0)
        return " очень много (низкая скорость)";

    QString result = "";

    if (hours > 0) {
        result += QString::number(hours);
        if (hours % 10 == 1 && hours / 10 != 1)
            result += " час ";
        else if (hours % 10 > 1 && hours % 10 < 5 && hours / 10 != 1)
            result += " часа ";
        else
            result += " часов ";
    }

    if (mins > 0) {
        result += QString::number(mins);
        if (mins % 10 == 1 && mins / 10 != 1)
            result += " минута ";
        else if (mins % 10 > 1 && mins % 10 < 5 && mins / 10 != 1)
            result += " минуты ";
        else
            result += " минут ";
    }

    if (secs > 0 && hours == 0) {
        result += QString::number(secs);
        if (secs % 10 == 1 && secs / 10 != 1)
            result += " секунда ";
        else if (secs % 10 > 1 && secs % 10 < 5 && secs / 10 != 1)
            result += " секунды ";
        else
            result += " секунд ";
    }

    if (result == "")
        result = "совсем чуть-чуть";
    return result;
}

void Downloader::start()
{
    if (busy) {
        qDebug() << "Cannot download " << url << ", downloader is busy!";
        return;
    }
    qDebug() << "Starting download " << url;

    downloadTime.restart();
    bytes_downloaded = 0;
    bytes_total = 0;
    download_speed = 0;
    bytesReceivedBeforeSecond = 0;
    timeElapsedBeforeSecond = 0;

    busy = true;
    QNetworkRequest request(url);
    m_CurrentReply = m_WebCtrl.get(request);
    m_CurrentReply->setReadBufferSize(download_speed_limit);
    connect(m_CurrentReply, &QNetworkReply::readyRead, this, &Downloader::onReadyRead);
    connect(m_CurrentReply, &QNetworkReply::downloadProgress, this, &Downloader::onDownloadProgressChanged);
}

void Downloader::updateDownloadSpeedLimit(int bytes_per_sec)
{
    download_speed_limit = bytes_per_sec;
    if (m_CurrentReply)
        m_CurrentReply->setReadBufferSize(bytes_per_sec);
}

void Downloader::onDownloadProgressChanged(qint64 bytesReceived, qint64 bytesTotal)
{

    bytes_downloaded = bytesReceived;
    bytes_total = bytesTotal;

    if (downloadTime.elapsed() - timeElapsedBeforeSecond >= 300) {
        download_speed = (bytes_downloaded - bytesReceivedBeforeSecond) * 1000.0 / (downloadTime.elapsed() - timeElapsedBeforeSecond);
        timeElapsedBeforeSecond = downloadTime.elapsed();
        bytesReceivedBeforeSecond = bytes_downloaded;
        emit progressChanged(this);
    }
}

void Downloader::stop()
{
    if (m_CurrentReply) {
        m_CurrentReply->abort();
    }
    busy = false;
}

void Downloader::onDownloadFinished(QNetworkReply*) {
    if (m_CurrentReply)
        m_CurrentReply->deleteLater();

    download_speed = 0;
    busy = false;

    emit downloadFinished(this);
}

void Downloader::onReadyRead()
{
    QByteArray readdata = m_CurrentReply->readAll();
    if (targetFile && targetFile->isWritable())
        targetFile->write(readdata);
    if (targetBytearray)
        targetBytearray->append(readdata);
}
