// Copyright (c) 2001 Charles Samuels <charles@kde.org>
// Copyright (c) 2001 Neil Stevens <neil@qualityassistant.com>
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "effects.h"
#include "effectview.h"
#include "app.h"

#include <kcombobox.h>
#include <kdialog.h>
#include <kiconloader.h>
#include <tdelocale.h>
#include <tqdragobject.h>
#include <tqheader.h>
#include <tqhgroupbox.h>
#include <tqlabel.h>
#include <tqlayout.h>
#include <tqpushbutton.h>
#include <tqtextedit.h>
#include <tqtoolbutton.h>
#include <tqvgroupbox.h>
#include <tqwhatsthis.h>

class EffectListItem : public TQListViewItem
{
public:
	EffectListItem(TQListView *parent, TQListViewItem *after, Effect *e)
		: TQListViewItem(parent, after, e->title()), mEffect(e)
	{
	}

	Effect *effect() const { return mEffect; }

private:
	Effect *mEffect;
};

EffectList::EffectList(TQWidget *parent)
	: TDEListView(parent)
{
}

bool EffectList::acceptDrag(TQDropEvent *event) const
{
	return TQCString(event->format()) == "application/x-noatun-effectdrag";
}

TQDragObject *EffectList::dragObject() const
{
	if (!currentItem()) return 0;
	return new TQStoredDrag("application/x-noatun-effectdrag", (TQWidget*)this);
}

EffectView::EffectView()
	: KDialogBase((TQWidget*)0L, 0, false, i18n("Effects"), Help | Close, Close, true)
	, initialized(false)
{
}

void EffectView::show()
{
	init();
	KDialogBase::show();
}

namespace
{
TQToolButton *newButton(const TQIconSet &iconSet, const TQString &textLabel, TQObject *receiver, const char * slot, TQWidget *parent, const char *name = 0)
{
	TQToolButton *button = new TQToolButton(parent, name);
	button->setIconSet(iconSet);
	button->setTextLabel(textLabel, true);
	TQObject::connect(button, TQ_SIGNAL(clicked()), receiver, slot);
	button->setFixedSize(TQSize(22, 22));
	return button;
}
}

void EffectView::init(void)
{
	if(initialized) return;
	initialized = true;

	setCaption(i18n("Effects - Noatun"));
	setIcon(SmallIcon("effect"));

	// Create widgets and layouts
	TQFrame *box = makeMainWidget();
	TQVBoxLayout *boxLayout = new TQVBoxLayout(box, 0, KDialog::spacingHint());

	// Available
	TQVGroupBox *topBox = new TQVGroupBox(i18n("Available Effects"), box);
	topBox->setInsideSpacing(KDialog::spacingHint());

	TQFrame *topTopFrame = new TQFrame(topBox);
	TQHBoxLayout *topTopLayout = new TQHBoxLayout(topTopFrame, 0, KDialog::spacingHint());
	topTopLayout->setAutoAdd(true);
	available = new KComboBox(false, topTopFrame);
	TQToolButton *add = newButton(BarIconSet("go-down", TDEIcon::SizeSmall), i18n("Add"), this, TQ_SLOT(addEffect()), topTopFrame);

	// Active
	TQHGroupBox *bottomBox = new TQHGroupBox(i18n("Active Effects"), box);
	bottomBox->setInsideSpacing(KDialog::spacingHint());

	active = new EffectList(bottomBox);

	boxLayout->addWidget(topBox);
	boxLayout->addWidget(bottomBox);

	// Fill and configure widgets
	available->insertStrList(napp->effects()->available());

	active->setAcceptDrops(true);
	active->addColumn("");
	active->header()->hide();
	active->setSorting(-1);
	active->setDropVisualizer(true);
	active->setItemsMovable(true);
	active->setSelectionMode(TQListView::Single);
	active->setDragEnabled(true);
	connect(active, TQ_SIGNAL(dropped(TQDropEvent *, TQListViewItem *)), TQ_SLOT(activeDrop(TQDropEvent *, TQListViewItem *)));

	// when a new effect is added
	connect(napp->effects(), TQ_SIGNAL(added(Effect *)), TQ_SLOT(added(Effect *)));
	connect(napp->effects(), TQ_SIGNAL(removed(Effect *)), TQ_SLOT(removed(Effect *)));
	connect(napp->effects(), TQ_SIGNAL(moved(Effect *)), TQ_SLOT(moved(Effect *)));

	available->setCurrentItem(0);

	connect(active, TQ_SIGNAL(currentChanged(TQListViewItem *)), TQ_SLOT(activeChanged(TQListViewItem *)));
	active->setCurrentItem(0);

	// the buttons
	TQFrame *bottomLeftFrame = new TQFrame(bottomBox);
	TQVBoxLayout *bottomLeftLayout = new TQVBoxLayout(bottomLeftFrame, 0, KDialog::spacingHint());
	up = newButton(BarIconSet("go-up", TDEIcon::SizeSmall), i18n("Up"), this, TQ_SLOT(moveUp()), bottomLeftFrame);
	down = newButton(BarIconSet("go-down", TDEIcon::SizeSmall), i18n("Down"), this, TQ_SLOT(moveDown()), bottomLeftFrame);
	configure = newButton(BarIconSet("configure", TDEIcon::SizeSmall), i18n("Configure"), this, TQ_SLOT(configureEffect()), bottomLeftFrame);
	remove = newButton(BarIconSet("remove", TDEIcon::SizeSmall), i18n("Remove"), this, TQ_SLOT(removeEffect()), bottomLeftFrame);
	bottomLeftLayout->addWidget(up);
	bottomLeftLayout->addWidget(down);
	bottomLeftLayout->addWidget(configure);
	bottomLeftLayout->addWidget(remove);
	bottomLeftLayout->addStretch();


	activeChanged(active->currentItem());

	// Inline documentation
	TQWhatsThis::add(available, i18n("This shows all available effects.\n\nTo activate a plugin, drag files from here to the active pane on the right."));
	TQWhatsThis::add(add, i18n("This will place the selected effect at the bottom of your chain."));
	TQWhatsThis::add(active, i18n("This shows your effect chain. Noatun supports an unlimited amount of effects in any order. You can even have the same effect twice.\n\nDrag the items to and from here to add and remove them, respectively. You may also reorder them with drag-and-drop. These actions can also be performed with the buttons to the right."));
	TQWhatsThis::add(up, i18n("Move the currently selected effect up in the chain."));
	TQWhatsThis::add(down, i18n("Move the currently selected effect down in the chain."));
	TQWhatsThis::add(configure, i18n("Configure the currently selected effect.\n\nYou can change things such as intensity from here."));
	TQWhatsThis::add(remove, i18n("This will remove the selected effect from your chain."));

	resize(300, 400);
}

void EffectView::activeDrop(TQDropEvent *, TQListViewItem *pafter)
{
	EffectListItem *after(static_cast<EffectListItem*>(pafter));
	napp->effects()->move(after ? after->effect() : 0,
	                      static_cast<EffectListItem*>(active->currentItem())->effect());
	activeChanged(active->currentItem());
}

TQListViewItem *EffectView::toListItem(Effect *e) const
{
	for(TQListViewItem *i = active->firstChild(); i; i = i->itemBelow())
		if(static_cast<EffectListItem*>(i)->effect() == e)
			return i;
	return 0;
}

void EffectView::added(Effect *item)
{
	new EffectListItem(active, toListItem(item->before()), item);
	activeChanged(active->currentItem());
}

void EffectView::moved(Effect *item)
{
	delete toListItem(item);
	added(item);
}

void EffectView::removed(Effect *item)
{
	delete toListItem(item);
	activeChanged(active->currentItem());
}

void EffectView::moveDown()
{
	Effect *e = static_cast<EffectListItem*>(active->currentItem())->effect();

	if(e->after())
		napp->effects()->move(e->after(), e);
	active->setCurrentItem(toListItem(e));
	active->setSelected(toListItem(e), true);
	activeChanged(active->currentItem());
}

void EffectView::moveUp()
{
	Effect *e = static_cast<EffectListItem*>(active->currentItem())->effect();
	if (e->before())
	{
		if (e->before()->before())
			napp->effects()->move(e->before()->before(), e);
		else
			napp->effects()->move(0, e);
	}
	active->setCurrentItem(toListItem(e));
	active->setSelected(toListItem(e), true);
	activeChanged(active->currentItem());
}

void EffectView::removeEffect()
{
	EffectListItem *item = static_cast<EffectListItem*>(active->currentItem());
	napp->effects()->remove(item->effect());
	activeChanged(active->currentItem());
}

void EffectView::addEffect()
{
	// local8Bit() and arts makes me nervous
	napp->effects()->append(new Effect(available->currentText().local8Bit()));
	activeChanged(active->currentItem());
}

void EffectView::configureEffect()
{
	Effect *e = static_cast<EffectListItem*>(active->currentItem())->effect();
	if(!e) return;

	TQWidget *c = e->configure();
	if(c) c->show();
}

void EffectView::activeChanged(TQListViewItem *i)
{
	if(i)
	{
		up->setEnabled(i->itemAbove());
		down->setEnabled(i->itemBelow());
		remove->setEnabled(true);

		Effect *e = static_cast<EffectListItem*>(active->currentItem())->effect();
		configure->setEnabled(e->configurable());
	}
	else
	{
		up->setEnabled(false);
		down->setEnabled(false);
		remove->setEnabled(false);
		configure->setEnabled(false);
	}
}

#include "effectview.moc"
