/***************************************************************************
                           Interface to access KsCD
                             -------------------
    begin                : Sat Dec 04 13:36:00 CET 2004
    copyright            : (C) 2004 by Michal Startek
    adapted from JuK interface which is (C) 2001-2002 by Stefan Gehn
    email                : michal.startek@op.pl
 ***************************************************************************/

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

#include <tdeapplication.h>
#include <kdebug.h>
#include <tqstringlist.h>
#include <tqstrlist.h>
#include <kurldrag.h>
#include <tdelocale.h>

#define TIMER_FAST  250

KsCDInterface::KsCDInterface() : PlayerInterface()
{
	mKsCDTimer = new TQTimer(this, "mKsCDTimer");

	connect(mKsCDTimer, TQT_SIGNAL(timeout()), TQT_SLOT(updateSlider()) );
	kapp->dcopClient()->setNotifications ( true );

	connect(kapp->dcopClient(), TQT_SIGNAL(applicationRegistered(const TQCString&)),
		TQT_SLOT(appRegistered(const TQCString&)) );

	connect(kapp->dcopClient(), TQT_SIGNAL(applicationRemoved(const TQCString&)),
		TQT_SLOT(appRemoved(const TQCString&)));

	TQTimer::singleShot(0, this, TQT_SLOT(myInit()));
}

KsCDInterface::~KsCDInterface()
{
	kapp->dcopClient()->setNotifications(false);
	delete mKsCDTimer;
}

void KsCDInterface::myInit()
{
	// Start the timer if KsCD is already running
	// Needed if user adds applet while running KsCD
	if (findRunningKsCD())
	{
		emit playerStarted();
		mKsCDTimer->start(TIMER_FAST);
	}
	else
	{
		emit playerStopped();
		emit newSliderPosition(0,0);
	}
}

void KsCDInterface::appRegistered(const TQCString &appId)
{
	if((appId) == "kscd")
	{
		mAppId = appId;
		emit playerStarted();
		mKsCDTimer->start(TIMER_FAST);
	}
}

void KsCDInterface::appRemoved(const TQCString &appId)
{
	if ((appId) == "kscd")
	{
		// is there still another KsCD alive?
		// Okay, KsCD does not allow multiple instances
		// of it to run at the same time, but
		// this can change.
		if (findRunningKsCD())
			return;
		mKsCDTimer->stop();
		emit playerStopped();
		emit newSliderPosition(0,0);
	}
}

void KsCDInterface::updateSlider()
{
	// length/time in secs, -1 means "no playobject in kscd"
	int len = -1;
	int time = -1;
	TQByteArray data, replyData;
	TQCString replyType;

	if (kapp->dcopClient()->call(mAppId, "CDPlayer", "currentTrackLength()", data,
		replyType, replyData))
	{
		TQDataStream reply(replyData, IO_ReadOnly);
		if (replyType == "int")
			reply >> len;
	}

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

	if (kapp->dcopClient()->call(mAppId, "CDPlayer", "currentPosition()", data,
		replyType, replyData))
	{
		TQDataStream reply(replyData, IO_ReadOnly);
		if (replyType == "int")
			reply >> time;
	}

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

// Drag-n-Drop stuff =================================================================
// As far as I know there is currently no way to drag an AudioCD track to KsCD,
// or even no application to drag AudioCD track from (not the TDEIO-wrapped track
// path (audiocd:/...) like from Konqueror)

void KsCDInterface::dragEnterEvent(TQDragEnterEvent* event)
{
	event->ignore();
}

void KsCDInterface::dropEvent(TQDropEvent* event)
{
	event->ignore();
}

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

void KsCDInterface::sliderStartDrag()
{
	mKsCDTimer->stop();
}

void KsCDInterface::sliderStopDrag()
{
	mKsCDTimer->start(TIMER_FAST);
}

void KsCDInterface::jumpToTime(int sec)
{
	TQByteArray data;
	TQDataStream arg(data, IO_WriteOnly);
	arg << sec;
	kapp->dcopClient()->send(mAppId, "CDPlayer", "jumpTo(int)", data);
}

void KsCDInterface::playpause()
{
	if (!findRunningKsCD())
		startPlayer("kscd");
	TQByteArray data;
	kapp->dcopClient()->send(mAppId, "CDPlayer", "play()", data);
}

void KsCDInterface::stop()
{
	TQByteArray data;
	kapp->dcopClient()->send(mAppId, "CDPlayer", "stop()", data);
}

void KsCDInterface::next()
{
	TQByteArray data;
	kapp->dcopClient()->send(mAppId, "CDPlayer", "next()", data);
}

void KsCDInterface::prev()
{
	TQByteArray data;
	kapp->dcopClient()->send(mAppId, "CDPlayer", "previous()", data);
}

void KsCDInterface::volumeUp()
{
   TQByteArray data;
   kapp->dcopClient()->send(mAppId, "CDPlayer", "volumeUp()", data);
}

void KsCDInterface::volumeDown()
{
   TQByteArray data;
   kapp->dcopClient()->send(mAppId, "CDPlayer", "volumeDown()", data);
}

const TQString KsCDInterface::getTrackTitle() const
{
	TQString title, artist, album, result;
	TQByteArray data, replyData;
	TQCString replyType;

	// Get track title from KsCD...
	if (kapp->dcopClient()->call(mAppId, "CDPlayer", "currentTrackTitle()", data,
		replyType, replyData))
	{
		TQDataStream reply(replyData, IO_ReadOnly);
		if (replyType == TQSTRING_OBJECT_NAME_STRING)
		{
			reply >> title;
		}
	}

	// Album...
	if (kapp->dcopClient()->call(mAppId, "CDPlayer", "currentAlbum()", data,
		replyType, replyData))
	{
		TQDataStream reply(replyData, IO_ReadOnly);
		if (replyType == TQSTRING_OBJECT_NAME_STRING)
		{
			reply >> album;
		}
	}

	// Artist...
	if (kapp->dcopClient()->call(mAppId, "CDPlayer", "currentArtist()", data,
		replyType, replyData))
	{
		TQDataStream reply(replyData, IO_ReadOnly);
		if (replyType == TQSTRING_OBJECT_NAME_STRING)
		{
			reply >> artist;
		}
	}

	// And compose them into one string that will be displayed...
	if(album.isEmpty())
	{
		if(artist.isEmpty())
		{
			result = title;
		}
		else // artist is non-empty
		{
			if(title.isEmpty())
			{
				result = artist;
			}
			else
			{
				result = i18n("artist - trackname", "%1 - %2").arg(artist, title);
			}
		}
	}
	else // album is non-empty
	{
		if(artist.isEmpty())
		{
			if(title.isEmpty())
			{
				result = album;
			}
			else
			{
				result = i18n("(album) - trackname", "(%1) - %2").arg(artist, title);
			}
		}
		else // artist is non-empty
		{
			if(title.isEmpty())
			{
				result = i18n("artistname (albumname)", "%1 (%2)").arg(artist, album);
			}
			else
			{
				result = i18n("artistname (albumname) - trackname", "%1 (%2) - %3").arg(artist, album, title);
			}
		}
	}

	return result;
}

bool KsCDInterface::findRunningKsCD()
{
	QCStringList allApps = kapp->dcopClient()->registeredApplications();
	TQValueList<TQCString>::const_iterator iterator;

	for (iterator = allApps.constBegin(); iterator != allApps.constEnd(); ++iterator)
	{
		if ((*iterator) == "kscd")
		{
			mAppId = *iterator;
			return true;
		}
	}
	return false;
}

int KsCDInterface::playingStatus()
{
	TQByteArray data, replyData;
	TQCString replyType;

	if (kapp->dcopClient()->call(mAppId, "CDPlayer", "getStatus()", data, replyType,
		replyData))
	{
		int status = 0;
		TQDataStream reply(replyData, IO_ReadOnly);
		if (replyType == "int")
			reply >> status;

		switch (status)
		{
			case 2:
				return Playing;
			case 4:
				return Paused;
			default:
				return Stopped;
		}
	}
	return Stopped;
}
