/***************************************************************************
                jukInterface.cpp  -  Interface to access JuK
                             -------------------
    begin                : Mon Jan 15 21:09:00 CEST 2001
    copyright            : (C) 2000-2002 by Stefan Gehn
    email                : sgehn@gmx.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 "jukInterface.h"
#include "jukInterface.moc"

#include <kdebug.h>
#include <qstringlist.h>
#include <qstrlist.h>
#include <kurldrag.h>

#define TIMER_FAST  250

JuKInterface::JuKInterface() : PlayerInterface()
{
	mTimerValue = TIMER_FAST;
	mJuKTimer = new QTimer ( this, "mJukTimer" );

	connect(mJuKTimer, SIGNAL(timeout()), SLOT(updateSlider()) );
	kapp->dcopClient()->setNotifications ( true );

	connect(kapp->dcopClient(), SIGNAL(applicationRegistered(const QCString&)),
		SLOT(appRegistered(const QCString&)) );

	connect(kapp->dcopClient(), SIGNAL(applicationRemoved(const QCString&)),
		SLOT(appRemoved(const QCString&)));

	QTimer::singleShot(0, this, SLOT(myInit()));
}

JuKInterface::~JuKInterface()
{
	kapp->dcopClient()->setNotifications(false);
	delete mJuKTimer;
}

void JuKInterface::myInit(void)
{
	// Start the timer if juk is already running
	// Needed if user adds applet while running juk
	if ( findRunningJuK() )
	{
		emit playerStarted();
		mJuKTimer->start(mTimerValue);
	}
	else
	{
		emit playerStopped();
		emit newSliderPosition(0,0);
	}
}

void JuKInterface::appRegistered ( const QCString &appId )
{
	if(appId.contains("juk",false) )
	{
		mAppId = appId;
		emit playerStarted();
		mJuKTimer->start(mTimerValue);
	}
}

void JuKInterface::appRemoved ( const QCString &appId )
{
	if ( appId.contains("juk",false) )
	{
	 	// is there still another juk alive?
		if ( findRunningJuK() )
			return;
		mJuKTimer->stop();
		emit playerStopped();
		emit newSliderPosition(0,0);
	}
}

void JuKInterface::updateSlider ( void )
{
	// length/time in msecs, -1 means "no playobject in juk"
	int len, time;
	QByteArray data, replyData;
	QCString replyType;

	if (!kapp->dcopClient()->call(mAppId, "Player", "totalTime()",data, replyType, replyData))
	{
		//kdDebug() << "mediacontrol: DCOP communication Error" << endl;
		// -2 is an internal errornumber, might be used later
		len = -2;
	}
	else
	{
		QDataStream reply(replyData, IO_ReadOnly);
		if (replyType == "int")
		{
			reply >> len;
		}
		else
		{
			//kdDebug() << "mediacontrol: unexpected type of DCOP-reply" << endl;
			// -3 is an internal errornumber, might be used later
			len = -3;
		}
	}

	data = 0;
	replyData = 0;
	replyType = 0;

	if (!kapp->dcopClient()->call(mAppId, "Player", "currentTime()",data, replyType, replyData))
	{
		//kdDebug() << "mediacontrol: DCOP communication error" << endl;
		time = -2;
	}
	else
	{
		QDataStream reply(replyData, IO_ReadOnly);
		if (replyType == "int")
		{
			reply >> time;
		}
		else
		{
			//kdDebug() << "mediacontrol: unexpected type of DCOP-reply" << endl;
			time = -3;
		}
	}

	//kdDebug() << "JuKInterface::updateSlider()  len  = " << len << endl;
	//kdDebug() << "JuKInterface::updateSlider()  time = " << time << endl;

	if ( (time < 0) || (len < 0)) // JuK isn't playing and thus returns -1
	{
		len = 0;
		time = 0;
	}
	emit ( newSliderPosition(len,time) );
}

// Drag-n-Drop stuff =================================================================

void JuKInterface::dragEnterEvent(QDragEnterEvent* event)
{
//	kdDebug() << "JuKInterface::dragEnterEvent()" << endl;
	event->accept( KURLDrag::canDecode(event) );
}

void JuKInterface::dropEvent(QDropEvent* event)
{
//	kdDebug() << "JuKInterface::dropEvent()" << endl;
	KURL::List list;
	if (KURLDrag::decode(event, list))
	{
		QByteArray data;
		QDataStream arg(data, IO_WriteOnly);
		arg << list.toStringList() << false;
		if (!kapp->dcopClient()->send(mAppId, "Player", "openFile(QStringList)",data))
			kdDebug() << "Couldn't send drop to juk" << endl;
	}
}

// ====================================================================================

void JuKInterface::sliderStartDrag()
{
	mJuKTimer->stop();
}

void JuKInterface::sliderStopDrag()
{
	mJuKTimer->start(mTimerValue);
}

void JuKInterface::jumpToTime( int sec )
{
	QByteArray data;
	QDataStream arg(data, IO_WriteOnly);
	arg << sec;
	kapp->dcopClient()->send(mAppId, "Player", "setTime(int)", data);
}

void JuKInterface::play()
{
	QByteArray data;
	kapp->dcopClient()->send(mAppId, "Player", "play()", data);
}

void JuKInterface::pause()
{
	QByteArray data;
	kapp->dcopClient()->send(mAppId, "Player", "pause()", data);
}

void JuKInterface::stop()
{
	QByteArray data;
	kapp->dcopClient()->send(mAppId, "Player", "stop()", data);
}

void JuKInterface::next()
{
	QByteArray data;
	kapp->dcopClient()->send(mAppId, "Player", "forward()", data);
}

void JuKInterface::prev()
{
	QByteArray data;
	kapp->dcopClient()->send(mAppId, "Player", "back()", data);
}

const QString JuKInterface::getTrackTitle() const
{
	QString title;
	QByteArray data, replyData;
	QCString replyType;
	if (!kapp->dcopClient()->call(mAppId, "Player", "playingString()",data, replyType, replyData))
	{
		//kdDebug() << "mediacontrol: DCOP communication Error" << endl;
		return QString("");
	}
	else
	{
		QDataStream reply(replyData, IO_ReadOnly);
		if (replyType == "QString")
		{
			reply >> title;
			return title;
		}
		else
		{
			//kdDebug() << "mediacontrol: unexpected type of DCOP-reply" << endl;
			return QString("");
		}
	}
}

// FIXME: what if we have a dcop app named, let's say, 'jukfrontend'?
bool JuKInterface::findRunningJuK()
{
	QCStringList allApps = kapp->dcopClient()->registeredApplications();
	QValueList<QCString>::iterator iterator;

	for (iterator = allApps.begin(); iterator != allApps.end(); iterator++)
	{
		if ((*iterator).contains("juk",false))
		{
			mAppId = *iterator;
			return true;
		}
	}
	return false;
}
