#include "Statistik.h"
#include <DateiSystem.h>
#include <Datei.h>
#ifndef WIN32
#include <unistd.h>
#define Sleep( x )    usleep( (x) * 1000 )
#endif

// Inhalt der Statistik Klasse aus Statistik.h
// Konstruktor
Statistik::Statistik()
{
	spielId = 0;
	karteId = 0;
	db = 0;
	spielerAnzahl = 0;
	spieler = new RCArray< Spieler >();
	erstellt = 0;
	sOnline = new Array< bool >();
	sBereit = new Array< bool >();
	gss = new RCArray< GesamtSpielerStatistik >();
	gts = new RCArray< GesamtTeamStatistik >();
	rrs = new RCArray< RundenRundenStatistik >();
	teamNamen = 0;
	gewinnerTeam = new Array< int >();
	rundenDauer = new Array< int >();
	rundenBild = new RCArray< Bild >();
	ref = 1;
}

// Destruktor
Statistik::~Statistik()
{
	if( db )
		db->release();
	spieler->release();
	sOnline->release();
	sBereit->release();
	gss->release();
	gts->release();
	rrs->release();
	if( teamNamen )
		teamNamen->release();
	gewinnerTeam->release();
	rundenDauer->release();
	rundenBild->release();
}

// privat
void Statistik::sendeStatistik( int index )
{ // Sendet Statistik an Spieler index
	if( !sOnline->hat( index ) || !sOnline->get( index ) )
		return;
	Klient *zk = spieler->z( index )->zKlient();
	if( !zk )
		return;
	int anz = gss->getEintragAnzahl();
	for( int i = 0; i < anz; i++ )
		zk->sendeGesamtSpielerStatistik( gss->z( i ) );
	anz = gts->getEintragAnzahl();
	for( int i = 0; i < anz; i++ )
		zk->sendeGesamtTeamStatistik( gts->z( i ) );
	anz = rrs->getEintragAnzahl();
	for( int i = 0; i < anz; i++ )
		zk->sendeRundeStatistik( rrs->z( i ) );
	zk->sendeStatistikLadenFertig();
	for( int i = 0; i < spielerAnzahl; i++ )
	{
		if( !sOnline->hat( i ) || !sOnline->get( i ) )
			zk->sendeStatistikSpielerOffline( spieler->z( i )->getAccountId() );
	}
}

// nicht constant
void Statistik::setSpielId( int id )
{
	spielId = id;
}

void Statistik::setKarteId( int id )
{
	karteId = id;
}

void Statistik::setPSQLDB( SSDatenbankV *db )
{
	if( this->db )
		this->db->release();
	this->db = db;
}

void Statistik::setTeamNamen( RCArray< Text > *namen )
{
	if( teamNamen )
		teamNamen->release();
	teamNamen = namen;
}

void Statistik::rundenEnde( int team, int dauer, Bild *b )
{
	gewinnerTeam->add( team );
	rundenDauer->add( dauer );
	Bild *rb = new Bild();
	rb->neuBild( b->getBreite(), b->getHeight(), 0 );
	rb->drawBild( 0, 0, rb->getBreite(), rb->getHeight(), *b );
	rundenBild->add( rb );
	b->release();
}

void Statistik::setSpieler( int anzahl, RCArray< Spieler > *zSpieler )
{
	spielerAnzahl = anzahl;
	for( int i = 0; i < anzahl; i++ )
	{
		spieler->set( zSpieler->get( i ), i );
		sOnline->set( 0, i );
		sBereit->set( 0, i );
	}
}

void Statistik::klientOffline( int accountId )
{
	for( int i = 0; i < spielerAnzahl; i++ )
	{
		if( spieler->z( i )->getAccountId() == accountId )
		{
			sOnline->set( 0, i );
			sBereit->set( 0, i );
		}
		else if( sOnline->hat( i ) && sOnline->get( i ) && spieler->z( i )->zKlient() )
			spieler->z( i )->zKlient()->sendeStatistikSpielerOffline( accountId );
	}
}

void Statistik::statistikAnfrage( int accountId, short len, char *bytes )
{
	len--;
	switch( *bytes )
	{
	case 1: // Spieler ist Bereit
		for( int i = 0; i < spielerAnzahl; i++ )
		{
			if( !erstellt )
			{
				if( spieler->z( i )->getAccountId() == accountId )
					sBereit->set( 1, i );
			}
			else if( spieler->z( i )->getAccountId() == accountId )
			{
				sendeStatistik( i );
				break;
			}
		}
		break;
	case 2: // Chat Nachricht
		bytes++;
		char *txt = new char[ len + 1 ];
		txt[ len ] = 0;
		for( int i = 0; i < len; i++ )
			txt[ i ] = bytes[ i ];
		for( int i = 0; i < spielerAnzahl; i++ )
		{
			if( sOnline->hat( i ) && sOnline->get( i ) && spieler->z( i )->zKlient() )
				spieler->z( i )->zKlient()->sendeStatistikChatNachricht( accountId, txt );
		}
		delete[] txt;
		break;
	}
}

void Statistik::run()
{
	for( int i = 0; i < spielerAnzahl; i++ )
		sOnline->set( spieler->z( i )->istOnline(), i );
	// Statistik erstellen
	// gesammt Spieler
	for( int i = 0; i < spielerAnzahl; i++ )
	{
		if( spieler->z( i ) )
		{
			Spieler *tmp = spieler->z( i );
			InitDatei *d = new InitDatei();
			Text w;
			w = tmp->getSpielerNummer();
			if( w.getLength() )
				d->addWert( "SpielerNummer", w.getText() );
			Text *sn = db->getAccountRufName( tmp->getAccountId() );
			if( sn && sn->getLength() )
				d->addWert( "SpielerName", sn->getText() );
			if( sn )
				sn->release();
			if( teamNamen && teamNamen->z( tmp->getSpielerTeam() ) )
				d->addWert( "TeamName", teamNamen->z( tmp->getSpielerTeam() )->getText() );
			w = tmp->getSpielerFarbe();
			if( w.getLength() )
				d->addWert( "SpielerFarbe", w.getText() );
			w = tmp->getTeamFarbe();
			if( w.getLength() )
				d->addWert( "TeamFarbe", w.getText() );
			w = tmp->getRundenGewonnen();
			if( w.getLength() )
				d->addWert( "GewonneneRunden", w.getText() );
			w = tmp->getPunkte();
			if( w.getLength() )
				d->addWert( "Punkte", w.getText() );
			w = tmp->getLinienLength();
			if( w.getLength() )
				d->addWert( "LinienLänge", w.getText() );
			w = tmp->getZeitAmLeben();
			if( w.getLength() )
				d->addWert( "ZeitAmLeben", w.getText() );
			w = tmp->getZeitTod();
			if( w.getLength() )
				d->addWert( "ZeitTod", w.getText() );
			w = tmp->getKills();
			if( w.getLength() )
				d->addWert( "Kills", w.getText() );
			w = tmp->getTode();
			if( w.getLength() )
				d->addWert( "Tode", w.getText() );
			GesamtSpielerStatistik *gss = new GesamtSpielerStatistik();
			gss->initValues( d );
			this->gss->add( gss );
		}
	}
	// Gesamt Team
	for( int i = 0; i < spielerAnzahl; i++ )
	{
		Spieler *tmp = spieler->z( i );
		if( tmp )
		{
			int anz = gts->getEintragAnzahl();
			bool gefunden = 0;
			for( int j = 0; j < anz; j++ )
			{
				if( gts->z( j ) && gts->z( j )->getTeamNummer() == tmp->getSpielerTeam() )
				{
					gefunden = 1;
					break;
				}
			}
			if( gefunden )
				continue;
			InitDatei *d = new InitDatei();
			Text w;
			w = tmp->getSpielerTeam();
			if( w.getLength() )
				d->addWert( "TeamNummer", w.getText() );
			if( teamNamen && teamNamen->z( tmp->getSpielerTeam() ) )
				d->addWert( "TeamName", teamNamen->z( tmp->getSpielerTeam() )->getText() );
			w = tmp->getTeamFarbe();
			if( w.getLength() )
				d->addWert( "TeamFarbe", w.getText() );
			int rundenGewonnen = 0;
			anz = gewinnerTeam->getEintragAnzahl();
			for( int j = 0; j < anz; j++ )
			{
				if( gewinnerTeam->hat( j ) && gewinnerTeam->get( j ) == tmp->getSpielerTeam() )
					rundenGewonnen++;
			}
			w = rundenGewonnen;
			if( w.getLength() )
				d->addWert( "GewonneneRunden", w.getText() );
			int punkte = 0;
			int linienLength = 0;
			int kills = 0;
			int tode = 0;
			for( int j = 0; j < spielerAnzahl; j++ )
			{
				Spieler *s = spieler->z( j );
				if( s && s->getSpielerTeam() == tmp->getSpielerTeam() )
				{
					punkte += s->getPunkte();
					linienLength += s->getLinienLength();
					kills += s->getKills();
					tode += s->getTode();
				}
			}
			w = punkte;
			if( w.getLength() )
				d->addWert( "Punkte", w.getText() );
			w = linienLength;
			if( w.getLength() )
				d->addWert( "LinienLänge", w.getText() );
			w = kills;
			if( w.getLength() )
				d->addWert( "Kills", w.getText() );
			w = tode;
			if( w.getLength() )
				d->addWert( "Tode", w.getText() );
			GesamtTeamStatistik *gts = new GesamtTeamStatistik();
			gts->initValues( d );
			this->gts->add( gts );
		}
	}
	// Rundenweise
	int rAnz = gewinnerTeam->getEintragAnzahl();
	for( int i = 0; i < rAnz; i++ )
	{
		InitDatei *d = new InitDatei();
		Text w;
		w = i;
		if( w.getLength() )
			d->addWert( "RundenNummer", w.getText() );
		w = rundenDauer->hat( i ) ? rundenDauer->get( i ) : -1;
		if( w.getLength() )
			d->addWert( "RundenDauer", w.getText() );
		w = gewinnerTeam->hat( i ) ? gewinnerTeam->get( i ) : -1;
		if( w.getLength() )
			d->addWert( "SiegerTeam", w.getText() );
		int spielFeldNutzung = 0;
		Bild *rb = rundenBild->get( i );
		int *rbBuff = rb->getBuffer();
		for( int j = 0; j < rb->getBreite() * rb->getHeight(); j++ )
		{
			if( rbBuff[ j ] )
				spielFeldNutzung++;
		}
		w = (int)( ( spielFeldNutzung / ( (double)( rb->getBreite() * rb->getHeight() ) / 25 ) ) * 100 );
		if( w.getLength() )
			d->addWert( "SpielFeldNutzung", w.getText() );
		RundenRundenStatistik *rrs = new RundenRundenStatistik();
		rrs->initValues( d );
		rrs->setBild( rb );
		// Runde Spieler
		for( int j = 0; j < spielerAnzahl; j++ )
		{
			Spieler *tmp = spieler->z( j );
			if( tmp )
			{
				InitDatei *d = new InitDatei();
				Text w;
				w = tmp->getSpielerNummer();
				if( w.getLength() )
					d->addWert( "SpielerNummer", w.getText() );
				Text *sn = db->getAccountRufName( tmp->getAccountId() );
				if( sn && sn->getLength() )
					d->addWert( "SpielerName", sn->getText() );
				if( sn )
					sn->release();
				if( teamNamen && teamNamen->z( tmp->getSpielerTeam() ) )
					d->addWert( "TeamName", teamNamen->z( tmp->getSpielerTeam() )->getText() );
				w = tmp->getSpielerFarbe();
				if( w.getLength() )
					d->addWert( "SpielerFarbe", w.getText() );
				w = tmp->getTeamFarbe();
				if( w.getLength() )
					d->addWert( "TeamFarbe", w.getText() );
				w = tmp->getLinienLength( i );
				if( w.getLength() )
					d->addWert( "LinienLänge", w.getText() );
				w = tmp->getKills( i );
				if( w.getLength() )
					d->addWert( "Kills", w.getText() );
				w = tmp->getTodesZeit( i );
				if( w.getLength() )
					d->addWert( "Todeszeit", w.getText() );
				RundenSpielerStatistik *rss = new RundenSpielerStatistik();
				rss->initValues( d );
				rrs->addSpielerStatistik( rss );
			}
		}
		// Runde Team
		for( int j = 0; j < spielerAnzahl; j++ )
		{
			Spieler *tmp = spieler->z( j );
			if( tmp )
			{
				int anz = gts->getEintragAnzahl();
				bool gefunden = 0;
				for( int k = 0; k < anz; k++ )
				{
					if( rrs->zTeamStatistik( k ) && rrs->zTeamStatistik( k )->getTeamNummer() == tmp->getSpielerTeam() )
					{
						gefunden = 1;
						break;
					}
				}
				if( gefunden )
					continue;
				InitDatei *d = new InitDatei();
				Text w;
				w = tmp->getSpielerTeam();
				if( w.getLength() )
					d->addWert( "TeamNummer", w.getText() );
				if( teamNamen && teamNamen->z( tmp->getSpielerTeam() ) )
					d->addWert( "TeamName", teamNamen->z( tmp->getSpielerTeam() )->getText() );
				w = tmp->getTeamFarbe();
				if( w.getLength() )
					d->addWert( "TeamFarbe", w.getText() );
				w = (int)( ( gewinnerTeam->hat( i ) ? gewinnerTeam->get( i ) : 0 ) == tmp->getSpielerTeam() );
				if( w.getLength() )
					d->addWert( "Ergebnis", w.getText() );
				int linienLength = 0;
				int kills = 0;
				int tode = 0;
				for( int k = 0; k < spielerAnzahl; k++ )
				{
					Spieler *s = spieler->z( k );
					if( s && s->getSpielerTeam() == tmp->getSpielerTeam() )
					{
						linienLength += s->getLinienLength( i );
						kills += s->getKills( i );
						tode += ( s->getTodesZeit( i ) != 0 );
					}
				}
				w = linienLength;
				if( w.getLength() )
					d->addWert( "LinienLänge", w.getText() );
				w = kills;
				if( w.getLength() )
					d->addWert( "Kills", w.getText() );
				w = tode;
				if( w.getLength() )
					d->addWert( "Tode", w.getText() );
				RundenTeamStatistik *rts = new RundenTeamStatistik();
				rts->initValues( d );
				rrs->addTeamStatistik( rts );
			}
		}
		this->rrs->add( rrs );
	}
	erstellt = 1;
	// Statistik senden
	for( int i = 0; i < spielerAnzahl; i++ )
	{
		if( sBereit->hat( i ) && sBereit->get( i ) )
			sendeStatistik( i );
	}
	// Statistik speichern
	Text *pfad = new Text( "../spiel log/" );
	pfad->append( spielId );
	pfad->append( "/fertig" );
	DateiPfadErstellen( pfad );
	// warten bis alle verlassen haben
	while( 1 )
	{
		Sleep( 1000 );
		int online = 0;
		for( int i = 0; i < spielerAnzahl; i++ )
			online += sOnline->hat( i ) && sOnline->get( i );
		if( !online )
			break;
	}
}

// constant

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

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