/***************************************************************************
 *   Copyright (C) 2007-2011 by Vegeta                                     *
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 *   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 General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "coverdownload.h"

#include <QtGui/QDialog>
#include <QtGui/QLabel>
#include <QtGui/QPushButton>
#include <QtGui/QSlider>
#include <QtGui/QVBoxLayout>
#include <QAction>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QUrl>
#include <QFile>
#include <QTimer>


CoverDownload::CoverDownload(QWidget *parent) : QWidget(parent)
        , isCancelAllJobs(false)
        , isDownloadJobRunning(false)
        , isSingleDownloadJob(false)
        , currentItem(0)
        , Errors(0)
        , Skipped(0)
        , p_Dialog(0)

{
    getResults = new QNetworkAccessManager(this);
    connect(getResults, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));

    getAmazonPictureURL = new QNetworkAccessManager(this);
    connect(getAmazonPictureURL, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyGetPictureURLfromAmazon(QNetworkReply*)));

    DownloaderPicture = new QNetworkAccessManager(this);
    connect(DownloaderPicture, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinishedPicture(QNetworkReply*)));

    timeout = new QTimer(this);
    connect(timeout, SIGNAL(timeout()), this, SLOT(Timeout()));

    previewCovers();
}

CoverDownload::~CoverDownload(){
}


// *********************************************************************************************
// Add new download to queue
// *********************************************************************************************
void CoverDownload::addDownloadJob(QString InterpretInfos, QString DownloadInfo, QString DownloadFolder, int SearchEngine){

    if (QFile::exists(DownloadFolder + "/cover.jpg")) {
        Skipped++;
        return; // Don't overwrite covers
    }

    searchEngine = SearchEngine;
    QString URL;
    if      (searchEngine == AMAZON) URL = QString("http://www.amazon.com/s?search-alias=aps&field-keywords=%1").arg(DownloadInfo.replace(QRegExp("[\\s&$\"'?!]+"), "+"));
    else if (searchEngine == GOOGLE) URL = QString("http://www.google.de/images?as_q=%1&safe=images&as_st=y&tbs=isch:1,isz:ex,iszw:300,iszh:300,ift:jpg").arg(DownloadInfo.replace(QRegExp("[\\s&$\"'?!]+"), "+"));

    DownloadJobClass tmp;
    tmp.DownloadURL     = URL;
    tmp.DownloadFolder  = DownloadFolder;
    tmp.InterpretInfos  = InterpretInfos;
    DownloadJobs << tmp;
}


// *********************************************************************************************
// Start downloads
// *********************************************************************************************
void CoverDownload::startDownloads(){

    if (!isDownloadJobRunning && !DownloadJobs.isEmpty()){
        isCancelAllJobs      = false;
        isDownloadJobRunning = true;
        currentItem          = 0;
        Errors               = 0;
        Skipped              = 0;

        currentNetworkReply = getResults->get(QNetworkRequest(QUrl(DownloadJobs[0].DownloadURL)));

        timeout->start(15000); // Timeout 15 seconds
        emit signal_updateDownloadInfos();
    } else emit signal_allDownloadsFinished();
}



// *********************************************************************************************
// Responce from Google - Pictures can extracted directly from this list
// *********************************************************************************************
void CoverDownload::replyFinished(QNetworkReply *reply){
    timeout->stop();

    if (isCancelAllJobs){
        previewCovers();
        DownloadJobs.clear();
        reply->deleteLater();
        isDownloadJobRunning = false;
        return;
    }

    QString Buffer = reply->readAll();
    QRegExp rx("", Qt::CaseInsensitive, QRegExp::RegExp2);
    if (searchEngine == GOOGLE) rx.setPattern("imgurl\\\\x3d([^\\\\]+)\\\\x26");
    else rx.setPattern("<a href=\"(http://www.amazon.com/[^\"]+)[^<]+<img src=\"http://ecx.images-amazon.com/images/");

    int pos = rx.indexIn(Buffer);
    if (pos != -1) {
        // Extract up to 10 picture URLs
        DownloadJobs[currentItem].PictureAlternatives << QUrl::fromPercentEncoding(rx.cap(1).toLatin1());
        for (int i=0; i<10; i++){
            pos = rx.indexIn(Buffer, pos + rx.matchedLength());
            if (pos == -1) break;
            DownloadJobs[currentItem].PictureAlternatives << rx.cap(1);
        }

        if (searchEngine == GOOGLE) currentNetworkReply = DownloaderPicture->get(QNetworkRequest(QUrl::fromEncoded(DownloadJobs[currentItem].PictureAlternatives.takeFirst().toLatin1()))); // This should not necessary but some URLs need to be decoded twice e.g. "http://www.plong.com/MusicCatalog/T/Tricky%2520-%2520A%2520Ruff%2520Guide/Tricky%2520-%2520A%2520Ruff%2520Guide.jpg"
        else currentNetworkReply = getAmazonPictureURL->get(QNetworkRequest(QUrl(DownloadJobs[currentItem].PictureAlternatives.takeFirst().toLatin1())));
        timeout->start(15000); // Timeout 15 seconds

    } else {
        // No match found
        emit signal_addToErrorlog(QString("<b>Can't find cover artwork for '%1'</b><br>").arg(DownloadJobs[currentItem].InterpretInfos));

        Errors++;
        currentItem++;
        if (currentItem < DownloadJobs.size()) {
            currentNetworkReply = getResults->get(QNetworkRequest(QUrl(DownloadJobs[currentItem].DownloadURL)));

            timeout->start(15000); // Timeout 15 seconds
            emit signal_updateDownloadInfos();
        } else previewCovers();
    }
    reply->deleteLater();
}



// *********************************************************************************************
// Amazon.com:
// Get the URL of the picture from the list above
// Download of the picture starts immediately
// *********************************************************************************************
void CoverDownload::replyGetPictureURLfromAmazon(QNetworkReply *reply){
    timeout->stop();

    if (isCancelAllJobs){
        previewCovers();
        DownloadJobs.clear();
        reply->deleteLater();
        isDownloadJobRunning = false;
        return;
    }

    QString Buffer = reply->readAll();
    QRegExp rx("<img [^>]+src=\"(http://ecx.images-amazon.com/images[^\"]+)\"[^>id=\"prodImage\"]", Qt::CaseInsensitive, QRegExp::RegExp2);

    int pos = rx.indexIn(Buffer);
    if (pos != -1) {

        currentNetworkReply = DownloaderPicture->get(QNetworkRequest(QUrl::fromPercentEncoding(rx.cap(1).toLatin1())));
        timeout->start(15000); // Timeout 15 seconds

    } else {
        // No match found
        emit signal_addToErrorlog(tr("<b>Can't find cover artwork for '%1'</b><br>").arg(DownloadJobs[currentItem].InterpretInfos));

        Errors++;
        currentItem++;
        if (currentItem < DownloadJobs.size()) {
            currentNetworkReply = getResults->get(QNetworkRequest(QUrl(DownloadJobs[currentItem].DownloadURL)));
            timeout->start(15000); // Timeout 15 seconds
            emit signal_updateDownloadInfos();
        } else previewCovers();
    }
    reply->deleteLater();
}



// *********************************************************************************************
// Requested picture downloaded (both Amazon && Google)
// *********************************************************************************************
void CoverDownload::replyFinishedPicture(QNetworkReply *reply){
    timeout->stop();

    if (isCancelAllJobs){
        previewCovers();
        DownloadJobs.clear();
        reply->deleteLater();
        return;
    }

    // Catch error, try another picture
    if ((reply->error() != QNetworkReply::NoError || reply->header(QNetworkRequest::ContentLengthHeader).toInt() < 5000) && searchEngine == GOOGLE && !DownloadJobs[currentItem].PictureAlternatives.isEmpty()){
        currentNetworkReply = DownloaderPicture->get(QNetworkRequest(QUrl::fromEncoded(DownloadJobs[currentItem].PictureAlternatives.takeFirst().toLatin1())));
        timeout->start(15000); // Timeout 15 seconds
        reply->deleteLater();
        return;
    }

    if (reply->error() == QNetworkReply::NoError){
        QFile file(DownloadJobs[currentItem].DownloadFolder + "/cover.jpg");
        if (!file.open(QIODevice::WriteOnly)) {
            emit signal_addToErrorlog(tr("Can't save cover: ") + DownloadJobs[currentItem].DownloadFolder + "/cover.jpg");
        } else {
            file.write(reply->readAll());
            file.close();
        }
    } else emit signal_addToErrorlog(tr("Download error: ") + reply->errorString());


    if (!isSingleDownloadJob){
        currentItem++;
        if (currentItem < DownloadJobs.size()) {
            if (searchEngine == GOOGLE) getResults->get(QNetworkRequest(QUrl(DownloadJobs[currentItem].DownloadURL)));
            else  currentNetworkReply = getAmazonPictureURL->get(QNetworkRequest(QUrl(DownloadJobs[currentItem].DownloadURL)));

            timeout->start(15000); // Timeout 15 seconds
            emit signal_updateDownloadInfos();
        } else {
            previewCovers();
        }
    } else previewCovers();

    reply->deleteLater();
}


// *********************************************************************************************
// Request timeout (15 seconds)
// *********************************************************************************************
void CoverDownload::Timeout(){
    timeout->stop();

    if (!isDownloadJobRunning) return;
    if (currentNetworkReply) currentNetworkReply->abort();
    currentNetworkReply->deleteLater();
    if (currentItem < DownloadJobs.size() && !DownloadJobs[currentItem].PictureAlternatives.isEmpty()){
        currentNetworkReply->deleteLater();
        if (searchEngine == GOOGLE) currentNetworkReply = DownloaderPicture->get(QNetworkRequest(QUrl::fromEncoded(DownloadJobs[currentItem].PictureAlternatives.takeFirst().toLatin1())));
        else currentNetworkReply = getAmazonPictureURL->get(QNetworkRequest(QUrl::fromEncoded(DownloadJobs[currentItem].PictureAlternatives.takeFirst().toLatin1())));

        timeout->start(15000); // Timeout 15 seconds
    } else emit signal_allDownloadsFinished();
}


// *********************************************************************************************
// Open dialog to preview the downloaded covers
// *********************************************************************************************
void CoverDownload::previewCovers(){
    timeout->stop();

    if (p_Dialog) {
        setCoverPicture(p_horizontalSlider->value());
        return;
    }

    isDownloadJobRunning = false;

    // Remove failed downloads from list
    for (int i=DownloadJobs.size() - 1; i>=0; i--){
        if (!QFile::exists(DownloadJobs[i].DownloadFolder + "/cover.jpg")) DownloadJobs.removeAt(i);
    }

    if (DownloadJobs.isEmpty()) {
        emit signal_allDownloadsFinished();
        return;
    }

    QDialog Dialog(this);
    QPushButton pushButton;
    QWidget widget;
    QVBoxLayout verticalLayout;
    QVBoxLayout verticalLayout2;
    QLabel CoverInfos;
    QLabel Picture;
    QSlider horizontalSlider;

    Dialog.resize(195, 271);
    Dialog.setMinimumSize(QSize(195, 271));
    Dialog.setMaximumSize(QSize(195, 271));
    pushButton.setGeometry(QRect(100, 240, 93, 27));
    pushButton.setText("Close");

    widget.setGeometry(QRect(7, 10, 181, 221));
    verticalLayout.setContentsMargins(0, 0, 0, 0);

    QFont font;
    font.setFamily(QString::fromUtf8("Bitstream Charter"));
    font.setPointSize(8);
    CoverInfos.setFont(font);

    Picture.setMinimumSize(QSize(175, 175));
    Picture.setMaximumSize(QSize(175, 175));
    Picture.setScaledContents(true);

    horizontalSlider.setPageStep(1);
    horizontalSlider.setMinimum(1);
    horizontalSlider.setOrientation(Qt::Horizontal);

    verticalLayout.addWidget(&CoverInfos);
    verticalLayout.addWidget(&Picture);
    verticalLayout.addWidget(&horizontalSlider);
    widget.setLayout(&verticalLayout);

    verticalLayout2.addWidget(&widget);
    verticalLayout2.addWidget(&pushButton);
    Dialog.setLayout(&verticalLayout2);

    QObject::connect(&pushButton, SIGNAL(clicked()), &Dialog, SLOT(accept()));
    QObject::connect(&horizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(setCoverPicture(int)));

    QAction actionLoadAnother(QPixmap(":/Icons/Download.png"), tr("Load another Cover"), &Dialog);
    QObject::connect(&actionLoadAnother, SIGNAL(triggered()), this, SLOT(LoadAnotherCover()));
    if (!DownloadJobs[0].PictureAlternatives.isEmpty()) Picture.addAction(&actionLoadAnother);

    QAction actionDelete(QPixmap(":/Icons/unavailable.png"), tr("Delete Cover"), &Dialog);
    QObject::connect(&actionDelete, SIGNAL(triggered()), this, SLOT(deleteCover()));

    Picture.addAction(&actionDelete);
    Picture.setContextMenuPolicy(Qt::ActionsContextMenu);

    p_CoverInfos        = &CoverInfos;
    p_Picture           = &Picture;
    p_Dialog            = &Dialog;
    p_horizontalSlider  = &horizontalSlider;
    p_actionLoadAnother = &actionLoadAnother;
    setCoverPicture(1);
    Dialog.exec();

    p_Dialog = 0;
    isCancelAllJobs      = false;
    currentItem          = 0;
    Errors               = 0;
    Skipped              = 0;
    DownloadJobs.clear();
    emit signal_allDownloadsFinished();
}


// *********************************************************************************************
// Change displayed values of the cover preview dialog
// *********************************************************************************************
void CoverDownload::setCoverPicture(const int &Nummer){
    if (DownloadJobs.isEmpty()) {
        p_Dialog->accept();
        return;
    }

    p_horizontalSlider->setMaximum(DownloadJobs.size());
    if (DownloadJobs.size() == 1) p_horizontalSlider->setDisabled(true);
    p_CoverInfos->setText(DownloadJobs[Nummer -1].InterpretInfos);
    p_Picture->setPixmap(QPixmap(DownloadJobs[Nummer -1].DownloadFolder + "/cover.jpg"));
    p_Dialog->setWindowTitle(tr("Coverpreview %1/%2").arg(Nummer).arg(DownloadJobs.size()));
    currentItem = p_horizontalSlider->value() - 1;
    p_actionLoadAnother->setDisabled(DownloadJobs[currentItem].PictureAlternatives.isEmpty());
}


// *********************************************************************************************
// Delete cover from HDD
// *********************************************************************************************
void CoverDownload::deleteCover(){
    QFile::remove(DownloadJobs[p_horizontalSlider->value() - 1].DownloadFolder + "/cover.jpg");
    DownloadJobs.removeAt(p_horizontalSlider->value() - 1);
    setCoverPicture(qMin(p_horizontalSlider->value(), DownloadJobs.size()));
}


// *********************************************************************************************
// User requests another Cover
// *********************************************************************************************
void CoverDownload::LoadAnotherCover(){
    if (!DownloadJobs[currentItem].PictureAlternatives.isEmpty()){
        isSingleDownloadJob = true;

        if (searchEngine == GOOGLE) currentNetworkReply = DownloaderPicture->get(QNetworkRequest(QUrl::fromEncoded(DownloadJobs[currentItem].PictureAlternatives.takeFirst().toLatin1())));
        else  currentNetworkReply = getAmazonPictureURL->get(QNetworkRequest(QUrl::fromEncoded(DownloadJobs[currentItem].PictureAlternatives.takeFirst().toLatin1())));
        timeout->start(15000); // Timeout 15 seconds
    }
}
