#include "MiniGames.h"
#include <Punkt.h>
#include <Rahmen.h>
#include "../../Global/Variablen.h"
#include <Datei.h>
#include "../../Global/Initialisierung.h"
#include <InitDatei.h>
#include <KSGTDatei.h>

typedef MiniGameV *( *GetMiniGame )( );

// Inhalt der MGLaden Klasse aus MiniGames.h
// Konstruktor
MGSuchen::MGSuchen( MiniGames *mGames )
{
	this->mGames = mGames;
	start();
}

// Destruktor
MGSuchen::~MGSuchen()
{
	mGames->release();
}

// nicht constant
void MGSuchen::thread()
{
	KSGTDatei *dgt = new KSGTDatei( "data/dg.ksgt" );
	dgt->laden();
	bool ak = 0;
	int dgId = infoKlient->getDateiGruppeIdVonPfad( "data/Minigames" );
	for( int i = 0; i < dgt->getZeilenAnzahl(); i++ )
	{
		if( dgt->zFeld( i, 0 ) && TextZuInt( dgt->zFeld( i, 0 )->getText(), 10 ) == dgId )
		{
			int lv = dgt->zFeld( i, 2 ) ? TextZuInt( dgt->zFeld( i, 2 )->getText(), 10 ) : 0;
			int ov = infoKlient->getDateiGruppeVersion( dgId );
			if( lv == ov )
				ak = 1;
			break;
		}
	}
	dgt->release();
	if( !ak )
	{
		mGames->setAktuell( 0, dgId );
		delete this;
		return;
	}
	Datei *d = new Datei();
	d->setDatei( "data/Minigames" );
	if( !d->existiert() )
		DateiPfadErstellen( "data/MiniGames/" );
	RCArray< Text > *list = d->getDateiListe();
	if( list )
	{
		for( int i = 0; i < list->getEintragAnzahl(); i++ )
		{
			MiniGame *mg = new MiniGame( list->z( i )->getText() );
			if( !mg->istOk() )
			{
				mg->release();
				continue;
			}
			mGames->addMiniGame( mg );
		}
		list->release();
	}
	d->release();
	delete this;
}


// Inhalt der MGLaden Klasse aus MiniGameV.h
// Konstruktor
MGLaden::MGLaden( char *name )
{
	this->name = new Text( name );
	game = 0;
	ref = 1;
	start();
}

// Destruktor
MGLaden::~MGLaden()
{
	if( game )
	{
		game->release();
		dllDateien->releaseDLL( name->getText() );
	}
	name->release();
}

// nicht constant
void MGLaden::thread()
{
	Text *pfad = new Text( "data/Minigames/" );
	pfad->anhängen( name->getText() );
	if( !DateiExistiert( pfad->getThis() ) )
	{
		pfad->release();
		run = 0;
		return;
	}
	pfad->anhängen( "/mg.ini" );
	if( !DateiExistiert( pfad->getThis() ) )
	{
		pfad->release();
		run = 0;
		return;
	}
	InitDatei *mgIni = new InitDatei( pfad );
	if( !mgIni->laden() )
	{
		mgIni->release();
		run = 0;
		return;
	}
	if( !mgIni->wertExistiert( "DllPfad" ) )
	{
		mgIni->release();
		run = 0;
		return;
	}
	Text *dllPfad = new Text( "data/Minigames/" );
	dllPfad->anhängen( name->getText() );
	dllPfad->anhängen( "/" );
	dllPfad->anhängen( mgIni->zWert( "DllPfad" )->getText() );
	mgIni->release();
	if( !DateiExistiert( dllPfad->getThis() ) )
	{
		dllPfad->release();
		run = 0;
		return;
	}
	HMODULE dll = dllDateien->ladeDLL( name->getText(), dllPfad->getText() );
	dllPfad->release();
	if( !dll )
	{
		run = 0;
		return;
	}
	GetMiniGame getMiniGame = (GetMiniGame)GetProcAddress( dll, "GetMiniGame" );
	if( !getMiniGame )
	{
		dllDateien->releaseDLL( name->getText() );
		run = 0;
		return;
	}
	game = getMiniGame();
	if( !game )
	{
		dllDateien->releaseDLL( name->getText() );
		run = 0;
		return;
	}
	if( !game->laden() )
	{
		game = game->release();
		dllDateien->releaseDLL( name->getText() );
	}
	run = 0;
}

// constant
bool MGLaden::fertig() const
{
	return !läuft();
}

MiniGameV *MGLaden::zGame() const
{
	return game;
}

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

MGLaden *MGLaden::release()
{
	ref--;
	if( !ref )
		delete this;
	return 0;
}


// Inhalt der MiniGames Klasse aus MiniGames.h
// Konstruktor
MiniGames::MiniGames( Schrift *zSchrift, Fenster *zNachLoginFenster, int x )
	: Zeichnung()
{
	schrift = zSchrift->getThis();
	bildschirmGröße = BildschirmGröße();
	pos = Punkt( x, 67 );
	gr = Punkt( 102, 32 );
	rahmen = new LRahmen();
	rahmen->setFarbe( 0xFFFFFFFF );
	rahmen->setGröße( 102, 32 );
	alpha = 0;
	alpha2 = 0;
	animation = 0;
	sichtbar = 0;
	tickVal = 0;
	prozent1 = 0;
	prozent2 = 0;
	begPos = Punkt( 0, 0 );
	begGröße = Punkt( 0, 0 );
	größe1 = Punkt( 102, 32 );
	pos1 = Punkt( x, 67 );
	größe2 = Punkt( 800, 500 );
	pos2 = bildschirmGröße / 2 - größe2 / 2;
	laden = (Animation2D*)ladeAnimation->dublizieren();
	laden->setSichtbar( 0 );
	laden->setPosition( 375, 225 );
	games = new RCArray< MiniGame >();
	suchFilter = initTextFeld( 10, 10, 100, 20, zSchrift, TextFeld::Style::Text | TextFeld::Style::VCenter, "Suchfilter:" );
	zSchrift->setSchriftGröße( 12 );
	suchFilter->setGröße( zSchrift->getTextBreite( suchFilter->zText() ), 20 );
	suchName = initTextFeld( 20 + suchFilter->getBreite(), 10, 200, 20, zSchrift, TextFeld::Style::TextFeld, "" );
	suchen = initKnopf( 230 + suchFilter->getBreite(), 10, 100, 20, zSchrift, Knopf::Style::Sichtbar, "Suchen" );
	gefiltert = 0;
	zNachLoginFenster->addMember( this );
	dg = 0;
	mgl = 0;
	ref = 1;
	new MGSuchen( getThis() );
}

// Destruktor
MiniGames::~MiniGames()
{
	if( schrift )
		schrift->release();
	rahmen->release();
	suchName->release();
	suchFilter->release();
	suchen->release();
	laden->release();
	games->release();
	if( mgl )
		mgl->release();
}

// nicht constant
void MiniGames::setSichtbar( bool sicht )
{
	begPos = pos;
	begGröße = gr;
	animation |= ( sicht ? 0x1 : 0x2 );
	rend = 1;
}

void MiniGames::addMiniGame( MiniGame *mg )
{
	games->add( mg );
	if( gefiltert )
		filter();
	else
	{
		int i = games->getEintragAnzahl() - 1;
		games->z( i )->setPosition( 10 + 10 * ( i % 3 ) + 250 * ( i % 3 ), 50 + 10 * ( i / 3 ) + 100 * ( i / 3 ) );
	}
	if( dg && updateH->hat( 0, dg ) )
		updateH->lösche( 0, dg );
}

void MiniGames::setAktuell( bool aktuell, int dg )
{
	this->aktuell = aktuell;
	if( aktuell )
		new MGSuchen( getThis() );
	if( !this->dg )
		this->dg = dg;
	if( !aktuell && !updateH->hat( 0, this->dg ) )
		updateH->erstellen( schrift, 0, this->dg );
	if( !aktuell )
		updateH->setSichtbar( 0, 1, this->dg );
}

void MiniGames::filter()
{
	Text filter = suchName->zText()->getText();
	bool notF = 0;
	if( !filter.getLänge() )
		notF = 1;
	int anz = games->getEintragAnzahl();
	bool *fertig = new bool[ anz ];
	for( int i = 0; i < anz; i++ )
		fertig[ i ] = 0;
	for( int i = 0; i < anz; i++ )
	{
		int pos = -1;
		int p = -1;
		for( int j = 0; j < anz; j++ )
		{
			if( ( notF || ( games->z( j )->zName()->hat( filter ) && ( pos == -1 || games->z( j )->zName()->positionVon( filter ) < pos ) ) ) && !fertig[ j ] )
			{
				p = j;
				pos = games->z( j )->zName()->positionVon( filter );
				games->z( j )->setSichtbar( 1 );
			}
		}
		if( p < 0 )
			break;
		fertig[ p ] = 1;
		games->z( p )->setPosition( 10 + 10 * ( i % 3 ) + 250 * ( i % 3 ), 50 + 10 * ( i / 3 ) + 100 * ( i / 3 ) );
	}
	for( int i = 0; i < anz; i++ )
	{
		if( !fertig[ i ] )
			games->z( i )->setSichtbar( 0 );
	}
	delete[] fertig;
}

void MiniGames::doMausEreignis( MausEreignis &me )
{
	if( laden->istSichtbar() || !sichtbar )
		return;
	me.mx -= pos.x;
	me.my -= pos.y;
	if( !aktuell )
	{
		me.mx -= 200;
		me.my -= 400;
		updateH->doMausEreignis( 0, me, dg );
		me.mx += 200;
		me.my += 400;
	}
	if( alpha2 )
	{
		suchName->doMausEreignis( me );
		bool vera = me.verarbeitet;
		suchen->doMausEreignis( me );
		if( !vera && me.verarbeitet && me.id == ME_RLinks )
			filter();
		int anz = games->getEintragAnzahl();
		for( int i = 0; i < anz; i++ )
		{
			bool vera = me.verarbeitet;
			games->z( i )->doMausEreignis( me );
			if( !vera && me.verarbeitet && me.id == ME_RLinks )
			{ // spiel starten
				laden->setSichtbar( 1 );
				if( mgl )
					mgl = mgl->release();
				mgl = new MGLaden( games->z( i )->zName()->getText() );
			}
		}
	}
	if( mgl && mgl->zGame() )
		mgl->zGame()->doMausEreignis( me );
	me.mx += pos.x;
	me.my += pos.y;
}

void MiniGames::doTastaturEreignis( TastaturEreignis &te )
{
	if( laden->istSichtbar() || !sichtbar )
		return;
	if( alpha2 )
	{
		bool vera = te.verarbeitet;
		suchName->doTastaturEreignis( te );
		if( !vera && te.verarbeitet && te.taste == T_Enter && te.id == TE_Release )
			filter();
	}
	if( mgl && mgl->zGame() )
		mgl->zGame()->doTastaturEreignis( te );
}

bool MiniGames::tick( double z )
{
	if( !aktuell )
		rend |= updateH->tick( 0, z, dg );
	if( laden->istSichtbar() && mgl && mgl->fertig() )
	{
		if( !mgl->zGame() )
		{
			mgl = mgl->release();
			nachLogin->zNachrichtenListe()->addNachricht( new Text( "Fehler" ), new Text( "Das Minigame konnte nicht geladen werden." ), new Text( "Ok" ) );
		}
		else
		{
			mgl->zGame()->setSchriftZ( schrift->getThis() );
			mgl->zGame()->setBildschirmZ( hauptScreen->getThis() );
		}
		laden->setSichtbar( 0 );
	}
	if( mgl && mgl->zGame() && !alpha2 )
	{
		if( sichtbar && !animation )
			rend |= mgl->zGame()->tick( z );
		if( mgl->zGame()->istEnde() )
			mgl = mgl->release();
	}
	rend |= laden->tick( z );
	if( alpha2 )
	{
		rend |= suchName->tick( z );
		rend |= suchen->tick( z );
		int anz = games->getEintragAnzahl();
		for( int i = 0; i < anz; i++ )
			rend |= games->z( i )->tick( z );
	}
	tickVal += z * 150;
	int val = (int)tickVal;
	if( val < 1 )
	{
		bool ret = rend;
		rend = 0;
		return ret;
	}
	tickVal -= val;
	if( ( animation | 0x1 ) == animation ) // Einblenden
	{
		if( prozent1 != 100 )
		{
			prozent1 += val;
			if( prozent1 >= 100 )
				prozent1 = 100;
			pos = begPos + (Punkt)( ( ( Vec2< double > )( pos2 - begPos ) / 100.0 ) * prozent1 );
			gr = begGröße + (Punkt)( ( ( Vec2< double > )( größe2 - begGröße ) / 100.0 ) * prozent1 );
		}
		else if( alpha != 255 )
		{
			alpha += val * 2;
			if( alpha >= 255 || ( animation | 0x2 ) == animation )
			{
				alpha = 255;
				animation &= ~0x1;
				sichtbar = 1;
				prozent1 = 0;
			}
		}
		rend = 1;
	}
	if( ( animation | 0x2 ) == animation ) // ausblenden
	{
		if( alpha != 0 )
		{
			alpha -= val * 2;
			if( alpha < 0 )
				alpha = 0;
		}
		else
		{
			prozent2 += val;
			if( prozent2 > 100 )
				prozent2 = 100;
			pos = begPos + (Punkt)( ( ( Vec2< double > )( pos1 - begPos ) / 100.0 ) * prozent2 );
			gr = begGröße + (Punkt)( ( ( Vec2< double > )( größe1 - begGröße ) / 100.0 ) * prozent2 );
			if( prozent2 == 100 )
			{
				prozent2 = 0;
				animation &= ~0x2;
				sichtbar = 0;
			}
		}
		rend = 1;
	}
	if( mgl && alpha2 )
	{
		alpha2 -= val;
		if( alpha2 < 0 )
			alpha2 = 0;
		rend = 1;
	}
	if( !mgl && alpha2 != 255 )
	{
		alpha2 += val;
		if( alpha2 > 255 )
			alpha2 = 255;
		rend = 1;
	}
	bool ret = rend;
	rend = 0;
	return ret;
}

void MiniGames::render( Bild &zRObj )
{
	if( pos == pos1 )
		return;
	rahmen->setPosition( pos );
	rahmen->setGröße( gr );
	rahmen->render( zRObj );
	if( !zRObj.setDrawOptions( pos.x + 1, pos.y + 1, gr.x - 2, gr.y - 2 ) )
		return;
	int rbr = rahmen->getRBreite();
	zRObj.setAlpha( (unsigned char)alpha );
	zRObj.setAlpha( (unsigned char)alpha2 );
	suchFilter->render( zRObj );
	suchName->render( zRObj );
	suchen->render( zRObj );
	int anz = games->getEintragAnzahl();
	for( int i = 0; i < anz; i++ )
		games->z( i )->render( zRObj );
	if( !aktuell )
		updateH->render( 0, 200, 400, zRObj, dg );
	zRObj.releaseAlpha();
	laden->render( zRObj );
	if( mgl && mgl->fertig() && mgl->zGame() )
		mgl->zGame()->render( zRObj );
	zRObj.releaseAlpha();
	zRObj.releaseDrawOptions();
}

// constant
bool MiniGames::istAnimiert() const
{
	return animation != 0;
}

bool MiniGames::istSichtbar() const
{
	return sichtbar || prozent1 != 0;
}

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

MiniGames *MiniGames::release()
{
	ref--;
	if( !ref )
		delete this;
	return 0;
}