/***************************************************************************
	kjfont.cpp
	--------------------------------------
	Font-Handling of KJ�fol
	Creates pixmaps of strings using the supplied font-pixmap
	--------------------------------------
	Maintainer: Stefan Gehn <sgehn@gmx.net>

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

#include "kjfont.h"
#include "kjloader.h"
#include "kjwidget.h"
#include "kjprefs.h"

#include <kdebug.h>
#include <tdeglobalsettings.h>

#include <tqimage.h>
#include <tqpainter.h>

/*******************************************
 * KJFont
 *******************************************/

KJFont::KJFont(const TQString &prefix, KJLoader *parent) : mTextMask(0), mTransparentRGB(0)
{
//	kdDebug(66666) << "KJFont::KJFont(const TQString &prefix, KJLoader *parent)" << prefix.latin1() << endl;

	if (prefix=="timefont")
	{
		mString[0]="0123456789: ";
		mString[1]=mString[2]="";
		mNullChar=' ';
	}
	else if ( (prefix=="volumefont") || (prefix=="pitchfont") )
	{
		mString[0]="0123456789% ";
		mString[1]=mString[2]="";
		mNullChar=' ';
	}
	else
	{
		mString[0]="abcdefghijklmnopqrstuvwxyz\"@";
		mString[1]="0123456789;_:()-'!_+\\/[]*&%.=$#";
		mString[2]="���?*,                          ";
		mNullChar=' ';
	}

	mText = parent->pixmap(parent->item(prefix+"image")[1]);

	if ( parent->exist(prefix+"size") )
	{
		mWidth = parent->item(prefix+"size")[1].toInt();
		mHeight = parent->item(prefix+"size")[2].toInt();
	}
	else // try to load the font even we are missing important settings
	{	// this still can cause crashes!
		kdDebug(66666) << "font height/width missing, this skin might crash noatun!" << endl;

		mWidth = mText.width() / strlen(mString[0]);

		if ( (prefix=="timefont") || (prefix=="volumefont") || (prefix=="pitchfont")  )
			mHeight = mText.height();
		else
			mHeight = mText.height()/3;
	}

//	kdDebug(66666) << prefix << " h: " << mHeight << " w: " << mWidth << endl;

	// fix for wrong numbers in rc (a skin named steelforged needs that)
	if ( mHeight > mText.height() )
		mHeight = mText.height();

	// Stupid Skin authors tend to forget keys :/
	if ( parent->exist(prefix+"spacing") )
		mSpacing = parent->item(prefix+"spacing")[1].toInt();
	else
		mSpacing = 0; // FIXME: What's default for this in kj�fol???

	if ( parent->exist(prefix+"transparent") )
		mTransparent = (bool)parent->item(prefix+"transparent")[1].toInt();
	else
		mTransparent = true; // transparency seems to be default in kj�fol

	// define color in font that will be transparent later on
	if ( mTransparent )
	{
		TQImage ibackground = mText.convertToImage();
		mTransparentRGB = ibackground.pixel( ibackground.width()-1, ibackground.height()-1 );
//		kdDebug(66666) << "color (" << tqRed(mTransparentRGB) << "," << tqGreen(mTransparentRGB) << "," << tqBlue(mTransparentRGB) << ") will be transparent for " << prefix.latin1() << endl;
		mTextMask = KJWidget::getMask(ibackground,mTransparentRGB);
	}

	mUseSysFont = KJLoader::kjofol->prefs()->useSysFont();
	sysFontMetrics = 0L;
	if (mUseSysFont)
		recalcSysFont();
}

void KJFont::recalcSysFont(void)
{
//	kdDebug(66666) << k_funcinfo << "called." << endl;

	mUseSysFont = KJLoader::kjofol->prefs()->useSysFont();
	if (!mUseSysFont)
		return;
	sysFont = TQFont(KJLoader::kjofol->prefs()->sysFont());
	sysFont.setStyleStrategy( TQFont::NoAntialias );
	if ( sysFontMetrics )
		delete sysFontMetrics;
	sysFontColor = KJLoader::kjofol->prefs()->sysFontColor();

//	kdDebug(66666) << "mHeight=" << mHeight << endl;

	int fSize;
	for(fSize = mHeight; fSize>=4; fSize--)
	{
		sysFont.setPixelSize ( fSize );
		sysFontMetrics = new TQFontMetrics(sysFont);
//		kdDebug(66666) << "wanted fSize=" << fSize << ", metric h=" << sysFontMetrics->height() << endl;
		// either found a small enough font or found no proper font at all
		if ( sysFontMetrics->height() <= mHeight || fSize==4 )
		{
//			kdDebug(66666) << "stopping @ fSize=" << fSize << ", metric h=" << sysFontMetrics->height() << endl;
			return;
		}
		delete sysFontMetrics;
	}
}

TQPixmap KJFont::draw(const TQCString &str, int wide, const TQPoint &pos) const
{
	if ( mUseSysFont )
		return drawSysFont(str,wide,pos);
	else
		return drawPixmapFont(str,wide,pos);
}

TQPixmap KJFont::drawSysFont(const TQCString &s, int wide, const TQPoint &pos) const
{
//	kdDebug(66666) << k_funcinfo << "BEGIN, s='" << s << "'" << endl;
	TQPoint to(pos);
	TQString string(s);

	int stringWidth = sysFontMetrics->width( string );
//	kdDebug(66666) << "final metrics; w=" << stringWidth << ", h=" << sysFontMetrics->height() << endl;

	TQPixmap region(
		(stringWidth > wide ? stringWidth : wide),
		mHeight);
	TQPainter rp(&region); // region painter

	TQBitmap regionMask(
		(stringWidth > wide ? stringWidth : wide),
		mHeight, true); // fully transparent mask
	TQPainter mp(&regionMask); // mask painter

//	kdDebug(66666) << "region; w=" << region.width() << ", h=" << region.height() << endl;

	int freeSpace=0;
	// center string into pixmap if its chars won't fill the whole pixmap
	if ( stringWidth < wide )
	{
		freeSpace = wide - stringWidth;
		mp.fillRect ( to.x(), 0, (freeSpace/2), mHeight, TQt::color0 );
		to += TQPoint ( (freeSpace/2), 0 );
//		kdDebug(66666) << "centering text, freeSpace=" << freeSpace << endl;
	}

	rp.setFont(sysFont);
	rp.setPen(sysFontColor);
	rp.drawText(to.x(), to.y(), region.width()-freeSpace, mHeight, TQt::AlignLeft|TQt::AlignTop, string);

	mp.setFont(sysFont);
	mp.setPen(TQt::color1);
	mp.drawText(to.x(), to.y(), region.width()-freeSpace, mHeight, TQt::AlignLeft|TQt::AlignTop, string);

	to += TQPoint(region.width()-freeSpace,0);
//	kdDebug(66666) << "text width=" << region.width()-freeSpace << endl;

	if (freeSpace > 0)
	{
		mp.fillRect ( to.x(), 0, (freeSpace/2), mHeight, TQt::color0 );
		to += TQPoint ( (freeSpace/2), 0 );
//		kdDebug(66666) << "centering text, freeSpace=" << freeSpace << endl;
	}

	region.setMask( regionMask );
//	kdDebug(66666) << "width: " << wide << "|end after drawing: " << to.x() << endl;
//	kdDebug(66666) << k_funcinfo << "END" << endl << endl;
	return region;
}

TQPixmap KJFont::drawPixmapFont(const TQCString &str, int wide, const TQPoint &pos) const
{
//	kdDebug(66666) << k_funcinfo << "BEGIN" << endl;
	TQPoint to(pos);

	TQCString string = str.lower();
	TQPixmap region(
		(string.length()*mWidth+string.length()*mSpacing > (unsigned int)wide
			? string.length()*mWidth+string.length()*mSpacing : wide),
		mHeight);

	TQBitmap regionMask(
			 (string.length()*mWidth+string.length()*mSpacing > (unsigned int)wide
			? string.length()*mWidth+string.length()*mSpacing : wide),
			 mHeight, true); // fully transparent mask
	TQPainter mask( &regionMask );

//	kdDebug(66666) << "draw: {" << str << "}" << endl;

	int freeSpace=0;
	// center string into pixmap if its chars won't fill the whole pixmap
	if ( string.length()*mWidth+string.length()*mSpacing < (unsigned int)wide )
	{
		freeSpace = wide - string.length()*mWidth+string.length()*mSpacing;
		mask.fillRect ( to.x(), 0, (freeSpace/2), mHeight, TQt::color0 );
		to += TQPoint ( (freeSpace/2), 0 );
	}

//	kdDebug(66666) << k_funcinfo << "pixmap width=" << region.width() << endl;

	// draw every char and add spacing in between these chars if defined
	unsigned int stringLength(string.length());
	for ( unsigned int charPos=0; charPos < stringLength; charPos++ )
	{
		char c = string[charPos]; // the character to be drawn next

		drawCharacter(&region, &regionMask, to, c);
		to += TQPoint(mWidth, 0);

		// draw according to "spacing"
		if ( (charPos < string.length()-1) && mSpacing > 0 )
		{	// make the spacing-area transparent
			mask.fillRect ( to.x(), 0, mSpacing, mHeight, TQt::color0 );
			to += TQPoint ( mSpacing, 0 );
		}
	}

	if (freeSpace > 0)
	{
		mask.fillRect ( to.x(), 0, (freeSpace/2), mHeight, TQt::color0 );
		to += TQPoint ( (freeSpace/2), 0 );
	}

	region.setMask( regionMask );
//	kdDebug(66666) << "width: " << wide << "|end after drawing: " << to.x() << endl;
	return region;
}

void KJFont::drawCharacter(TQPixmap *dev, TQBitmap *devMask, const TQPoint &to, char c) const
{
	TQPoint src=charSource(c);
	int x=src.x();
	int y=src.y();
	int xs=mWidth;
	int ys=mHeight;

	bitBlt(dev, to, &mText, TQRect(x,y,xs,ys), TQt::CopyROP);

	// bitBlt mask for transparency
	if ( mTransparent )
	{
		bitBlt(devMask, to, &mTextMask, TQRect(x,y,xs,ys), TQt::OrROP);
	}
	else // fill mask
	{
		TQPainter tempPainter (devMask);
		tempPainter.fillRect ( to.x(), 0, xs,ys, TQt::color1 );
	}
}

// needed for strchr
#include <string.h>

// searches for top/left coordinate of a given character inside the font-pixmap
TQPoint KJFont::charSource(char c) const
{
	for (int i=0; i<3; i++)
	{
		const char *pos = strchr(mString[i], c);

		if (!pos) continue;
		return TQPoint(mWidth*((int)(pos-mString[i])), mHeight*i);
	}

	return charSource(mNullChar);
}