/*************************************************************************
        DebugPlugin.cpp  -  various debug aids
                             -------------------
    begin                : Mon Feb 02 2009
    copyright            : (C) 2009 by Thomas Eschenbacher
    email                : Thomas.Eschenbacher@gmx.de
 ***************************************************************************/

#include "config.h"
#include <math.h>
#include <klocale.h> // for the i18n macro

#include <QtCore/QList>
#include <QtCore/QStringList>

#include "libkwave/MultiTrackWriter.h"
#include "libkwave/PluginManager.h"
#include "libkwave/SignalManager.h"
#include "libkwave/String.h"
#include "libkwave/Writer.h"
#include "libkwave/undo/UndoTransactionGuard.h"

#include "libgui/SelectTimeWidget.h" // for selection mode

#include "DebugPlugin.h"

KWAVE_PLUGIN(Kwave::DebugPlugin, "debug", "2.3",
             I18N_NOOP("Debug Functions"), "Thomas Eschenbacher");

/** size of the internal buffer */
#define BUFFER_SIZE (64 * 1024)

/** helper for generating menu entries */
#define MENU_ENTRY(cmd,txt) \
    emitCommand(entry.arg(_(cmd)).arg(txt));

//***************************************************************************
Kwave::DebugPlugin::DebugPlugin(Kwave::PluginManager &plugin_manager)
    :Kwave::Plugin(plugin_manager), m_buffer()
{
}

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

//***************************************************************************
void Kwave::DebugPlugin::load(QStringList &params)
{
    Q_UNUSED(params);

    QString entry = _("menu (plugin:execute(debug,%1),&Calculate/Debug/%2)");

    MENU_ENTRY("dc_50",             _(I18N_NOOP("Generate 50% DC Level")));
    MENU_ENTRY("dc_100",            _(I18N_NOOP("Generate 100% DC Level")));
    MENU_ENTRY("min_max",           _(I18N_NOOP("MinMax Pattern")));
    MENU_ENTRY("sawtooth",          _(I18N_NOOP("Generate Sawtooth Pattern")));
//     MENU_ENTRY("sawtooth",          _(I18N_NOOP("Verify Sawtooth Pattern")));
//     MENU_ENTRY("stripe_index",      _(I18N_NOOP("Stripe Index")));
//     MENU_ENTRY("hull_curve",        _(I18N_NOOP("Hull Curve")));
//     MENU_ENTRY("offset_in_stripe",  _(I18N_NOOP("Offset in Stripe")));
//     MENU_ENTRY("stripe_borders",    _(I18N_NOOP("Show Stripe Borders")));
//     MENU_ENTRY("labels_at_stripes", _(I18N_NOOP("Labels at Stripe borders")));

    emitCommand(_("menu (dump_metadata(), ") +
                _(I18N_NOOP("&Help")) + _("/") +
                _(I18N_NOOP("Dump &Meta Data")) + _(")"));
}

//***************************************************************************
void Kwave::DebugPlugin::run(QStringList params)
{
    sample_index_t first = 0;
    sample_index_t last  = 0;

    if (params.count() != 1) return;

    QString command = params.first();
    QString action = i18n("Debug (%1)", command);
    Kwave::UndoTransactionGuard undo_guard(*this, action);

    // get the buffer for faster processing
    if (m_buffer.size() != BUFFER_SIZE) {
	m_buffer.resize(BUFFER_SIZE);
	m_buffer.fill(0);
    }
    Q_ASSERT(m_buffer.size() == BUFFER_SIZE);

    bool make_new_track = (
	(command == _("stripe_index")) ||
	(command == _("offset_in_stripe")) ||
	(command == _("stripe_borders"))
    );

    if (command == _("min_max")) {
	// toggle between minimum and maximum possible sample value
	for (unsigned int i = 0; i < BUFFER_SIZE; i++)
	    m_buffer[i] = (i & 1) ? SAMPLE_MIN : SAMPLE_MAX;
    }

    Kwave::MultiTrackWriter *writers = 0;

    if (make_new_track) {
	// append a new track
	signalManager().appendTrack();

	// and use only the new track as target
	last = signalLength() - 1;
	QList<unsigned int> track_list;
	track_list.append(signalManager().tracks() - 1);
	writers = new Kwave::MultiTrackWriter(signalManager(), track_list,
	                                      Kwave::Overwrite, 0, last);
    } else {
	// use all currently selected tracks
	writers = new Kwave::MultiTrackWriter(signalManager(), Kwave::Overwrite);
    }

    Q_ASSERT(writers);
    if (!writers) return; // out-of-memory

    // break if aborted
    if (!writers->tracks()) return;

    first = (*writers)[0]->first();
    last  = (*writers)[0]->last();
    unsigned int count = writers->tracks();

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

    // loop over the sample range
    sample_t v = 0;
    while ((first <= last) && (!shouldStop())) {
	unsigned int rest = last - first + 1;
	if (rest < m_buffer.size()) m_buffer.resize(rest);

	// sawtooth pattern from min to max
	if (command == _("sawtooth")) {
	    unsigned int shift = SAMPLE_BITS -
		Kwave::FileInfo(signalManager().metaData()).bits();
	    for (unsigned int i = 0; i < m_buffer.size(); i++) {
		m_buffer[i] = v;
		v += (1 << shift);
		if (v > SAMPLE_MAX) v = 0;
	    }
	} else if (command == _("dc_50")) {
	    const sample_t s = float2sample(0.5);
	    for (unsigned int i = 0; i < m_buffer.size(); i++) {
		m_buffer[i] = s;
	    }
	} else if (command == _("dc_100")) {
	    const sample_t s = SAMPLE_MAX;
	    for (unsigned int i = 0; i < m_buffer.size(); i++) {
		m_buffer[i] = s;
	    }
	}

	// loop over all writers
	for (unsigned int w = 0; w < count; w++) {
	    *((*writers)[w]) << m_buffer;
	}

	first += m_buffer.size();
    }

    delete writers;
}

//***************************************************************************
#include "DebugPlugin.moc"
//***************************************************************************
//***************************************************************************
