/**
 ** On-Screen-Display for Noatun
 ** Copyright (c) 2001, Flaming Sword Productions
 ** All Rights Reserved under the BSD License
 **/
#include <kdebug.h>
#include <kwin.h>
#include <kglobalsettings.h>
#include <klocale.h>
#include <qapplication.h>
#include <qbitmap.h>
#include <qcursor.h>
#include <qfont.h>
#include <qobject.h>
#include <qpainter.h>
#include <qwidget.h>
#include <qtimer.h>
#include <qimage.h>
#include <qlabel.h>
#include "kosd.h"

/**
 ** KOSD::KOSD(): CONSTRUCTOR. 
 **/
KOSD::KOSD()
	: QLabel(0L, "KOSD", WStyle_Customize | WStyle_StaysOnTop | WStyle_NoBorder ),
	position (Bottom),
	status (Stopped),
	font (QFont(KGlobalSettings::generalFont().family(), 18, QFont::Bold)),
	color (Qt::green),
	displayTime (1000),
	volume( -1),
	displayTimer(new QTimer(this))
{

	KWin::setState( winId(), NET::Modal | NET::Sticky | NET::StaysOnTop | NET::SkipTaskbar | NET::SkipPager );
	KWin::setType( winId(), NET::Override );

	emit setTextFont( font );
	emit setTextColor( color );

	setText( QString::null );
	setAlignment( AlignBottom );

	connect( displayTimer, SIGNAL(timeout()), this, SLOT(hide()));
	connect( displayTimer, SIGNAL(timeout()), this, SLOT(clear()));
	hide();
}

/**
 ** KOSD::~KOSD(): DESTRUCTOR. 
 **/
KOSD::~KOSD()
{
}

/**
 ** KOSD::setPosition(): Update our position.
 **/
void KOSD::setPosition( int p )
{
	position = p;
}

/**
 ** KOSD::setStatus(): Set our current operational status.
 **/
void KOSD::setStatus( Status s )
{
	status = s;
	showText(lastMessage);
}

/**
 ** KOSD::setDisplayTime(): Adjust the delay between text updates.
 **/
void KOSD::setDisplayTime( uint time )
{
	displayTime = time;
	displayTimer->changeInterval( time );
}

/**
 ** KOSD::setTextColor(): Set the text color.
 **/
void KOSD::setTextColor( const QColor& c )
{
	color = c;

	QPalette p(Qt::black);
	p.setColor( QColorGroup::Foreground, color );
	setPalette( p );
}

/**
 ** KOSD::setFont(): Set the text color.
 **/
void KOSD::setTextFont( const QFont& c )
{
	font = c;
	setFont( font );
}

/**
 ** KOSD::setVolume(): Someone adjusted our volume.
 **/
void KOSD::setVolume( int volume )
{
	volume = volume;
	showText(lastMessage);
}

/**
 ** KOSD::showText(): Emit this signal when you want KOSD to show
 ** something.
 **/
void KOSD::showText( const QString& s )
{
	QString show = statusString();
	switch(status)
	{
	case Stopped:
		// do nothing
		break;
	case Playing:
	case Paused:
		show += "\n" + volumeString();
		if(s.length()) show += "\n" + s;
		break;
	};

	lastMessage = s;

	setText( show );
	setPosition();
	emit showLabel();
}

namespace
{
int widthForString(QString string, QFontMetrics metrics)
{
	int width = 0;
	QStringList list = QStringList::split('\n', string);
	for(QStringList::Iterator i = list.begin(); i != list.end(); ++i)
	{
		const int lineWidth = metrics.width(*i);
		if(lineWidth > width) width = lineWidth;
	}
	return width;
}

int heightForString(QString string, QFontMetrics metrics)
{
	return metrics.lineSpacing() * (string.contains('\n') + 1);
}

}

/**
 ** KOSD::setPosition(): Based on the screen geometry and configured parameters,
 ** move the label to a point on the screen.
 **/
void KOSD::setPosition()
{
	QFontMetrics metrics(font);
	QRect screenGeometry = KGlobalSettings::desktopGeometry(QCursor::pos());

	int x, y;

	const int w = widthForString(text(), metrics);
	const int h = heightForString(text(), metrics);

	if(position & Right)
		x = screenGeometry.width() - w;
	else if(position & Center)
		x = (screenGeometry.width() - w) / 2;
	else //if(position & Left)
		x = 5;

	if(position & Bottom)
		y = screenGeometry.height() - h;
	else if(position & VerticalCenter)
		y = (screenGeometry.height() - h) / 2;
	else //if(position & Top)
		y = 5;

	x += screenGeometry.x();
	y += screenGeometry.y();

	setGeometry(x, y, w, h);
}

/**
 ** KOSD::showLabel(): Emit this to show the label.  It will set
 ** a hide() timer automagically.
 **/
void KOSD::showLabel()
{
	if(displayTimer->isActive())
		displayTimer->stop();
	setPosition();
	updateMask();
	show();
	repaint(true);
	displayTimer->start( displayTime, false );
}

/**
 ** KOSD::statusString(): Return a QString representing our current
 ** status.
 **/
QString KOSD::statusString()
{
	switch(status)
	{
	case Playing:
		return i18n("Play");
	case Stopped:
		return i18n("Stop");
	case Paused:
		return i18n("Pause");
	default:
		return QString::null;
	}
}

/**
 ** KOSD::volumeString(): Return a QString representing our current
 ** volume level.  The volume should be set by a signal connected to
 ** KOSD::setVolume().
 **/
QString KOSD::volumeString()
{
	if(volume < 0) return QString::null;

	QString volumeStr = i18n("Volume: ");
	for( int i = 0; i < (volume / 2); i++ )
		volumeStr.append("|");
	for( int i = (volume / 2) + 1; i <= 50; i++ )
		volumeStr.append("-");

	return volumeStr;
}

void KOSD::updateMask(void)
{
	QPixmap mask(size());
	mask.fill(qRgb(255, 255, 255));
	QPainter painter(&mask);
	painter.setFont(font);
	drawContents(&painter);
	painter.end();
	QImage result = mask.convertToImage();

	int w = size().width();
	int h = size().height();

	int total = w * h, cur;
	unsigned int *data = (unsigned int *)result.bits();

	for (cur = w; cur < (total - w); ++cur) {
		if (QColor(data[cur]) != QColor(qRgb(255, 255, 255))) {
			data[cur] = qRgb(0, 0, 0);
		} else {
			data[cur] = qRgb(255, 255, 255);
		}
	}

	QBitmap bm;
	bm.convertFromImage(result);
	setMask(bm);
}

#include "kosd.moc"
