// userinterface.cpp
//
// Copyright (C) 2001 Neil Stevens <neil@qualityassistant.com>
// Copyright (C) 1999 Charles Samuels <charles@kde.org>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// 
// Except as contained in this notice, the name(s) of the author(s) shall not be
// used in advertising or otherwise to promote the sale, use or other dealings
// in this Software without prior written authorization from the author(s).

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <noatun/effects.h>
#include <noatun/app.h>
#include <noatun/controls.h>
#include <noatun/pref.h>
#include <noatun/player.h>
#include <noatun/stdaction.h>

#include "userinterface.h"

#include <kbuttonbox.h>
#include <kconfig.h>
#include <kfiledialog.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kmenubar.h>
#include <kmessagebox.h>
#include <kpixmapeffect.h>
#include <kpopupmenu.h>
#include <kstatusbar.h>
#include <kstdaction.h>
#include <kwin.h>
#include <kurldrag.h>

#include <qbitmap.h>
#include <qdragobject.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qobjectlist.h>
#include <qobjectdict.h>
#include <qpushbutton.h>
#include <qtooltip.h>
#include <qvbox.h>

Excellent::Excellent()
	: KMainWindow()
	, UserInterface()
{
	setAcceptDrops(true);

	KStdAction::quit(napp, SLOT(quit()), actionCollection());
	KStdAction::open(napp, SLOT(fileOpen()), actionCollection());
	toolbarAction = KStdAction::showToolbar(this, SLOT(showToolbar()), actionCollection());
	menubarAction = KStdAction::showMenubar(this, SLOT(showMenubar()), actionCollection());
	KStdAction::preferences(napp, SLOT(preferences()), actionCollection());

	// buttons
	NoatunStdAction::back(actionCollection(), "back");
	NoatunStdAction::stop(actionCollection(), "stop");
	NoatunStdAction::play(actionCollection(), "play");
	NoatunStdAction::pause(actionCollection(), "pause");
	NoatunStdAction::forward(actionCollection(), "forward");
	NoatunStdAction::playlist(actionCollection(), "show_playlist");

	volumeAction = new KToggleAction(i18n("Show &Volume Control"), 0, this, SLOT(showVolumeControl()), actionCollection(), "show_volumecontrol");
	NoatunStdAction::effects(actionCollection(), "effects");
	NoatunStdAction::equalizer(actionCollection(), "equalizer");
	
	loop = new KAction(i18n("L&oop Style"), 0, napp->player(), SLOT(loop()), actionCollection(), "loop_style");
	
	loop->setIcon("noatunloopnone");

	createGUI("excellentui.rc");

	menuBar()->insertItem(i18n("&Actions"), napp->pluginMenu(), -1, 3);
	toolBar("mainToolBar")->hide();

	// Who needs Qt Designer?
	mainFrame = new QHBox(this);
	mainFrame->setSpacing(KDialog::spacingHint());
	mainFrame->setMargin(0);
	slider = new L33tSlider(0, 1000, 10, 0, L33tSlider::Horizontal, mainFrame);
	slider->setTickmarks(QSlider::NoMarks);

	elapsed = new QLabel(mainFrame);
	QFont labelFont = elapsed->font();
	labelFont.setPointSize(24);
	labelFont.setBold(true);
	QFontMetrics labelFontMetrics = labelFont;
	elapsed->setFont(labelFont);
	elapsed->setAlignment(AlignCenter | AlignVCenter | ExpandTabs);
	elapsed->setText("--:--");
	elapsed->setFixedHeight(labelFontMetrics.height());
	elapsed->setMinimumWidth(elapsed->sizeHint().width());

	// Doing this makes the slider the same heigh as the font. This is just plain wrong...
	//slider->setFixedHeight(labelFontMetrics.height());
	
	setCentralWidget(mainFrame);

	total = new QLabel(statusBar());
	labelFont = total->font();
	labelFont.setBold(true);
	total->setFont(labelFont);
	total->setAlignment(AlignCenter | AlignVCenter | ExpandTabs);
	total->setText("--:--");
	total->setMinimumWidth(total->sizeHint().width());
	total->setText("");

	statusBar()->addWidget(total, 0, true);
	statusBar()->show();

	connect( napp, SIGNAL(hideYourself()), this, SLOT(hide()) );
	connect( napp, SIGNAL(showYourself()), this, SLOT(show()) );

	connect(napp->player(), SIGNAL(playing()), this, SLOT(slotPlaying()));
	connect(napp->player(), SIGNAL(stopped()), this, SLOT(slotStopped()));
	connect(napp->player(), SIGNAL(paused()), this, SLOT(slotPaused()));
	napp->player()->handleButtons();
	
	connect(napp->player(), SIGNAL(timeout()), this, SLOT(slotTimeout()));
	connect(napp->player(), SIGNAL(loopTypeChange(int)), this, SLOT(changeLoopType(int)));

	/* This skipToWrapper is needed to pass milliseconds to Player() as everybody
	 * below the GUI is based on milliseconds instead of some unprecise thingy
	 * like seconds or mille */
	connect(slider, SIGNAL(userChanged(int)), this, SLOT(skipToWrapper(int)));
	connect(this, SIGNAL(skipTo(int)), napp->player(), SLOT(skipTo(int)));

	connect(slider, SIGNAL(sliderMoved(int)), SLOT(sliderMoved(int)));

	setCaption("Noatun");
	setIcon(SmallIcon("noatun"));
	changeLoopType(Player::None);
	changeStatusbar();
	handleLengthString("--:--/--:--");

	setMinimumWidth(250);
	resize(300, 75);

	KConfig &config = *KGlobal::config();

	toolBar("main")->applySettings(&config, "Excellent main");
	toolbarAction->setChecked( !toolBar("main")->isHidden() );

	config.setGroup("excellent");

	volumeSlider = 0;
	volumeAction->setChecked( config.readBoolEntry("volumeShown", false) );
	showVolumeControl();

	menubarAction->setChecked( config.readBoolEntry("menuShown", true) );
	showMenubar();

	applyMainWindowSettings(&config, "excellent");

	switch((NET::MappingState)config.readNumEntry("mappingState", (int)NET::Visible))
	{
	case NET::Visible:
		showNormal();
		break;
	case NET::Withdrawn:
		hide();
		break;
	case NET::Iconic:
		showMinimized();
		break;
	}
}

Excellent::~Excellent()
{
	KConfig &config = *KGlobal::config();
	saveMainWindowSettings(&config, "excellent");
	toolBar("main")->saveSettings(&config, "Excellent main");
	config.setGroup("excellent");
	config.writeEntry("volumeShown", volumeAction->isChecked());
	config.writeEntry("menuShown", menubarAction->isChecked());
	config.writeEntry("width", width());
	config.writeEntry("height", height());
	config.sync();
}

void Excellent::showEvent(QShowEvent *e)
{
	KConfig *config = KGlobal::config();
	config->setGroup("excellent");
	config->writeEntry("mappingState", NET::Visible);
	config->sync();

	KMainWindow::showEvent(e);
}

void Excellent::hideEvent(QHideEvent *e)
{
	KConfig *config = KGlobal::config();
	config->setGroup("excellent");
	config->writeEntry("mappingState", NET::Withdrawn);
	config->sync();

	KMainWindow::hideEvent(e);
}

void Excellent::closeEvent(QCloseEvent *)
{
	unload();
}

void Excellent::dragEnterEvent(QDragEnterEvent *event)
{
	// accept uri drops only
	event->accept(QUriDrag::canDecode(event));
}

void Excellent::dropEvent(QDropEvent *event)
{
	KURL::List uri;
	if (KURLDrag::decode(event, uri))
	{
		for (KURL::List::Iterator i = uri.begin(); i != uri.end(); ++i)
			napp->player()->openFile(*i, false);
	}
}

void Excellent::slotPlaying()
{
	slider->setEnabled(true);
	changeStatusbar();
}

void Excellent::slotStopped()
{
	slider->setEnabled(false);
	if(!napp->player()->current()) return;
	changeStatusbar();
	slider->setValue(0);
	handleLengthString("--:--/--:--");
}

void Excellent::slotPaused()
{
	slider->setEnabled(true);
	changeStatusbar();
}

void Excellent::slotTimeout()
{
	if(volumeSlider) volumeSlider->setValue(100 - napp->player()->volume());

	if (!slider->currentlyPressed())
		handleLengthString(napp->player()->lengthString());

	if(!napp->player()->current()) return;
	if(slider->currentlyPressed()) return;

	slider->setRange(0, (int)napp->player()->getLength() / 1000 );
	slider->setValue((int)napp->player()->getTime() / 1000 );

	changeStatusbar();
}

void Excellent::sliderMoved(int seconds)
{
	if(napp->player()->current())
		handleLengthString(napp->player()->lengthString(seconds * 1000));
}

void Excellent::skipToWrapper(int second) // wrap int to int _and_ seconds to mseconds
{
	emit skipTo((int)(second*1000));
}

void Excellent::changeLoopType(int t)
{
	static const int time = 2000;
	switch (t)
	{
	case Player::None:
		statusBar()->message(i18n("No looping"), time);
		loop->setIcon("noatunloopnone");
		loop->setText(i18n("No Looping"));
		break;
	case Player::Song:
		statusBar()->message(i18n("Song looping"), time);
		loop->setIcon("noatunloopsong");
		loop->setText(i18n("Song Looping"));
		break;
	case Player::Playlist:
		statusBar()->message(i18n("Playlist looping"), time);
		loop->setIcon("noatunloopplaylist");
		loop->setText(i18n("Playlist Looping"));
		break;
	case Player::Random:
		statusBar()->message(i18n("Random play"), time);
		loop->setIcon("noatunlooprandom");
		loop->setText(i18n("Random Play"));
	}
}

void Excellent::showToolbar(void)
{
	if(toolbarAction->isChecked())
		toolBar("main")->show();
	else
		toolBar("main")->hide();
}

void Excellent::showMenubar(void)
{
	if(menubarAction->isChecked())
	{
		menuBar()->show();
	}
	else
	{
		KMessageBox::information(this, i18n("<qt>Press %1 to show the menubar.</qt>").arg(QString(QKeySequence(menubarAction->accel()))), QString::null, "Hide Menu warning");
		menuBar()->hide();
	}
}

void Excellent::showVolumeControl(void)
{
	if(volumeAction->isChecked())
		growVolumeControl();
	else
		shrinkVolumeControl();
}

void Excellent::changeStatusbar(void)
{
	if(!napp->player()->current().isNull())
		statusBar()->message(napp->player()->current().title());
}

void Excellent::handleLengthString(const QString &text)
{
	if(text.right(5) == "00:00" && text.left(5) == "00:00")
	{
		elapsed->setText("--:--");
		total->setText("--:--");
	}
	else
	{
		// Split the length string in to "current" and "elapsed"
		QStringList tokens = QStringList::split("/", text);

		elapsed->setText(tokens[0]);
		total->setText(tokens[1]);
	}
}

void Excellent::growVolumeControl(void)
{
	volumeSlider = new L33tSlider(0, 100, 10, 0, Vertical, mainFrame);
	volumeSlider->setValue(100 - napp->player()->volume());
	volumeSlider->show();
	connect(volumeSlider, SIGNAL(sliderMoved(int)), this, SLOT(changeVolume(int)));
	connect(volumeSlider, SIGNAL(userChanged(int)), this, SLOT(changeVolume(int)));
}

void Excellent::shrinkVolumeControl(void)
{
	delete volumeSlider;
	volumeSlider = 0;
}

void Excellent::changeVolume(int slider)
{
	napp->player()->setVolume(100 - slider);
}

#include "userinterface.moc"
