/***************************************************************************
       CodecManager.cpp  -  manager for Kwave's coders and decoders
                             -------------------
    begin                : Mar 10 2002
    copyright            : (C) 2002 by Thomas Eschenbacher
    email                : Thomas Eschenbacher <thomas.eschenbacher@gmx.de>
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 "config.h"

#include <QLatin1Char>
#include <QMimeData>
#include <QMimeDatabase>
#include <QMimeType>
#include <QRegularExpression>

#include "libkwave/CodecManager.h"
#include "libkwave/Decoder.h"
#include "libkwave/Encoder.h"
#include "libkwave/String.h"

//***************************************************************************
/* static initializers */
QList<Kwave::Encoder *> Kwave::CodecManager::m_encoders;
QList<Kwave::Decoder *> Kwave::CodecManager::m_decoders;

//***************************************************************************
//***************************************************************************
Kwave::CodecManager::CodecManager()
{
}

//***************************************************************************
Kwave::CodecManager::~CodecManager()
{
    Q_ASSERT(m_encoders.isEmpty());
    Q_ASSERT(m_decoders.isEmpty());
}

//***************************************************************************
void Kwave::CodecManager::registerEncoder(Kwave::Encoder &encoder)
{
    if (m_encoders.contains(&encoder)) return; /* already known */
    m_encoders.append(&encoder);
}

//***************************************************************************
void Kwave::CodecManager::unregisterEncoder(Kwave::Encoder *encoder)
{
    if (!m_encoders.contains(encoder)) return; /* unknown */
    m_encoders.removeAll(encoder);
}

//***************************************************************************
void Kwave::CodecManager::registerDecoder(Kwave::Decoder &decoder)
{
    if (m_decoders.contains(&decoder)) return; /* already known */
    m_decoders.append(&decoder);
}

//***************************************************************************
void Kwave::CodecManager::unregisterDecoder(Kwave::Decoder *decoder)
{
    if (!m_decoders.contains(decoder)) return; /* unknown */
    m_decoders.removeAll(decoder);
}

//***************************************************************************
bool Kwave::CodecManager::canDecode(const QString &mimetype_name)
{
    for (Kwave::Decoder *d : m_decoders)
        if (d && d->supports(mimetype_name)) return true;
    return false;
}

//***************************************************************************
QString Kwave::CodecManager::mimeTypeOf(const QUrl &url)
{
    const QString default_mime_type = QMimeType().name();

    for (Kwave::Decoder *d : m_decoders) {
        if (!d) continue;
        QString mime_type = d->mimeTypeOf(url);
        if (mime_type != default_mime_type) return mime_type;
    }
    for (Kwave::Encoder *e : m_encoders) {
        if (!e) continue;
        QString mime_type = e->mimeTypeOf(url);
        if (mime_type != default_mime_type) return mime_type;
    }

    QMimeDatabase db;
    return db.mimeTypeForUrl(url).name();
}

//***************************************************************************
QStringList Kwave::CodecManager::encodingMimeTypes()
{
    QStringList list;
    for (Kwave::Encoder *e : m_encoders) {
        if (!e) continue;
        for (const Kwave::CodecBase::MimeType &mime_type : e->mimeTypes()) {
            QString name = mime_type.name;
            if (list.isEmpty() || !list.contains(name))
                list.append(name);
        }
    }
    return list;
}

//***************************************************************************
Kwave::Decoder *Kwave::CodecManager::decoder(const QString &mimetype_name)
{
    for (Kwave::Decoder *d : m_decoders)
        if (d && d->supports(mimetype_name)) return d->instance();
    return nullptr;
}

//***************************************************************************
Kwave::Encoder *Kwave::CodecManager::encoder(const QString &mimetype_name)
{
    for (Kwave::Encoder *e : m_encoders)
        if (e && e->supports(mimetype_name)) return e->instance();
    return nullptr;
}

//***************************************************************************
QString Kwave::CodecManager::encodingFilter()
{
    QStringList list;
    for (Kwave::Encoder *e : m_encoders) {
        // loop over all mime types that the encoder supports
        QList<Kwave::CodecBase::MimeType> types = e->mimeTypes();
        QListIterator<Kwave::CodecBase::MimeType> ti(types);
        while (ti.hasNext()) {
            Kwave::CodecBase::MimeType type = ti.next();
            QString extensions = type.patterns.join(_(" "));

            // skip if extensions are already known/present
            if (!list.isEmpty() && list.join(_("\n")).contains(extensions))
                continue;

            // otherwise append to the list
            QString entry = extensions;
            QString comment = type.description.replace(
                QRegularExpression(_("/")), _(","));
            entry += _("|") + comment;
            list.append(entry + _(" (") + extensions + _(")"));
        }
    }
    list.sort();
    QString str_list = list.join(_("\n"));
    Q_ASSERT(!str_list.contains(QLatin1Char('/')));
    if (str_list.contains(QLatin1Char('/'))) {
        qWarning("CodecManager::encodingFilter() -> '%s'", DBG(str_list));
    }

    return str_list;
}

//***************************************************************************
QString Kwave::CodecManager::decodingFilter()
{
    QStringList list;
    QStringList all_extensions;

    for (Kwave::Decoder *d : m_decoders) {
        // loop over all mime types that the decoder supports
        QList<Kwave::CodecBase::MimeType> types = d->mimeTypes();
        QListIterator<Kwave::CodecBase::MimeType> ti(types);
        while (ti.hasNext()) {
            Kwave::CodecBase::MimeType type = ti.next();
            QString extensions = type.patterns.join(_(" "));

            // skip if extensions are already known/present
            if (!list.isEmpty() && list.join(_("\n")).contains(extensions))
                continue;

            // otherwise append to the list
            all_extensions += type.patterns;
            QString entry = extensions;
            QString comment = type.description.replace(
                QRegularExpression(_("/")), _(","));
            entry += _("|") + comment;
            list.append(entry + _(" (") + extensions + _(")"));
        }
    }

    // builtin type for macro files
    all_extensions += _("*.kwave");
    list.append(_("*.kwave|") + i18n("Kwave Macro Files") + _(" (*.kwave)"));

    // special entries for "all" and "all supported"
    list.sort();
    list.prepend(_("*|") + i18n("All Files"));
    list.prepend(all_extensions.join(_(" ")) + _("|") +
                 i18n("All Supported Files"));

    QString str_list = list.join(_("\n"));
    Q_ASSERT(!str_list.contains(QLatin1Char('/')));
    if (str_list.contains(QLatin1Char('/'))) {
        qWarning("CodecManager::decodingFilter() -> '%s'", DBG(str_list));
    }

    return str_list;
}

//***************************************************************************
//***************************************************************************

#include "moc_CodecManager.cpp"
