/***************************************************************************
	kjtexdisplay.cpp
	---------------------------------------------
	Displays for time and other things
	using fonts provided by KJFont
	---------------------------------------------
	Maintainer: Stefan Gehn <sgehn@gmx.net>

 ***************************************************************************/

// local includes
#include "kjtextdisplay.h"
#include "kjfont.h"

// kde includes
#include <klocale.h>
#include <kdebug.h>
#include <kconfig.h>
#include <kpixmap.h>

// arts-includes, needed for pitch
#include <artsmodules.h>
#include <arts/reference.h>
#include <arts/soundserver.h>
#include <arts/kmedia2.h>

// noatun includes
#include <noatun/player.h>
#include <noatun/engine.h>

/*******************************************
 * KJFilename
 *******************************************/

KJFilename::KJFilename(const QStringList &l, KJLoader *p)
	: QObject(0), KJWidget(p), mBack(0)
{
	int x  = l[1].toInt();
	int y  = l[2].toInt();
	int xs = l[3].toInt() - x;
	int ys = l[4].toInt() - y;

	// fix for all those weird skins where the filenamewindow has more
	// height than needed for the font
	// ( ... usually resulting in garbage on-screen )
	if ( ys > (textFont().fontHeight()) )
		ys = textFont().fontHeight();

	// background under filename-scroller
	QPixmap tmp  = p->pixmap(p->item("backgroundimage")[1]);
	mBack = new KPixmap ( QSize(xs,ys) );
	bitBlt( mBack, 0, 0, &tmp, x, y, xs, ys, Qt::CopyROP );

	setRect(x,y,xs,ys);

	// how far it moves per cycle
	// TODO: make that configurable for the user

	//mDistance = 1;
	mDistance = (int)(textFont().fontWidth()/2);

	prepareString(i18n("Welcome to Noatun").latin1());
	killTimers();
}

void KJFilename::paint(QPainter *p, const QRect &)
{
/*
// direct bitblt of tex on screen (oboslete)
	bitBlt(p->device(), rect().topLeft(), &mView,
	       QRect(0,0, rect().width(), rect().height()), Qt::CopyROP);
*/
	QPixmap temp ( rect().width(), rect().height() );

	// draw background into buffer
	bitBlt ( &temp, 0, 0, mBack, 0, 0, -1, -1, Qt::CopyROP );
	// draw font into buffer
	bitBlt( &temp, 0, 0, &mView, 0, 0, rect().width(), rect().height(), Qt::CopyROP);
	// and draw it on screen
	bitBlt(p->device(), rect().topLeft(), &temp,
	       QRect(0,0,-1,-1), Qt::CopyROP);
}

void KJFilename::timerEvent(QTimerEvent *)
{
	int height = mView.height();
	int width = mView.width();
/*
	if ( textFont().isTransparent() )
	{
*/

	QBitmap cycleMask ( mDistance, height ); // temporary-space for moving parts of the mask
	QPixmap cycle ( mDistance, height );	// temporary-space for moving parts of the pixmap
	QBitmap newMask ( *mView.mask() );		// save old mask

	// copy mask like the same way we're doing it with the pixmap
	// a mask does not get copied on a bitblt automatically, we have to do
	// it "by hand"
	bitBlt(&cycleMask, 0,0, &newMask, 0,0, mDistance, height, Qt::CopyROP);
	bitBlt(&newMask, 0,0, &newMask, mDistance, 0, width-mDistance, height, Qt::CopyROP);
	bitBlt(&newMask, width-mDistance, 0, &cycleMask, 0,0, mDistance, height, Qt::CopyROP);

	bitBlt(&cycle, 0,0, &mView, 0,0, mDistance, height, Qt::CopyROP);
	bitBlt(&mView, 0,0, &mView, mDistance, 0, width-mDistance, height, Qt::CopyROP);
	bitBlt(&mView, width-mDistance, 0, &cycle, 0,0, mDistance, height, Qt::CopyROP);

	// apply the newly created mask
	mView.setMask(newMask);

/*
	}
	else
	{
		QPixmap cycle(mDistance, height);
		bitBlt(&cycle, 0,0, &mView, 0,0, mDistance, height, Qt::CopyROP);
		bitBlt(&mView, 0,0, &mView, mDistance, 0, width-mDistance, height, Qt::CopyROP);
		bitBlt(&mView, width-mDistance, 0, &cycle, 0,0, mDistance, height, Qt::CopyROP);
	}
*/

	repaint();
}

bool KJFilename::mousePress(const QPoint &)
{
	return false;
}

void KJFilename::prepareString(const QCString &str)
{
	killTimers(); // i.e. stop timers

	mView = textFont().draw(str, rect().width());

	// ! Takes care of mDistance too !
//	startTimer(100); // OLD, smooth title scrolling, 1pixel every 100ms
	startTimer(400); // move text mDistance pixels every 400ms
}

void KJFilename::newFile()
{
	if ( !napp->player()->current() ) // just for safety
		return;

	QCString title = QCString( napp->player()->current().title().latin1() );

	if ( title == mLastTitle )
		return;

	mLastTitle = title;

	QCString timestring = napp->player()->lengthString().latin1();
	timestring = timestring.mid(timestring.find('/')+1);
	prepareString ( title + " (" + timestring + ")   ");
}

QString KJFilename::tip()
{
	if ( !napp->player()->current() ) // just for safety
		return i18n("Filename");
	else
		return napp->player()->current().url().prettyURL();
}


/*******************************************
 * KJTime
 *******************************************/

KJTime::KJTime(const QStringList &l, KJLoader *p)
	: KJWidget(p)
{
	int x  = l[1].toInt();
	int y  = l[2].toInt();
	int xs = l[3].toInt() - x;
	int ys = l[4].toInt() - y;

	// fix for all those weird skins where the timewindow
	// has more space than needed for the font
	int maxNeededHeight = timeFont().fontHeight();
	if ( ys > maxNeededHeight )
		ys = maxNeededHeight;

	// five digits + spacing between them
	int maxNeededWidth = ( 5 *timeFont().fontWidth() ) + ( 4 * timeFont().fontSpacing() );
	if ( xs > maxNeededWidth )
		xs = maxNeededWidth;

	// background under time-display
	QPixmap tmp  = p->pixmap(p->item("backgroundimage")[1]);
	mBack = new KPixmap ( QSize(xs,ys) );
	bitBlt( mBack, 0, 0, &tmp, x, y, xs, ys, Qt::CopyROP );

	setRect(x,y,xs,ys);
	
	KGlobal::config()->setGroup("KJofol-Skins");
	countMode = KGlobal::config()->readNumEntry("TimeCountMode", Up);

	prepareString("00:00");
}

void KJTime::paint(QPainter *p, const QRect &)
{
//	kdDebug(66666) << "KJTime::paint(QPainter *p, const QRect &)" << endl;
/*
	bitBlt(p->device(), rect().topLeft(), &mTime,
	       QRect(0,0, rect().width(), rect().height()), Qt::CopyROP);
*/

	QPixmap temp ( rect().width(), rect().height() );

	// draw background into buffer
	bitBlt ( &temp, 0, 0, mBack, 0, 0, -1, -1, Qt::CopyROP );
	// draw time-display into buffer (that's a pixmap with a mask applied)
	bitBlt( &temp, 0, 0, &mTime, 0, 0, rect().width(), rect().height(), Qt::CopyROP);

	// and draw it on screen
	bitBlt(p->device(), rect().topLeft(), &temp,
	       QRect(0,0, rect().width(), rect().height()), Qt::CopyROP);
}

bool KJTime::mousePress(const QPoint &)
{
	if ( countMode == Up )
		countMode = Down;
	else
		countMode = Up;

	KGlobal::config()->setGroup("KJofol-Skins");
	KGlobal::config()->writeEntry("TimeCountMode", countMode);
	KGlobal::config()->sync();

	return true;
}

/*
void KJTime::readConfig()
{
	kdDebug(66666) << "KJTime::readConfig()" << endl;
	KGlobal::config()->setGroup("KJofol-Skins");
	countMode = KGlobal::config()->readNumEntry("TimeCountMode", Up);
}
*/

void KJTime::timeUpdate(int)
{
//	kdDebug(66666) << "START KJTime::timeUpdate(int)" << endl;

	QCString time;

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

	if ( countMode == Up )
	{
		time = napp->player()->lengthString().latin1();
	}
	else
	{
		int remaining = napp->player()->getLength() - napp->player()->getTime();
		time = napp->player()->lengthString(remaining).latin1();
	}

	time = time.left(time.find('/'));
	if (time == "--:--" )
		time = "00:00"; // We don't want this type of showing "nothing loaded"
	
	prepareString(time);

//	kdDebug(66666) << "END KJTime::timeUpdate(int)" << endl;
}

void KJTime::prepareString(const QCString &str)
{
//	kdDebug(66666) << "<KJTime::prepareString(const QCString &str)>" << endl;
	if ( str == mLastTime )
		return;

	mLastTime = str;

	mTime = timeFont().draw(str, rect().width());
/*
	if ( timeFont().isTransparent() )
	{
//		kdDebug(66666) << "timetext background repaint" << endl;
		repaint(false);
	}
*/
	repaint();
//	kdDebug(66666) << "</KJTime::prepareString(const QCString &str)>" << endl;
}

QString KJTime::tip()
{
	if ( countMode == Up )
		return i18n("Current play time");
	else
		return i18n("Play time left");
}


/*******************************************
 * KJVolumeText
 *******************************************/

KJVolumeText::KJVolumeText(const QStringList &l, KJLoader *p)
	: KJWidget(p)
{
	int x=l[1].toInt();
	int y=l[2].toInt();
	int xs=l[3].toInt()-x;
	int ys=l[4].toInt()-y;

	// fix for all those weird skins where the timewindow has more space than needed for the font
	if ( ys > (volumeFont().fontHeight()) )
		ys = volumeFont().fontHeight();

	// 3 digits for volume (1-100)
	// + spaces according to spacing
	// + percentage letter (seems to be 1px wider than a normal char)
	int tempWidth = (3*volumeFont().fontWidth()) + (2*volumeFont().fontSpacing()) + ((volumeFont().fontWidth()+1));
	if ( xs > ( tempWidth ) )
		xs = tempWidth;

	// background under volumetext-display
	QPixmap tmp  = p->pixmap(p->item("backgroundimage")[1]);
	mBack = new KPixmap ( QSize(xs,ys) );
	bitBlt( mBack, 0, 0, &tmp, x, y, xs, ys, Qt::CopyROP );

	setRect(x,y,xs,ys);

	prepareString("100%");
}

void KJVolumeText::paint(QPainter *p, const QRect &)
{
/*
	bitBlt(p->device(), rect().topLeft(), &mVolume,
	       QRect(0,0, rect().width(), rect().height()), Qt::CopyROP);
*/
	QPixmap temp ( rect().width(), rect().height() );

	// draw background into buffer
	bitBlt ( &temp, 0, 0, mBack, 0, 0, -1, -1, Qt::CopyROP );
	// draw time-display into buffer
	bitBlt( &temp, 0, 0, &mVolume, 0, 0, rect().width(), rect().height(), Qt::CopyROP);

	// and draw it on screen
	bitBlt(p->device(), rect().topLeft(), &temp,
	       QRect(0,0,-1,-1), Qt::CopyROP);
}

bool KJVolumeText::mousePress(const QPoint &)
{
	return true;
}

void KJVolumeText::timeUpdate(int)
{
	QCString volume;

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

	volume.sprintf("%d%%", napp->player()->volume() ); // FIXME: is sprintf safe to use?

	prepareString(volume);
}

void KJVolumeText::prepareString(const QCString &str)
{
	if ( str == mLastVolume )
		return;

	mLastVolume = str;

	mVolume = volumeFont().draw(str, rect().width());
/*
	if ( volumeFont().isTransparent() )
	{
//		kdDebug(66666) << "volumetext background repaint" << endl;
		repaint(false);
	}
*/
	repaint();
}

QString KJVolumeText::tip()
{
	return i18n("Volume");
}


/*******************************************
 * KJPitchText
 *******************************************/

KJPitchText::KJPitchText(const QStringList &l, KJLoader *p)
	: KJWidget(p)
{
	int x  = l[1].toInt();
	int y  = l[2].toInt();
	int xs = l[3].toInt() - x;
	int ys = l[4].toInt() - y;

	// fix for all those weird skins where the timewindow has more space than needed for the font
	if ( ys > (pitchFont().fontHeight()) )
		ys = pitchFont().fontHeight();

	// 3 digits for volume (1-100), spaces according to spacing and percentage letter
	int tempWidth = (3*pitchFont().fontWidth()) + (2*pitchFont().fontSpacing());
	if ( xs > tempWidth )
		xs = tempWidth;

	// background under time-display
	QPixmap tmp  = p->pixmap(p->item("backgroundimage")[1]);
	mBack = new KPixmap ( QSize(xs,ys) );
	bitBlt( mBack, 0, 0, &tmp, x, y, xs, ys, Qt::CopyROP );

	setRect(x,y,xs,ys);

	prepareString("100");
}

void KJPitchText::paint(QPainter *p, const QRect &)
{
/*
	// OLD way
	bitBlt( p->device(), rect().topLeft(),
		&mSpeed, QRect(0,0, rect().width(), rect().height()), Qt::CopyROP );
*/
	QPixmap temp ( rect().width(), rect().height() );
	// draw background into buffer
	bitBlt ( &temp, 0, 0, mBack, 0, 0, -1, -1, Qt::CopyROP );
	// draw time-display into buffer
	bitBlt( &temp, 0, 0, &mSpeed, 0, 0, rect().width(), rect().height(), Qt::CopyROP);
	// and draw it on screen
	bitBlt(p->device(), rect().topLeft(), &temp, QRect(0,0,-1,-1), Qt::CopyROP);
}

bool KJPitchText::mousePress(const QPoint &)
{
	Arts::PlayObject playobject = napp->player()->engine()->playObject();
	Arts::PitchablePlayObject pitchable = Arts::DynamicCast(playobject);

	if (pitchable.isNull())
		return false;

	pitchable.speed( 1.0f ); // reset pitch
	return true;
}

void KJPitchText::timeUpdate(int)
{
	QCString speed;

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

	Arts::PlayObject playobject = napp->player()->engine()->playObject();
	Arts::PitchablePlayObject pitchable = Arts::DynamicCast(playobject);

	if (pitchable.isNull())
		return;

	speed.setNum ( (int) ((float)pitchable.speed()*(float)100) );
	prepareString ( speed );
}

void KJPitchText::prepareString(const QCString &str)
{
	if ( str == mLastPitch )
		return;

	mLastPitch = str;

	mSpeed = pitchFont().draw(str, rect().width());
/*	if ( pitchFont().isTransparent() )
		repaint(false); */
	repaint();
}

QString KJPitchText::tip()
{
	return i18n("Pitch");
}

#include "kjtextdisplay.moc"
