/***************************************************************************
  AmplifyFreePlugin.cpp  -  Plugin for free amplification curves
                             -------------------
    begin                : Sun Sep 02 2001
    copyright            : (C) 2001 by Thomas Eschenbacher
    email                : 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 <new>

#include <QPointer>
#include <QStringList>

#include <KLocalizedString>

#include "libkwave/Connect.h"
#include "libkwave/MultiTrackReader.h"
#include "libkwave/MultiTrackSource.h"
#include "libkwave/MultiTrackWriter.h"
#include "libkwave/Parser.h"
#include "libkwave/PluginManager.h"
#include "libkwave/String.h"
#include "libkwave/modules/CurveStreamAdapter.h"
#include "libkwave/modules/Mul.h"
#include "libkwave/undo/UndoTransactionGuard.h"

#include "AmplifyFreeDialog.h"
#include "AmplifyFreePlugin.h"

KWAVE_PLUGIN(amplifyfree, AmplifyFreePlugin)

//***************************************************************************
Kwave::AmplifyFreePlugin::AmplifyFreePlugin(QObject *parent,
                                            const QVariantList &args)
    :Kwave::Plugin(parent, args),
     m_action_name(), m_params(), m_curve(), m_cmd_map()
{
    m_cmd_map[_("fade in")]      = i18n("Fade In");
    m_cmd_map[_("fade out")]     = i18n("Fade Out");
    m_cmd_map[_("fade intro")]   = i18n("Fade Intro");
    m_cmd_map[_("fade leadout")] = i18n("Fade Leadout");
}

//***************************************************************************
Kwave::AmplifyFreePlugin::~AmplifyFreePlugin()
{
}

//***************************************************************************
int Kwave::AmplifyFreePlugin::interpreteParameters(QStringList &params)
{
    // store last parameters
    m_params = params;

    m_action_name = _("");
    if (params.count() < 2) return -1;
    if (params.count() & 1) return -1; // no. of params must be even

    // first list entry == name of operation
    m_action_name = (params[0].length() && m_cmd_map.contains(params[0])) ?
         m_cmd_map[params[0]] : i18n("Amplify Free");

    // convert string list into command again...
    QString cmd = _("curve(");
    for (int i = 1; i < params.count(); ++i) {
        cmd += params[i];
        if ((i + 1) < params.count()) cmd += _(",");
    }
    cmd += _(")");

    // and initialize our curve with it
    m_curve.fromCommand(cmd);

    return 0;
}

//***************************************************************************
QStringList *Kwave::AmplifyFreePlugin::setup(QStringList &previous_params)
{
    // try to interpret the previous parameters
    interpreteParameters(previous_params);

    // create the setup dialog
    QPointer<Kwave::AmplifyFreeDialog> dialog =
        new(std::nothrow) Kwave::AmplifyFreeDialog(parentWidget());
    Q_ASSERT(dialog);
    if (!dialog) return nullptr;

    // remove the first list entry (action name), the rest is for the dialog
    if ((m_params.count() > 2) && !(m_params.count() & 1)) {
        QStringList curve_params = m_params;
        curve_params.takeFirst(); // ignore action name
        dialog->setParams(curve_params);
    }

    QStringList *list = new(std::nothrow) QStringList();
    Q_ASSERT(list);
    if (list && dialog->exec() && dialog) {
        // user has pressed "OK"
        *list << _("amplify free");
        QString cmd = dialog->getCommand();
        Kwave::Parser p(cmd);
        while (!p.isDone()) *list << p.nextParam();

        qDebug("setup -> emitCommand('%s')", DBG(cmd));
        emitCommand(cmd);
    } else {
        // user pressed "Cancel"
        delete list;
        list = nullptr;
    }

    delete dialog;
    return list;
}

//***************************************************************************
QString Kwave::AmplifyFreePlugin::progressText()
{
    return m_action_name;
}

//***************************************************************************
int Kwave::AmplifyFreePlugin::start(QStringList &params)
{
    interpreteParameters(params);
    return Kwave::Plugin::start(params);
}

//***************************************************************************
void Kwave::AmplifyFreePlugin::run(QStringList params)
{
    sample_index_t first, last;
    QVector<unsigned int> track_list;

    interpreteParameters(params);

    Kwave::UndoTransactionGuard undo_guard(*this, m_action_name);

    sample_index_t input_length = selection(&track_list, &first, &last, true);
    unsigned int   tracks = static_cast<unsigned int>(track_list.count());

    // create all objects
    Kwave::MultiTrackReader source(Kwave::SinglePassForward,
        signalManager(), selectedTracks(), first, last);
    Kwave::CurveStreamAdapter curve(m_curve, input_length);
    Kwave::MultiTrackWriter sink(signalManager(), track_list, Kwave::Overwrite,
        first, last);
    Kwave::MultiTrackSource<Kwave::Mul, true> mul(tracks, this);

    // break if aborted
    if (!sink.tracks()) return;

    // connect them
    bool ok = Kwave::connect(
        source, SIGNAL(output(Kwave::SampleArray)),
        mul,    SLOT(input_a(Kwave::SampleArray)));
    if (ok) ok = Kwave::connect(
        curve,  SIGNAL(output(Kwave::SampleArray)),
        mul,    SLOT(input_b(Kwave::SampleArray)));
    if (ok) ok = Kwave::connect(
        mul,    SIGNAL(output(Kwave::SampleArray)),
        sink,   SLOT(input(Kwave::SampleArray)));
    if (!ok) {
        return;
    }

    // connect the progress dialog
    connect(&sink, SIGNAL(progress(qreal)),
            this,  SLOT(updateProgress(qreal)),
            Qt::BlockingQueuedConnection);

    // transport the samples
    qDebug("AmplifyFreePlugin: filter started...");
    while (!shouldStop() && !source.done()) {
        source.goOn();
        curve.goOn();
        /* mul.goOn(); */
    }
    qDebug("AmplifyFreePlugin: filter done.");
}

//***************************************************************************
#include "AmplifyFreePlugin.moc"
//***************************************************************************
//***************************************************************************

#include "moc_AmplifyFreePlugin.cpp"
