#include "Aufzeichnung.h"
#include <MausEreignis.h>
#include <TastaturEreignis.h>

// Inhalt der Aufzeichnung Klasse auf Aufzeichnung.h
// Konstruktor
Aufzeichnung::Aufzeichnung()
{
	nMsg = 0;
	nMsgVorw�rts = 0;
	schrift = 0;
	screen = 0;
	nachrichten = 0;
	bestenliste = 0;
	chat = 0;
	steuerung = 0;
	kam = 0;
	map = 0;
	ende = 0;
	spieler = new RCArray< VideoSpieler >();
	spielZeit = 0;
	rSpielZeit = new Array< double >();
	spielPause = 1;
	spielerAnzahl = 0;
	teamAnzahl = 0;
	kamSpielerNummer = -1;
	mx = -1;
	my = -1;
	geladen = 0;
	pauseZeit = -1;
	time = 0;
	ref = 1;
}

// Destruktor
Aufzeichnung::~Aufzeichnung()
{
	if( schrift )
		schrift->release();
	if( screen )
		screen->release();
	spieler->release();
	if( ende )
		ende->release();
	if( map )
		map->release();
	if( kam )
		kam->release();
	if( steuerung )
		steuerung->release();
	if( chat )
		chat->relese();
	if( bestenliste )
		bestenliste->release();
	if( nachrichten )
		nachrichten->release();
	rSpielZeit->release();
}

// nicht constant
void Aufzeichnung::setSchrift( Schrift *schrift )
{
	if( this->schrift )
		this->schrift->release();
	this->schrift = schrift;
}

void Aufzeichnung::setBildschirm( Bildschirm *screen )
{
	if( this->screen )
		this->screen->release();
	this->screen = screen;
}

bool Aufzeichnung::ladeSpiel( int id )
{
	nachrichten = new SpielNachricht( id );
	bestenliste = new VideoBestenliste( schrift->getThis() );
	chat = new VideoChat( schrift );
	steuerung = new VideoSteuerung( schrift, screen );
	kam = new VideoKamera();
	map = new VideoKarte();
	ende = new VideoEnde( schrift );
	Text f;
	if( nachrichten->hatFehler( &f ) )
	{
		ende->setText( f );
		ende->setSichtbar( 1 );
		geladen = 1;
		return 1;
	}
	spielerAnzahl = nachrichten->getSVD()->spielerAnzahl;
	teamAnzahl = 0;
	for( int i = 0; i < spielerAnzahl; i++ )
	{
		SpielerVideoDaten *dat = nachrichten->getSPVD( i );
		if( !i )
			kam->setSize( dat->kamBreite, dat->kamH�he );
		VideoSpieler *tmp = new VideoSpieler( dat );
		bestenliste->addSpieler( tmp );
		spieler->set( tmp, i );
		teamAnzahl = teamAnzahl < dat->team ? dat->team : teamAnzahl;
	}
	teamAnzahl++;
	bestenliste->setTeamAnzahl( teamAnzahl );
	for( int i = 0; i < nachrichten->getTeamAnzahl(); i++ )
	{
		TeamVideoDaten *dat = nachrichten->getTVD( i );
		bestenliste->setTeamMaxPunkte( dat->teamNummer, dat->maxPunkte );
		bestenliste->setTeamPunkte( dat->teamNummer, dat->punkte );
	}
	RundeVideoDaten *rDat = nachrichten->getRVD();
	map->setSize( rDat->mapBreite, rDat->mapH�he );
	for( int i = 0; i < spielerAnzahl; i++ )
	{
		RundeSpielerVideoDaten *dat = nachrichten->getRSVD( i );
		spieler->z( i )->neuRunde( 1, dat, 1 );
		bestenliste->updateSpielerStatus( spieler->z( i ) );
	}
	pauseZeit = 3;
	ende->setText( "Die Aufzeichnung des Spiels wird geladen.\nRunde 1 beginnt in k�rze." );
	ende->setSichtbar( 1 );
	geladen = 1;
	return 1;
}

void Aufzeichnung::doMausEreignis( MausEreignis &me )
{
	if( !geladen )
		return;
	if( kam->istMausIn( me.mx, me.my ) )
	{
		if( me.id == ME_PLinks )
		{
			for( int i = 0; i < spielerAnzahl; i++ )
			{
				if( spieler->z( i )->istMausIn( kam->getLinks() + me.mx - kam->getRX( kam->getLinks() ), kam->getOben() + me.my - kam->getRY( kam->getOben() ) ) )
				{
					kamSpielerNummer = spieler->z( i )->getSpielerNummer();
					me.verarbeitet = 1;
					break;
				}
			}
		}
		if( ( me.id == ME_RLinks || me.id == ME_RRechts ) && mx >= 0 )
		{
			mx = -1;
			my = -1;
		}
		if( me.id == ME_Bewegung && mx >= 0 )
		{
			kam->addPosition( mx - me.mx, my - me.my, map );
			mx = me.mx;
			my = me.my;
		}
		if( ( me.id == ME_PLinks || me.id == ME_PRechts ) && mx < 0 && !me.verarbeitet )
		{
			mx = me.mx;
			my = me.my;
			kamSpielerNummer = -1;
		}
		me.verarbeitet = 1;
	}
	else
	{
		mx = -1;
		my = -1;
	}
	bestenliste->doMausEreignis( me );
	steuerung->doMausEreignis( me );
}

void Aufzeichnung::doTastaturEreignis( TastaturEreignis &te )
{
	if( !geladen )
		return;
	if( te.id == TE_Press )
	{
		switch( te.taste )
		{
		case T_Links:
			kam->addPosition( -2, 0, map );
			te.verarbeitet = 1;
			break;
		case T_Oben:
			kam->addPosition( 0, -2, map );
			te.verarbeitet = 1;
			break;
		case T_Rechts:
			kam->addPosition( 2, 0, map );
			te.verarbeitet = 1;
			break;
		case T_Unten:
			kam->addPosition( 0, 2, map );
			te.verarbeitet = 1;
			break;
		}
		if( te.verarbeitet )
			kamSpielerNummer = -1;
	}
}

bool Aufzeichnung::spielTick( double spielZeit )
{
	this->spielZeit += spielZeit;
	bool setKam = kamSpielerNummer >= 0;
	int x = 0;
	int y = 0;
	bool rEnd = 0;
	for( int i = 0; i < spielerAnzahl; i++ )
	{
		VideoSpieler *tmp = spieler->z( i );
		if( tmp )
		{
			if( tmp->getSpielerNummer() == kamSpielerNummer )
			{
				x = (int)( tmp->getX() + 0.5 );
				y = (int)( tmp->getY() + 0.5 );
			}
			bool amLeben = tmp->istAmLeben();
			tmp->tick( map->zMap(), spielZeit );
			if( amLeben != tmp->istAmLeben() )
			{
				bestenliste->updateSpielerStatus( tmp );
				for( int j = 0; j < spielerAnzahl; j++ )
				{
					VideoSpieler *s = spieler->z( j );
					if( s && s != tmp && s->istAmLeben() )
						bestenliste->addPunkt( s->getTeam(), s->getSpielerNummer(), spielZeit > 0 );
				}
			}
			if( amLeben && !tmp->istAmLeben() )
			{ // gestorben
				int team = tmp->getTeam();
				bool teamLebt = 0;
				for( int k = 0; k < spielerAnzahl; k++ )
				{
					if( spieler->z( k ) && spieler->z( k )->getTeam() == team )
						teamLebt |= spieler->z( k )->istAmLeben();
				}
				if( !teamLebt )
				{
					int teamAmLebenAnzahl = 0;
					for( int k = 0; k < teamAnzahl; k++ )
					{
						if( !bestenliste->teamExistiert( k ) )
							continue;
						bool amLeben = 0;
						for( int l = 0; l < spielerAnzahl; l++ )
						{
							if( spieler->z( l ) && spieler->z( l )->getTeam() == k )
								amLeben |= spieler->z( l )->istAmLeben();
						}
						if( amLeben )
						{
							teamAmLebenAnzahl++;
							bestenliste->addPunkt( k, 1 );
						}
						else
							bestenliste->addPunkt( k, 0 );
						if( !bestenliste->getTeamPunkte( k ) )
							bestenliste->setTeamStatus( k, "tod", 0xFFFF0000 );
					}
					if( teamAmLebenAnzahl <= 1 )
						rEnd = 1;
				}
			}
			if( !amLeben && tmp->istAmLeben() )
			{ // Wiederbelebt
				int team = tmp->getTeam();
				bool teamLebt = 0;
				for( int k = 0; k < spielerAnzahl; k++ )
				{
					if( k != i && spieler->z( k ) && spieler->z( k )->getTeam() == team )
						teamLebt |= spieler->z( k )->istAmLeben();
				}
				if( !teamLebt )
				{
					for( int k = 0; k < teamAnzahl; k++ )
					{
						if( !bestenliste->teamExistiert( k ) )
							continue;
						bool amLeben = 0;
						for( int l = 0; l < spielerAnzahl; l++ )
						{
							if( l != i && spieler->z( l ) && spieler->z( l )->getTeam() == k )
								amLeben |= spieler->z( l )->istAmLeben();
						}
						if( amLeben )
							bestenliste->addPunkt( k, 0 );
						else
							bestenliste->addPunkt( k, 1 );
						if( bestenliste->getTeamPunkte( k ) )
							bestenliste->setTeamStatus( k, "lebt", 0xFF00FF00 );
					}
				}
			}
		}
	}
	if( setKam )
	{
		double z = spielZeit < 0 ? -spielZeit : spielZeit;
		double px = ( ( x - kam->getX() ) / 100.0 ) * ( 50 * z );
		double py = ( ( y - kam->getY() ) / 100.0 ) * ( 50 * z );
		kam->addPosition( (int)px, (int)py, map );
	}
	chat->tick( spielZeit );
	steuerung->tick( spielZeit );
	if( rEnd && spielZeit > 0 )
	{ // Runden Ende
		int nAnz = 0;
		int nAnz2 = 0;
		for( int i = 0; i < teamAnzahl; i++ )
		{
			if( bestenliste->teamExistiert( i ) )
			{
				nAnz += bestenliste->hatTeamGewonnen( i );
				nAnz2 += bestenliste->getTeamPunkte( i ) >= 0;
			}
		}
		if( nAnz || nAnz2 <= 1 || nachrichten->getRunde() >= 9 )
		{ // Spiel Ende
			steuerung->pause( 1 );
			return 1;
		}
		spielPause = 1;
		pauseZeit = 2;
		ende->setText( "Die n�chste Runde beginnt in k�rze." );
		ende->setSichtbar( 1 );
		int r = nachrichten->setRundenEnde( 1 );
		rSpielZeit->set( spielZeit, r - 1 );
		this->spielZeit = 0;
		time = 0;
		bestenliste->updatePunkte();
		kam->nextRunde( 1 );
		map->nextRunde( 1 );
		RundeVideoDaten *dat = nachrichten->getRVD();
		map->setSize( dat->mapBreite, dat->mapH�he );
		for( int i = 0; i < spielerAnzahl; i++ )
		{
			spieler->z( i )->neuRunde( 1, nachrichten->getRSVD( i ), bestenliste->getTeamPunkte( spieler->z( i )->getTeam() ) != 0 );
			bestenliste->updateSpielerStatus( spieler->z( i ) );
		}
		return 1;
	}
	return 0;
}

bool Aufzeichnung::tick( double tickVal )
{
	if( !geladen )
		return 0;
	if( spielPause )
	{
		if( pauseZeit >= 0 )
		{
			pauseZeit -= tickVal;
			if( pauseZeit < 0 )
			{
				pauseZeit = 0;
				spielPause = 0;
				ende->setSichtbar( 0 );
			}
		}
		chat->tick( 0 );
		steuerung->tick( 0 );
		return 1;
	}
	if( ( steuerung->istVorw�rts() || nMsg && nMsgVorw�rts ) && !( nMsg && !nMsgVorw�rts ) )
	{
		if( steuerung->istZeitlupe() )
			time += tickVal / steuerung->getSpeed();
		else
			time += tickVal * steuerung->getSpeed();
		while( steuerung->getSpeed() != 0 )
		{
			while( !nMsg || nMsg->typ && steuerung->getSpeed() != 0 )
			{
				if( !nMsg )
					nMsg = nachrichten->GetNextNachricht();
				if( !nMsg )
					break;
				nMsgVorw�rts = 1;
				if( !nMsg->typ )
					break;
				VideoAktionMSG *ak = (VideoAktionMSG*)nMsg;
				switch( ak->aktion )
				{
				case 0: // T_Links Press
					for( int i = 0; i < spielerAnzahl; i++ )
					{
						if( spieler->z( i )->getSpielerNummer() == ak->spielerNummer )
						{
							spieler->z( i )->setLinksKurve( 1 );
							break;
						}
					}
					break;
				case 1: // T_Links Release
					for( int i = 0; i < spielerAnzahl; i++ )
					{
						if( spieler->z( i )->getSpielerNummer() == ak->spielerNummer )
						{
							spieler->z( i )->setLinksKurve( 0 );
							break;
						}
					}
					break;
				case 2: // T_Rechts Press
					for( int i = 0; i < spielerAnzahl; i++ )
					{
						if( spieler->z( i )->getSpielerNummer() == ak->spielerNummer )
						{
							spieler->z( i )->setRechtsKurve( 1 );
							break;
						}
					}
					break;
				case 3: // T_Rechts Release
					for( int i = 0; i < spielerAnzahl; i++ )
					{
						if( spieler->z( i )->getSpielerNummer() == ak->spielerNummer )
						{
							spieler->z( i )->setRechtsKurve( 0 );
							break;
						}
					}
					break;
				case 4: // Chat Nachricht
					if( 1 )
					{
						VideoChatMSG *msg = (VideoChatMSG*)ak;
						for( int i = 0; i < spielerAnzahl; i++ )
						{
							if( spieler->z( i )->getSpielerNummer() == ak->spielerNummer )
							{
								Text txt = spieler->z( i )->zName()->getText();
								txt += ": ";
								txt += msg->msg.getText();
								chat->addNachricht( txt );
								break;
							}
						}
					}
					break;
				case 5: // Linien Unterbrechung
					if( 1 )
					{
						VideoLinieMSG *lMsg = (VideoLinieMSG*)ak;
						for( int i = 0; i < spielerAnzahl; i++ )
						{
							if( spieler->z( i )->getSpielerNummer() == ak->spielerNummer )
							{
								spieler->z( i )->setLinienUnterbrechung( lMsg->unterbrechung != 0 );
								break;
							}
						}
					}
					break;
				}
				nMsg = 0;
			}
			if( !nMsg )
				break;
			if( time > spielZeit + TICK )
			{
				bool end = spielTick( TICK );
				nMsg = 0;
				if( !steuerung->istVorw�rts() || end )
					break;
			}
			else
				break;
		}
	}
	else
	{
		if( steuerung->istZeitlupe() )
			time -= tickVal / steuerung->getSpeed();
		else
			time -= tickVal * steuerung->getSpeed();
		while( 1 )
		{
			while( !nMsg || nMsg->typ )
			{
				if( !nMsg )
				{
					nMsg = nachrichten->GetLastNachricht();
					nMsgVorw�rts = 0;
					if( !nMsg )
					{
						int r = nachrichten->setRundenEnde( 0 );
						if( r < 0 )
						{ // Spiel Beginn
							steuerung->pause( 0 );
							return 1;
						}
						bestenliste->updatePunkte( 0 );
						kam->nextRunde( 0 );
						map->nextRunde( 0 );
						for( int i = 0; i < spielerAnzahl; i++ )
							spieler->z( i )->neuRunde( 0, 0, 1 );
						spielPause = 1;
						pauseZeit = 2;
						ende->setText( "Vorherige Runde beginnt in k�rze." );
						ende->setSichtbar( 1 );
						spielZeit = rSpielZeit->get( r );
						time = spielZeit;
						return 1;
					}
				}
				if( !nMsg->typ )
					break;
				VideoAktionMSG *ak = (VideoAktionMSG*)nMsg;
				switch( ak->aktion )
				{
				case 0: // T_Links Press
					for( int i = 0; i < spielerAnzahl; i++ )
					{
						if( spieler->z( i )->getSpielerNummer() == ak->spielerNummer )
						{
							spieler->z( i )->setLinksKurve( 0 );
							break;
						}
					}
					break;
				case 1: // T_Links Release
					for( int i = 0; i < spielerAnzahl; i++ )
					{
						if( spieler->z( i )->getSpielerNummer() == ak->spielerNummer )
						{
							spieler->z( i )->setLinksKurve( 1 );
							break;
						}
					}
					break;
				case 2: // T_Rechts Press
					for( int i = 0; i < spielerAnzahl; i++ )
					{
						if( spieler->z( i )->getSpielerNummer() == ak->spielerNummer )
						{
							spieler->z( i )->setRechtsKurve( 0 );
							break;
						}
					}
					break;
				case 3: // T_Rechts Release
					for( int i = 0; i < spielerAnzahl; i++ )
					{
						if( spieler->z( i )->getSpielerNummer() == ak->spielerNummer )
						{
							spieler->z( i )->setRechtsKurve( 1 );
							break;
						}
					}
					break;
				case 4: // Chat Nachricht
					if( 1 )
					{
						VideoChatMSG *msg = (VideoChatMSG*)ak;
						for( int i = 0; i < spielerAnzahl; i++ )
						{
							if( spieler->z( i )->getSpielerNummer() == ak->spielerNummer )
							{
								Text txt = spieler->z( i )->zName()->getText();
								txt += ": ";
								txt += msg->msg.getText();
								chat->removeNachricht( txt );
								break;
							}
						}
					}
					break;
				case 5: // Linien Unterbrechung
					if( 1 )
					{
						VideoLinieMSG *lMsg = (VideoLinieMSG*)ak;
						if( 1 )
						{
							for( int i = 0; i < spielerAnzahl; i++ )
							{
								if( spieler->z( i )->getSpielerNummer() == ak->spielerNummer )
								{
									spieler->z( i )->setLinienUnterbrechung( lMsg->unterbrechung == 0 );
									break;
								}
							}
						}
					}
					break;
				}
				nMsg = 0;
			}
			if( time <= spielZeit - TICK )
			{
				spielTick( -TICK );
				nMsg = 0;
				if( steuerung->istVorw�rts() )
					break;
			}
			else
				break;
		}
	}
	return 1;
}

void Aufzeichnung::render( Bild &zRObj )
{
	if( !geladen )
		return;
	bestenliste->render( zRObj );
	chat->render( zRObj );
	steuerung->render( zRObj );
	kam->render( zRObj );
	int x = kam->getRX( kam->getLinks() ) + 1, y = kam->getRY( kam->getOben() ) + 1;
	if( zRObj.setDrawOptions( x, y, kam->getRechts() - kam->getLinks() - 2, kam->getUnten() - kam->getOben() - 2 ) )
	{
		zRObj.addScrollOffset( x, y );
		map->render( kam, zRObj );
		for( int i = 0; i < spielerAnzahl; i++ )
			spieler->z( i )->render( kam, zRObj );
		zRObj.releaseDrawOptions();
	}
	if( ende )
		ende->render( zRObj );
}

// constant
bool Aufzeichnung::hatVerlassen( bool jetzt ) const
{
	if( !geladen )
		return 0;
	return steuerung->istBeendet( jetzt );
}

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

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