#include "TextFeld.h"
#include "Schrift.h"
#include "Text.h"
#include "Farbe.h"
#include "Rahmen.h"
#include "Bild.h"
#include "Punkt.h"
#include "TastaturEreignis.h"
#include "MausEreignis.h"
#include "Fenster.h"
#include <math.h>
#include "Globals.h"

using namespace Framework;

// Inhalt der TextFeld Klasse aus TextFeld.h 
// Konstruktor 
TextFeld::TextFeld()
:	Objekt()
{
	this->setMausEreignis( _ret1ME );
	this->setTastaturEreignis( _ret1TE );
	style = 0;
	schriftGröße = 12;
	schrift = 0;
	buffer = 0;
	bgF = 0;
	sF = 0;
	bgBuff = 0;
	rahmen = 0;
	bgBild = 0;
	showChar = 0;
	begf = 0, cpos = 0;
	tickVal = 0;
	ref = 1;
}

// Destruktor 
TextFeld::~TextFeld()
{
	if( schrift )
		schrift->release();
	if( buffer )
		buffer->release();
	if( bgF )
		bgF->release();
	if( sF )
		sF->release();
	if( rahmen )
		rahmen->release();
	if( bgBild )
		bgBild->release();
}

// nicht constant 
void TextFeld::update() // aktualisiert Position und größe 
{
	int rbr = 0;
	if( rahmen && hatStyle( TF_Style::Rahmen ) )
	{
		rbr = rahmen->getRBreite();
		rahmen->setPosition( pos->x, pos->y );
		rahmen->setGröße( gr->x, gr->y );
	}
}

void TextFeld::setText( Text *txt ) // setzt den angezeigten Text
{
	if( !buffer )
		buffer = new Text();
	buffer->setText( txt );
}

void TextFeld::setTextZ( Text *txt ) // setzt einen Zeiger zum angezeigten Text
{
	if( buffer )
		buffer->release();
	buffer = txt;
}

void TextFeld::setText( const char *txt ) // setzt den angezeigten Text
{
	if( !buffer )
		buffer = new Text();
	buffer->setText( txt );
}

void TextFeld::setAuswahl( int pos1, int pos2 ) // setzt den Ausgewählten Text
{
	cpos = pos1;
	begf = pos2;
}

void TextFeld::setAuswahl( Punkt *auswahl )
{
	cpos = auswahl->x;
	begf = auswahl->y;
	auswahl->release();
}

void TextFeld::setHintergrundBild( Bild *bild ) // setzt das Hintergrund Bild
{
	if( !bgBild )
		bgBild = new Bild();
	bgBild->neuBild( bild->getGröße(), new Farbe() );
	int *buff1 = bgBild->getBuffer();
	int *buff2 = bild->getBuffer();
	for( int i = 0; i < bild->getBreite() * bild->getHöhe(); i++ )
		buff1[ i ] = buff2[ i ];
	bild->release();
}

void TextFeld::setHintergrundBildZ( Bild *bild ) // setzt einen Zeiger zum Hintergrund Bild
{
	if( bgBild )
		bgBild->release();
	bgBild = bild;
}

void TextFeld::setHintergrundFarbe( int fc ) // setzt die Hintergrundfarbe
{
	if( !bgF )
		bgF = new Farbe();
	bgF->setFarbe( fc );
}

void TextFeld::setHintergrundFarbe( Farbe *f )
{
	if( !bgF )
		bgF = new Farbe();
	bgF->setFarbe( f->getFarbe() );
	f->release();
}

void TextFeld::setHintergrundFarbeZ( Farbe *f ) // setzt einen Zeiger zur Hintergrundfarbe
{
	if( bgF )
		bgF->release();
	bgF = f;
}

void TextFeld::setSchriftZ( Schrift *schrift ) // setzt einen Zeiger zur Schrift
{
	if( this->schrift )
		this->schrift->release();
	this->schrift = schrift;
}

void TextFeld::setSchriftGröße( unsigned char gr ) // setzt die Schriftgröße
{
	schriftGröße = gr;
}

void TextFeld::setSchriftFarbe( int fc ) // setzt die Schrift Farbe
{
	if( !sF )
		sF = new Farbe();
	sF->setFarbe( fc );
}

void TextFeld::setSchriftFarbe( Farbe *f )
{
	if( !sF )
		sF = new Farbe();
	sF->setFarbe( f->getFarbe() );
	f->release();
}

void TextFeld::setSchriftFarbeZ( Farbe *f ) // setze einen Zeiger zur Schriftfarbe
{
	if( sF )
		sF->release();
	sF = f;
}

void TextFeld::setLRZ( LRahmen *ram ) // setzt einen Zeiger zum Rahmen
{
	if( rahmen )
		rahmen->release();
	rahmen = ram;
}

void TextFeld::setLRBreite( int br ) // setzt die Breite des Rahmens
{
	if( !rahmen )
		rahmen = new LRahmen();
	rahmen->setRamenBreite( br );
}

void TextFeld::setLRFarbe( int fc ) // setzt die Farbe des Rahmens
{
	if( !rahmen )
		rahmen = new LRahmen();
	rahmen->setFarbe( fc );
}

void TextFeld::setLRFarbe( Farbe *f )
{
	if( !rahmen )
		rahmen = new LRahmen();
	rahmen->setFarbe( f->getFarbe() );
	f->release();
}

void TextFeld::setLRFarbeZ( Farbe *f ) // setzt einen Zeiger zur Farbe des Rahmens
{
	if( !rahmen )
		rahmen = new LRahmen();
	rahmen->setFarbeZ( f );
}

void TextFeld::setSchowChar( unsigned char c ) // bei Passwortfeld *
{
	showChar = c;
}

void TextFeld::setStyle( int style ) // setzt den Style des Text Feldes
{
	this->style = style;
}

void TextFeld::setStyle( int style, bool add_löschen )
{
	if( add_löschen )
		this->style |= style;
	else
		this->style &= ~style;
}

void TextFeld::addStyle( int style )
{
	this->style |= style;
}

void TextFeld::löscheStyle( int style )
{
	this->style &= ~style;
}

void TextFeld::tick( double tickval ) // tick
{
	tickVal += tickval;
	if( tickVal >= 1 )
		tickVal -= 1;
}

void TextFeld::doMausEreignis( MausEreignis *me ) // Maus Ereignis
{
	if( hatStyleNicht( TF_Style::Erlaubt ) || hatStyleNicht( TF_Style::Sichtbar ) )
		return;
	bool removeFokus = 0;
	if( me->verarbeitet || !( me->mx >= pos->x && me->mx <= pos->x + gr->x && me->my >= pos->y && me->my <= pos->y + gr->y ) )
	{
		if( mausIn )
		{
			mausIn = 0;
			MausEreignis me2;
			me2.id = ME_Verlässt;
			me2.mx = me->mx;
			me2.my = me->my;
			me2.verarbeitet = 0;
			doMausEreignis( &me2 );
			return;
		}
		removeFokus = 1;
	}
	if( !( me->mx >= pos->x && me->mx <= pos->x + gr->x && me->my >= pos->y && me->my <= pos->y + gr->y ) && me->id != ME_Verlässt )
	{
		if( removeFokus && me->id == ME_RLinks )
			if( Mak && ( me->verarbeitet || Mak( this, *me ) ) )
				löscheStyle( TF_Style::Fokus );
		return;
	}
	if( !mausIn && me->id != ME_Verlässt )
	{
		mausIn = 1;
		MausEreignis me2;
		me2.id = ME_Betritt;
		me2.mx = me->mx;
		me2.my = me->my;
		me2.verarbeitet = 0;
		doMausEreignis( &me2 );
	}
	me->mx -= pos->x, me->my -= pos->y;
	if( Mak && ( me->verarbeitet || Mak( this, *me ) ) )
	{
		if( removeFokus && me->id == ME_RLinks )
			löscheStyle( TF_Style::Fokus );
		if( !me->verarbeitet )
		{
			if( hatStyleNicht( TF_Style::Fokus ) )
			{
				if( me->id == Framework::ME_PLinks )
				{
					addStyle( TF_Style::Fokus );
				}
			}
			if( schrift )
			{
				schrift->setSchriftGröße( schriftGröße );
				bool shift = TastenStand[ T_Shift ];
				if( me->id == Framework::ME_PLinks )
				{
					int rbr = 0;
					if( rahmen )
						rbr = rahmen->getRBreite();
					int tbr = schrift->getTextBreite( buffer->getThis() );
					int thö = schrift->getTextHöhe( buffer->getThis() );
					int xxx = me->mx - rbr;
					int yyy = me->my - rbr;
					if( hatStyle( TF_Style::HCenter ) )
						xxx -= ( ( gr->x / 2 ) - tbr / 2 ) - rbr;
					if( hatStyle( TF_Style::VCenter ) )
						yyy -= ( ( gr->y / 2 ) - thö / 2 ) - rbr;
					int pos = schrift->textPos( buffer->getThis(), xxx, yyy );
					if( pos != -1 )
					{
						if( shift )
							begf = pos;
						else
						{
							cpos = pos;
							begf = pos;
						}
					}
				}
				if( me->id == ME_RLinks )
				{
					if( !shift )
					{
						int rbr = 0;
						if( rahmen )
							rbr = rahmen->getRBreite();
						int tbr = schrift->getTextBreite( buffer->getThis() );
						int thö = schrift->getTextHöhe( buffer->getThis() );
						int xxx = me->mx - rbr;
						int yyy = me->my - rbr;
						if( hatStyle( TF_Style::HCenter ) )
							xxx -= ( ( gr->x / 2 ) - tbr / 2 ) - rbr;
						if( hatStyle( TF_Style::VCenter ) )
							yyy -= ( ( gr->y / 2 ) - thö / 2 ) - rbr;
						int pos = schrift->textPos( buffer->getThis(), xxx, yyy );
						if( pos != -1 )
							begf = pos;
					}
				}
			}
		}
		me->verarbeitet = 1;
	}
	me->mx += pos->x, me->my += pos->y;
}

void TextFeld::doTastaturEreignis( TastaturEreignis *te )
{
	if( te->verarbeitet || hatStyleNicht( TF_Style::Fokus ) )
		return;
	if( !Tak )
		return;
	if( Tak( this, *te ) )
	{
		if( hatStyleNicht( TF_Style::Erlaubt ) )
			return;
		if( te->id == TE_Press )
		{
			bool shift = TastenStand[ T_Shift ];
			bool strg = TastenStand[ T_Strg ];
			switch( te->taste )
			{
			case T_Entf:
				if( cpos != begf )
					buffer->löschen( cpos, begf );
				else
					buffer->löschen( cpos, cpos + 1 );
				begf = cpos;
				break;
			case T_BackSpace:
				if( cpos != begf )
				{
					buffer->löschen( cpos, begf );
					cpos -= abs( cpos - begf );
				}
				else
				{
					buffer->löschen( cpos - 1, cpos );
					cpos--;
				}
				begf = cpos;
				break;
			case T_Enter:
				if( cpos != begf )
				{
					buffer->löschen( begf, cpos );
					cpos -= abs( cpos - begf );
				}
				buffer->einfügen( cpos, '\n' );
				cpos++;
				begf = cpos;
				break;
			case T_Links:
				if( shift )
				{
					if( strg )
						begf = buffer->getLKick( begf );
					else
						begf--;
				}
				else
				{
					if( strg )
						cpos = buffer->getLKick( cpos );
					else
						cpos--;
					begf = cpos;
				}
				break;
			case T_Oben:
				if( shift )
				{
					begf = buffer->getOKick( begf );
				}
				else
				{
					cpos = buffer->getOKick( cpos );
					begf = cpos;
				}
				break;
			case T_Rechts:
				if( shift )
				{
					if( strg )
						begf = buffer->getRKick( begf );
					else
						begf++;
				}
				else
				{
					if( strg )
						cpos = buffer->getRKick( cpos );
					else
						cpos++;
					begf = cpos;
				}
				break;
			case T_Unten:
				if( shift )
				{
					begf = buffer->getUKick( begf );
				}
				else
				{
					cpos = buffer->getUKick( cpos );
					begf = cpos;
				}
				break;
			default:
				if( istSchreibbar( te->taste ) )
				{
					if( begf != cpos )
					{
						buffer->löschen( begf, cpos );
						if( cpos > begf )
							cpos = begf;
					}
					buffer->einfügen( cpos, (char)te->taste );
					cpos++;
					begf = cpos;
				}
				break;
			}
		}
		if( cpos < 0 )
			cpos = 0;
		if( cpos > buffer->getLänge() )
			cpos = buffer->getLänge();
		if( begf < 0 )
			begf = 0;
		if( begf > buffer->getLänge() )
			begf = buffer->getLänge();
		te->verarbeitet = 1;
	}
}

void TextFeld::render( Bild *rObj ) // zeichenet nach rObj
{
	if( hatStyleNicht( TF_Style::Sichtbar ) )
		return;
	lockObjekt();
	int x = pos->x;
	int y = pos->y;
	int br = gr->x;
	int hö = gr->y;
	rObj->setDrawOptions( x, y, x + br, y + hö );
	if( hatStyle( TF_Style::Hintergrund ) )
	{
		if( bgF )
			if( hatStyle( TF_Style::HAlpha ) )
				rObj->alphaRegion( x, y, br, hö, bgF->getFarbe() );
			else
				rObj->füllRegion( x, y, br, hö, bgF->getFarbe() );
		if( hatStyle( TF_Style::HBild ) && bgBild )
			if( hatStyle( TF_Style::HAlpha ) )
				rObj->alphaBild( x, y, br, hö, bgBild );
			else
				rObj->drawBild( x, y, br, hö, bgBild );
	}
	if( hatStyle( TF_Style::Rahmen ) && rahmen )
		rahmen->render( rObj );
	if( !buffer || !sF || !schrift )
	{
		rObj->setDrawOptions( -1, -1, -1, -1 );
		unlockObjekt();
		return;
	}
	if( hatStyleNicht( TF_Style::Mehrzeilig ) )
		buffer->löschen( '\n' );
	if( hatStyleNicht( TF_Style::Mehrfarbig ) )
		while( buffer->hat( '\r' ) )
			buffer->löschen( buffer->positionVon( '\r' ), buffer->positionVon( '\r' ) + 11 );
	schrift->lockSchrift();
	schrift->setFarbe( sF->getFarbe() );
	schrift->setSchriftGröße( schriftGröße );
	int rbr = 0;
	if( rahmen && hatStyle( TF_Style::Rahmen ) )
		rbr = rahmen->getRBreite();
	int tbr = schrift->getTextBreite( buffer->getThis() );
	int thö = schrift->getTextHöhe( buffer->getThis() );
	int xxx = pos->x + rbr;
	int yyy = pos->y + rbr;
	if( hatStyle( TF_Style::HCenter ) )
		xxx = ( pos->x + gr->x / 2 ) - tbr / 2;
	if( hatStyle( TF_Style::VCenter ) )
		yyy = ( pos->y + gr->y / 2 ) - thö / 2;
	schrift->setDrawPosition( xxx, yyy );
	if( hatStyle( TF_Style::Fokus ) && hatStyle( TF_Style::Erlaubt ) )
	{
		if( istSchreibbar( showChar ) )
		{
			Text *rt = new Text();
			int län = buffer->getLänge() - buffer->anzahlVon( '\n' ) - buffer->anzahlVon( '\r' ) * 11;
			rt->füllText( showChar, län );
			if( tickVal <= 0.5 )
				schrift->renderText( rt, rObj, cpos, 0xFFFF5555, begf, 0xFF0000FF );
			else
				schrift->renderText( rt, rObj, cpos, 0x00000000, begf, 0xFF0000FF );
		}
		else
		{
			if( tickVal <= 0.5 )
				schrift->renderText( buffer->getThis(), rObj, cpos, 0xFFFF5555, begf, 0xFF0000FF );
			else
				schrift->renderText( buffer->getThis(), rObj, cpos, 0x00000000, begf, 0xFF0000FF );
		}
	}
	else
	{
		if( istSchreibbar( showChar ) )
		{
			Text *rt = new Text();
			int län = buffer->getLänge() - buffer->anzahlVon( '\n' ) - buffer->anzahlVon( '\r' ) * 11;
			rt->füllText( showChar, län );
			schrift->renderText( rt, rObj );
		}
		else
			schrift->renderText( buffer->getThis(), rObj );
	}
	schrift->unlockSchrift();
	rObj->setDrawOptions( -1, -1, -1, -1 );
	unlockObjekt();
}

void TextFeld::render( int xOff, int yOff, int bOff, int hOff, Bild *zrObj )
{
	if( hatStyleNicht( TF_Style::Sichtbar ) )
		return;
	lockObjekt();
	int x = pos->x + xOff;
	int y = pos->y + yOff;
	int br = gr->x;
	int hö = gr->y;
	int xx = x < ( xOff + bOff ) ? x : ( xOff + bOff );
	xx = xx >= xOff ? xx : xOff;
	int yy = y < ( yOff + hOff ) ? y : ( yOff + hOff );
	yy = yy >= yOff ? yy : yOff;
	int xb = ( x + br ) < ( xOff + bOff ) ? ( x + br ) : ( xOff + bOff );
	xb = xb >= xOff ? xb : ( xOff - 1 );
	int yh = ( y + hö ) < ( yOff + hOff ) ? ( y + hö ) : ( yOff + hOff );
	yh = yh >= yOff ? yh : ( yOff - 1 );
	if( xx == xOff + bOff || yy == yOff + hOff || xb == xOff - 1 || yh == yOff - 1 )
	{
		unlockObjekt();
		return;
	}
	zrObj->setDrawOptions( xx, yy, xb, yh );
	if( hatStyle( TF_Style::Hintergrund ) )
	{
		if( bgF )
			if( hatStyle( TF_Style::HAlpha ) )
				zrObj->alphaRegion( x, y, br, hö, bgF->getFarbe() );
			else
				zrObj->füllRegion( x, y, br, hö, bgF->getFarbe() );
		if( hatStyle( TF_Style::HBild ) && bgBild )
			if( hatStyle( TF_Style::HAlpha ) )
				zrObj->alphaBild( x, y, br, hö, bgBild );
			else
				zrObj->drawBild( x, y, br, hö, bgBild );
	}
	int rbr = 0;
	if( hatStyle( TF_Style::Rahmen ) && rahmen )
	{
		rahmen->setPosition( x, y );
		rahmen->setGröße( br, hö );
		rahmen->render( zrObj );
		rbr = rahmen->getRBreite();
	}
	if( !buffer || !sF || !schrift )
	{
		zrObj->setDrawOptions( -1, -1, -1, -1 );
		unlockObjekt();
		return;
	}
	if( hatStyleNicht( TF_Style::Mehrzeilig ) )
		buffer->löschen( '\n' );
	if( hatStyleNicht( TF_Style::Mehrfarbig ) )
		while( buffer->hat( '\r' ) )
			buffer->löschen( buffer->positionVon( '\r' ), buffer->positionVon( '\r' ) + 11 );
	schrift->lockSchrift();
	schrift->setFarbe( sF->getFarbe() );
	schrift->setSchriftGröße( schriftGröße );
	int tbr = schrift->getTextBreite( buffer->getThis() );
	int thö = schrift->getTextHöhe( buffer->getThis() );
	int xxx = x + rbr;
	int yyy = y + rbr;
	if( hatStyle( TF_Style::HCenter ) )
		xxx = ( x + gr->x / 2 ) - tbr / 2;
	if( hatStyle( TF_Style::VCenter ) )
		yyy = ( y + gr->y / 2 ) - thö / 2;
	schrift->setDrawPosition( xxx, yyy );
	if( hatStyle( TF_Style::Fokus ) && hatStyle( TF_Style::Erlaubt ) )
	{
		if( istSchreibbar( showChar ) )
		{
			Text *rt = new Text();
			int län = buffer->getLänge() - buffer->anzahlVon( '\n' ) - buffer->anzahlVon( '\r' ) * 11;
			rt->füllText( showChar, län );
			if( tickVal <= 0.5 )
				schrift->renderText( rt, zrObj, cpos, 0xFFFF5555, begf, 0xFF0000FF );
			else
				schrift->renderText( rt, zrObj, cpos, 0x00000000, begf, 0xFF0000FF );
		}
		else
		{
			if( tickVal <= 0.5 )
				schrift->renderText( buffer->getThis(), zrObj, cpos, 0xFFFF5555, begf, 0xFF0000FF );
			else
				schrift->renderText( buffer->getThis(), zrObj, cpos, 0x00000000, begf, 0xFF0000FF );
		}
	}
	else
	{
		if( istSchreibbar( showChar ) )
		{
			Text *rt = new Text();
			int län = buffer->getLänge() - buffer->anzahlVon( '\n' ) - buffer->anzahlVon( '\r' ) * 11;
			rt->füllText( showChar, län );
			schrift->renderText( rt, zrObj );
		}
		else
			schrift->renderText( buffer->getThis(), zrObj );
	}
	schrift->unlockSchrift();
	zrObj->setDrawOptions( -1, -1, -1, -1 );
	unlockObjekt();
}

// Konstant 
Text *TextFeld::getText() const // gibt vom Text zurück
{
	if( !buffer )
		return 0;
	return buffer->getThis();
}

Text *TextFeld::zText() const // gibt den Text zurück
{
	return buffer;
}

Bild *TextFeld::getHintergrundBild() const // gibt getThis vom Hintergrund Bild zurück
{
	if( !bgBild )
		return 0;
	return bgBild->getThis();
}

Bild *TextFeld::zHintergrundBild() const // gibt das Hintergrund Bild zurück
{
	return bgBild;
}

Farbe *TextFeld::getHintergrundFarbe() const // giebt getThis der Hintergrundfarbe zurück
{
	if( !bgF )
		return 0;
	return bgF->getThis();
}

Farbe *TextFeld::zHintergrundFarbe() const // gibt die Hintergrundfarbe zurück
{
	return bgF;
}

int TextFeld::getHintergrundFarbeCode() const
{
	if( !bgF )
		return 0;
	return bgF->getFarbe();
}

Schrift *TextFeld::getSchrift() const// gint getThis der Schrift Zurück
{
	if( !schrift )
		return 0;
	return schrift->getThis();
}

Schrift *TextFeld::zSchrift() const// gibt die Schrift zurück
{
	return schrift;
}

unsigned char TextFeld::getSchriftGröße() const // gibt die Schriftgröße zurück
{
	return schriftGröße;
}

Farbe *TextFeld::getSchriftFarbe() const// gibt getThis der Schriftfarbe zurück
{
	if( !sF )
		return 0;
	return sF->getThis();
}

Farbe *TextFeld::zSchriftFarbe() const // gibt die Schriftfarbe zurück
{
	return sF;
}

int TextFeld::getSchriftFarbeCode() const
{
	if( !sF )
		return 0;
	return sF->getFarbe();
}

LRahmen *TextFeld::getLR() const // gibt getThis des Rahmens zurück
{
	if( !rahmen )
		return 0;
	return rahmen->getThis();
}

LRahmen *TextFeld::zLR() const // gibt den Rahmen zurück
{
	return rahmen;
}

int TextFeld::getLRBreite() const // gibt die Breite des Rahmens zurück
{
	if( !rahmen )
		return 0;
	return rahmen->getRBreite();
}

Farbe *TextFeld::getLRFarbe() const // gibt getThis der Farbe des Rahmens zurück
{
	if( !rahmen )
		return 0;
	return rahmen->getFarbe();
}

Farbe *TextFeld::zLRFarbe() const // gibt die Farbe des Rahmens zurück
{
	return rahmen->zFarbe();
}

int TextFeld::getLRFarbeCode() const
{
	if( !rahmen )
		return 0;
	return rahmen->getFarbeCode();
}

unsigned char TextFeld::getShowChar() const // gibt den Anzeige Char zurück
{
	return showChar;
}

bool TextFeld::hatStyle( int style ) const // prüft, ob style vorhanden
{
	return ( this->style | style ) == this->style;
}

bool TextFeld::hatStyleNicht( int style ) const // prüft, ob style nicht vorhanden
{
	return ( this->style | style ) != this->style;
}

int TextFeld::getMarkierungLänge() const // gibt die Länge der Markierung zurück
{
	return abs( cpos - begf );
}

// Reference Counting 
TextFeld *TextFeld::getThis()
{
	ref++;
	return this;
}

TextFeld *TextFeld::release()
{
	ref--;
	if( ref == 0 )
		delete this;
	return 0;
}