/*
 * Cantata
 *
 * Copyright (c) 2011-2022 Craig Drummond <craig.p.drummond@gmail.com>
 *
 * ----
 *
 * 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; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "currentcover.h"
#include "covers.h"
#include "config.h"
#include "widgets/icons.h"
#include "support/utils.h"
#include "support/globalstatic.h"
#include "online/onlineservice.h"
#include <QFile>
#include <QTimer>

#if !defined Q_OS_WIN && !defined Q_OS_MAC
static void themes(const QString &theme, QStringList &iconThemes)
{
    if (iconThemes.contains(theme)) {
        return;
    }
    QString lower=theme.toLower();
    iconThemes << theme;
    if (lower!=theme) {
        iconThemes << lower;
    }
    QStringList paths=QIcon::themeSearchPaths();
    QString key("Inherits=");
    for (const QString &p: paths) {
        QString index(p+"/"+theme+"/index.theme");
        QFile f(index);
        if (f.open(QIODevice::ReadOnly|QIODevice::Text)) {
            while (!f.atEnd()) {
                QString line=QString::fromUtf8(f.readLine()).trimmed().simplified();
                if (line.startsWith(key)) {
                    QStringList inherited=line.mid(key.length()).split(",", CANTATA_SKIP_EMPTY);
                    for (const QString &i: inherited) {
                        themes(i, iconThemes);
                    }
                    return;
                }
            }
        }
    }
}

void CurrentCover::initIconThemes()
{
    if (iconThemes.isEmpty()) {
        themes(QIcon::themeName(), iconThemes);
    }
}

QString CurrentCover::findIcon(const QStringList &names)
{
    initIconThemes();
    QList<int> sizes=QList<int>() << 256 << 128 << 64 << 48 << 32 << 24 << 22;
    QStringList paths=QIcon::themeSearchPaths();
    QStringList sections=QStringList() << "apps" << "categories" << "devices" << "mimetypes" << "mimes";
    for (const QString &theme: iconThemes) {
        for (const QString &n: names) {
            for (const QString &p: paths) {
                QMap<int, QString> files;
                for (int s: sizes) {
                    for (const QString &sect: sections) {
                        QString f(p+"/"+theme+"/"+QString::number(s)+"x"+QString::number(s)+"/"+sect+"/"+n+".png");
                        if (QFile::exists(f)) {
                            files.insert(s, f);
                            break;
                        }
                        f=QString(p+"/"+theme+"/"+QString::number(s)+"x"+QString::number(s)+"/"+sect+"/"+n+".svg");
                        if (QFile::exists(f)) {
                            files.insert(s, f);
                            break;
                        }
                        f=QString(p+"/"+theme+"/"+sect+"/"+QString::number(s)+"/"+n+".svg");
                        if (QFile::exists(f)) {
                            files.insert(s, f);
                            break;
                        }
                    }
                }

                if (!files.isEmpty()) {
                    for (int s: sizes) {
                        if (files.contains(s)) {
                            return files[s];
                        }
                    }
                }
            }
        }
    }
    return QString();
}
#endif

GLOBAL_STATIC(CurrentCover, instance)

CurrentCover::CurrentCover()
    : QObject(nullptr)
    , enabled(false)
    , valid(false)
    , timer(nullptr)
{
    img=stdImage(current);
    coverFileName=noCoverFileName;
}

CurrentCover::~CurrentCover()
{
}

const QImage & CurrentCover::stdImage(const Song &s)
{
    bool podcast=s.isFromOnlineService() && OnlineService::isPodcasts(s.onlineService());
    bool stream=s.isStandardStream() || OnlineService::showLogoAsCover(s);

    QImage &img=podcast
                ? noPodcastCover
                : stream
                    ? noStreamCover
                    : noCover;

    if (img.isNull()) {
        int iconSize=Icon::stdSize(Utils::scaleForDpi(128));
        const QIcon &icon=podcast
                ? Icons::self()->podcastIcon
                : stream
                    ? Icons::self()->streamIcon
                    : Icons::self()->albumIcon(iconSize);
        img=icon.pixmap(iconSize, iconSize).toImage();

        QString &file=podcast
                      ? noPodcastCoverFileName
                      : stream
                          ? noStreamCoverFileName
                          : noCoverFileName;

        if (file.isEmpty()) {
            if (podcast) {
                QString iconFile=QString(CANTATA_SYS_ICONS_DIR+"podcasts.png");
                if (QFile::exists(iconFile)) {
                    file=iconFile;
                }
            } else if (stream) {
                QString iconFile=QString(CANTATA_SYS_ICONS_DIR+"stream.png");
                if (QFile::exists(iconFile)) {
                    file=iconFile;
                }
            }
        }
        #if !defined Q_OS_WIN && !defined Q_OS_MAC
        if (file.isEmpty()) {
            QStringList iconNames=podcast
                    ? QStringList{ QStringLiteral("x-media-podcast"), QStringLiteral("news-feed"), QStringLiteral("application-rss+xml"), QStringLiteral("application-atom+xml") }
                    : stream
                        ? QStringList{ QStringLiteral("applications-internet") }
                        : QStringList{ QStringLiteral("media-optical"), QStringLiteral("media-optical-audio") };
            file=findIcon(iconNames);
        }
        #endif
    }
    return img;
}

void CurrentCover::setEnabled(bool e)
{
    if (enabled==e) {
        return;
    }

    enabled=e;
    if (enabled) {
        img=stdImage(Song());
        connect(Covers::self(), SIGNAL(cover(const Song &, const QImage &, const QString &)), this, SLOT(coverRetrieved(const Song &, const QImage &, const QString &)));
        connect(Covers::self(), SIGNAL(coverUpdated(const Song &, const QImage &, const QString &)), this, SLOT(coverRetrieved(const Song &, const QImage &, const QString &)));
    } else {
        disconnect(Covers::self(), SIGNAL(cover(const Song &, const QImage &, const QString &)), this, SLOT(coverRetrieved(const Song &, const QImage &, const QString &)));
        disconnect(Covers::self(), SIGNAL(coverUpdated(const Song &, const QImage &, const QString &)), this, SLOT(coverRetrieved(const Song &, const QImage &, const QString &)));
        current=Song();
    }
}

void CurrentCover::update(const Song &s)
{
    if (!enabled) {
        return;
    }

    if (s.albumArtist()!=current.albumArtist() || s.album!=current.album || s.isStream()!=current.isStream() ||
        s.onlineService()!=current.onlineService()) {
        current=s;
        if (timer) {
            timer->stop();
        }
        if (!s.isUnknownAlbum() && ((!s.albumArtist().isEmpty() && !s.album.isEmpty() && !current.isStandardStream()) || OnlineService::showLogoAsCover(s))) {
            Covers::Image cImg=Covers::self()->requestImage(s, true);
            valid=!cImg.img.isNull();
            if (valid) {
                coverFileName=cImg.fileName;
                img=cImg.img;
                emit coverFile(cImg.fileName);
                if (current.isFromOnlineService()) {
                    if (coverFileName.startsWith(CANTATA_SYS_ICONS_DIR)) {
                        emit coverImage(QImage());
                    } else {
                        emit coverImage(cImg.img);
                    }
                } else {
                    emit coverImage(cImg.img);
                }
            } else {
                // We need to set the image here, so that TrayItem gets the correct 'noCover' image
                // ...but if Covers does eventually download a cover, we dont want valid->noCover->valid
                img=stdImage(current);
                // Start a timer - in case cover retrieval fails...
                if (!timer) {
                    timer=new QTimer(this);
                    timer->setSingleShot(true);
                    connect(timer, SIGNAL(timeout()), this, SLOT(setDefault()));
                }
                timer->start(750);
            }
        } else {
            valid=true;
            img=stdImage(current);
            setDefault();
        }
    }
}

void CurrentCover::coverRetrieved(const Song &s, const QImage &newImage, const QString &file)
{
    if (!s.isArtistImageRequest() && s.albumArtist()==current.albumArtist() && s.album==current.album) {
        if (timer) {
            timer->stop();
        }
        valid=!newImage.isNull();
        if (valid) {
            coverFileName=file;
            img=newImage;
            emit coverFile(file);
            emit coverImage(newImage);
        } else {
            setDefault();
        }
    }
}

void CurrentCover::setDefault()
{
    bool podcast=current.isFromOnlineService() && OnlineService::isPodcasts(current.onlineService());
    bool stream=current.isStandardStream() || OnlineService::showLogoAsCover(current);

    coverFileName=podcast
                  ? noPodcastCoverFileName
                  : stream
                      ? noStreamCoverFileName
                      : noCoverFileName;

    emit coverFile(coverFileName);
    emit coverImage(QImage());
}

#include "moc_currentcover.cpp"
