/***************************************************************************
 *   Copyright (C) 2013-2025 by Ilya Kotov                                 *
 *   forkotov02@ya.ru                                                      *
 *                                                                         *
 *   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.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/

#include <QStringList>
#include <QDateTime>
#include <QFileInfo>
#include <QPluginLoader>
#include <QApplication>
#include <QTranslator>
#include <qmmp/qmmp.h>
#include "generalfactory.h"
#include "uifactory.h"
#include "filedialogfactory.h"
#include "qmmpuiplugincache_p.h"

QmmpUiPluginCache::QmmpUiPluginCache(const QString &file, QSettings *settings)
{
    bool update = false;
    QFileInfo info(file);
    m_path = info.QFileInfo::canonicalFilePath();

    settings->beginGroup(u"PluginCache"_s);
    QString key = m_path;
#ifndef Q_OS_WIN
    key.remove(0, 1);
#endif
    if(settings->allKeys().contains(key))

    {
        QStringList values = settings->value(m_path).toStringList();
        if(values.count() != 3)
            update = true;
        else
        {
            m_shortName = values.constFirst();
            m_priority = values.at(1).toInt();
            update = (info.lastModified().toString(Qt::ISODate) != values.at(2));
        }
    }
    else
        update = true;


    if(update)
    {
        if(GeneralFactory *factory = generalFactory())
        {
            m_shortName = factory->properties().shortName;
            m_priority = 0;
        }
        else if(UiFactory *factory = uiFactory())
        {
            m_shortName = factory->properties().shortName;
            m_priority = 0;
        }
        else if(FileDialogFactory *factory = fileDialogFactory())
        {
            m_shortName = factory->properties().shortName;
            m_priority = 0;
        }
        else
        {
            qCWarning(core, "unknown plugin type: %s", qPrintable(m_path));
            m_error = true;
        }

        if (!m_error)
        {
            QStringList values;
            values << m_shortName;
            values << QString::number(m_priority);
            values << info.lastModified().toString(Qt::ISODate);
            settings->setValue(m_path, values);
            qCDebug(core, "added cache item \"%s=%s\"", qPrintable(info.fileName()), qPrintable(values.join(QLatin1Char(','))));
        }
    }
    settings->endGroup();
}

QmmpUiPluginCache::QmmpUiPluginCache(QObject *instance)
{   
    m_instance = instance;

    if(GeneralFactory *factory = generalFactory())
    {
        m_shortName = factory->properties().shortName;
        m_priority = 0;
    }
    else if(UiFactory *factory = uiFactory())
    {
        m_shortName = factory->properties().shortName;
        m_priority = 0;
    }
    else if(FileDialogFactory *factory = fileDialogFactory())
    {
        m_shortName = factory->properties().shortName;
        m_priority = 0;
    }
    else
    {
        qCWarning(core, "unknown plugin type");
        m_error = true;
        return;
    }
    qCDebug(core) << "registered internal factory" << m_shortName;
}

const QString QmmpUiPluginCache::shortName() const
{
    return m_shortName;
}

const QString QmmpUiPluginCache::file() const
{
    return m_path;
}

int QmmpUiPluginCache::priority() const
{
    return m_priority;
}

bool QmmpUiPluginCache::hasError() const
{
    return m_error;
}

GeneralFactory *QmmpUiPluginCache::generalFactory()
{
    if(!m_generalFactory)
    {
        m_generalFactory = qobject_cast<GeneralFactory *> (instance());
        if(m_generalFactory)
            loadTranslation(m_generalFactory->translation());
    }
    return m_generalFactory;
}

UiFactory *QmmpUiPluginCache::uiFactory()
{
    if(!m_uiFactory)
    {
        m_uiFactory = qobject_cast<UiFactory *> (instance());
        if(m_uiFactory)
            loadTranslation(m_uiFactory->translation());
    }
    return m_uiFactory;
}

FileDialogFactory *QmmpUiPluginCache::fileDialogFactory()
{
    if(!m_fileDialogFactory)
    {
        m_fileDialogFactory = qobject_cast<FileDialogFactory *> (instance());
        if(m_fileDialogFactory)
            loadTranslation(m_fileDialogFactory->translation());
    }
    return m_fileDialogFactory;
}

QObject *QmmpUiPluginCache::instance()
{
    if(m_error)
        return nullptr;
    if(m_instance)
        return m_instance;
    QPluginLoader loader(m_path);
    m_instance = loader.instance();
    if (loader.isLoaded())
        qCDebug(core) << "loaded plugin" << QFileInfo(m_path).fileName();
    else
    {
        m_error = true;
        qCWarning(core, "error: %s", qPrintable(loader.errorString ()));
    }
    return m_instance;
}

void QmmpUiPluginCache::loadTranslation(const QString &translation)
{
    if(!translation.isEmpty())
    {
        QTranslator *translator = new QTranslator(qApp);
        if(translator->load(translation + Qmmp::systemLanguageID()))
            qApp->installTranslator(translator);
        else
            delete translator;
    }
}

void QmmpUiPluginCache::cleanup(QSettings *settings)
{
    settings->beginGroup(u"PluginCache"_s);

    for(const QString &key : settings->allKeys())
    {
#ifdef Q_OS_WIN
        if(!QFile::exists(key))
#else
        if(!QFile::exists(QLatin1Char('/') + key))
#endif
        {
            settings->remove(key);
            qCDebug(core) << "removed key" << key;
        }
    }
    settings->endGroup();
}
