#include "Spiel.h"
#include <time.h>
#include <DateiSystem.h>
#include "Define.h"
#include "SSKlient.h"
#include "KartenLeser.h"
#include "Statistik.h"
#include "Team.h"
#include "Laser.h"
#include <M2Datei.h>
#include <iostream>
#ifdef WIN32
#include <random>
#else
#include <math.h>
#include <unistd.h>
#include <stdlib.h>
#define Sleep( x )    usleep( (x) * 1000 )
#endif

// Inhalt der Spiel Klasse aus Spiel.h
// Konstruktor
Spiel::Spiel()
{
    zAccounts = 0;
    zKlients = 0;
    asteroids = new RCArray< Asteroid >();
    asteroidModels = new RCArray< Model2DData >();
    stat = new Statistik();
    teams = new RCArray< Team >();
    teamAnzahl = 0;
    spieler = new RCArray< Spieler >();
    shots = new RCArray< Laser >();
    objekte = new RCArray< SpielObjekt >();
    welt = new Welt2D();
    pixel = new RCArray< Pixel >();
    welt->setCircular( 1 );
    welt->setAirResistance( 0.001f );
    psqldb = 0;
    spielId = 0;
    karteId = 0;
    spielerAnzahl = 0;
    karte = 0;
    InitializeCriticalSection( &cs );
    sts = 0;
    log = 0;
    isRunning = 0;
    spielZeit = 0;
    ende = 1;
    nextSchussId = 1;
    nextAsteroid = 30;
    asteroidId = 0;
    pixelId = 0;
    ref = 1;
}

// Destruktor
Spiel::~Spiel()
{
    teams->release();
    stat->release();
    spieler->release();
    for( auto o = objekte->getIterator(); o; o++ )
        o->setTeam( 0 );
    objekte->release();
    welt->release();
    asteroids->release();
    asteroidModels->release();
    if( psqldb )
        psqldb->release();
    if( karte )
        karte->release();
    if( sts )
        sts->release();
    pixel->release();
    DeleteCriticalSection( &cs );
}

// privat
int Spiel::getTeamVonSpieler( int sNum )
{
    for( int i = 0; i < spielerAnzahl; i++ )
    {
        Spieler *tmp = spieler->z( i );
        if( tmp && tmp->getSpielerNummer() == sNum )
            return tmp->zTeam() ? tmp->zTeam()->id : 0;
    }
    return 0;
}

// nicht constant
void Spiel::setPSQLK( SSDatenbankV * psqldb )
{
    if( this->psqldb )
        this->psqldb->release();
    this->psqldb = psqldb;
    stat->setPSQLDB( psqldb->getThis() );
}

void Spiel::setSpielId( int id )
{
    spielId = id;
    stat->setSpielId( id );
}

void Spiel::setKarteId( int karteId )
{
    this->karteId = karteId;
    stat->setKarteId( karteId );
}

void Spiel::setTempPfad( char *pfad )
{
    mapPfad = pfad;
    mapPfad += "/";
}

void Spiel::setAccounts( int anzahl, Array< int > * zAccounts )
{
    this->zAccounts = zAccounts->getThis();
    spielerAnzahl = anzahl;
}

void Spiel::setKlients( int anzahl, RCArray< SSKlientV > * zKlients )
{
    this->zKlients = zKlients->getThis();
}

void Spiel::setSpielerNummern( int anzahl, Array< int > * spielerNummern )
{
    if( !sts )
    {
        sts = new SpielerTeamStruktur();
        KartenLeser *reader = new KartenLeser( karteId, psqldb->getThis(), mapPfad );
        reader->ladeSpielerTeamStruktur( sts );
        if( karte )
            karte->release();
        karte = reader->ladeKarte( sts );
        reader->release();
        for( int i = 0; i < sts->teamAnzahl; i++ )
            teams->set( karte->createTeam( i ), i );
        stat->setTeamNamen( sts->teamName->getThis() );
        for( auto o = karte->getObjekte(); o; o++ )
        {
            SpielObjekt *obj = karte->createObjekt( o->id );
            obj->setTeam( teams->get( o->team - 1 ) );
            welt->addObject( obj->getThis() );
            objekte->add( obj );
        }
        welt->setSize( karte->getSize().x, karte->getSize().y );
        welt->setSize( 1 );
    }
    for( int i = 0; i < anzahl; i++ )
    {
        Spieler *tmp = karte->createSpieler( spielerNummern->get( i ) );
        if( tmp )
        {
            int team = 0;
            int von = 0;
            int bis = 0;
            for( int j = 0; j < sts->teamAnzahl; j++ )
            {
                bis = von + ( sts->teamSize->hat( j ) ? sts->teamSize->get( j ) : 0 );
                if( spielerNummern->get( i ) >= von && spielerNummern->get( i ) < bis )
                {
                    team = j;
                    break;
                }
                von = bis;
            }
            tmp->setTeam( teams->get( team ) );
            teams->z( team )->spieler->add( tmp );
        }
        welt->addObject( tmp->getThis() );
        spieler->set( tmp, i );
    }
    for( int i = 0; i < anzahl; i++ )
        spieler->z( i )->setAccountId( zAccounts->hat( i ) ? zAccounts->get( i ) : 0 );
    for( int i = 0; i < anzahl; i++ )
        spieler->z( i )->setKlient( new Klient( zKlients->get( i ) ) );
    stat->setSpieler( spielerAnzahl, spieler );
    zAccounts = zAccounts->release();
    zKlients = zKlients->release();
    teamAnzahl = 0;
    for( int i = 0; i < sts->teamAnzahl; i++ )
        if( teams->z( i )->spieler->getEintragAnzahl() )
            teamAnzahl++;
}

void Spiel::klientOffline( int accountId )
{
    for( int i = 0; i < spielerAnzahl; i++ )
    {
        if( spieler->z( i )->getAccountId() == accountId )
            spieler->z( i )->offline();
    }
}

void Spiel::klientOnline( int accountId, SSKlientV * zKlient )
{
    for( int i = 0; i < spielerAnzahl; i++ )
    {
        if( spieler->z( i )->getAccountId() == accountId )
        {
            EnterCriticalSection( &cs );
            Spieler *s = spieler->z( i );
            s->online( zKlient );
            Klient *tmp = spieler->z( i )->zKlient();
            tmp->sendeSpielerNummer( s->getSpielerNummer(), 0 );
            //--------------------------
            LeaveCriticalSection( &cs );
        }
    }
}

void Spiel::nachricht( int accountId, int len, char *bytes )
{
    if( !isRunning || ende )
        return;
    EnterCriticalSection( &cs );
    if( ende )
    {
        LeaveCriticalSection( &cs );
        return;
    }
    char *msgBeg = bytes;
    int msgLen = len;
    int msgAccount = accountId;
    bool saveMSG = 1;
    len--;
    switch( *bytes )
    {
    case 0:
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
    case 6:
    case 7:
        for( int i = 0; i < spielerAnzahl; i++ )
        {
            Spieler *tmp = spieler->z( i );
            if( tmp && tmp->getAccountId() == accountId )
            {
                if( !tmp->istAmLeben() )
                    break;
                if( !tmp->setTastataturStatus( (TastaturStatus)( (int)( *bytes ) / 2 ), ( (int)( *bytes ) % 2 ) == 0 ) )
                {
                    saveMSG = 0;
                    break;
                }
                if( *bytes != 6 && *bytes != 7 )
                {
                    for( int j = 0; j < spielerAnzahl; j++ )
                    {
                        Spieler *s = spieler->z( j );
                        if( s && s->zKlient() )
                            s->zKlient()->sendeTastaturStatus( tmp->getSpielerNummer(), (TastaturStatus)( (int)( *bytes ) / 2 ), ( (int)( *bytes ) % 2 ) == 0, spielZeit );
                    }
                }
                break;
            }
        }
        break;
    case 8: // chat Nachricht
        if( 1 )
        {
            bytes++;
            Text *txt = psqldb->getAccountRufName( accountId );
            txt->append( ": " );
            txt->append( bytes, len );
            for( int i = 0; i < spielerAnzahl; i++ )
            {
                Spieler *tmp = spieler->z( i );
                if( tmp && tmp->zKlient() )
                    tmp->zKlient()->sendeChatNachricht( txt->getText(), spielZeit );
            }
            txt->release();
            len = 0;
        }
        break;
    case 9: // Skill verwendung
    {
        bytes++;
        char art = *bytes;
        len--;
        for( int i = 0; i < spielerAnzahl; i++ )
        {
            Spieler *tmp = spieler->z( i );
            if( tmp && tmp->getAccountId() == accountId )
            {
                if( !tmp->istAmLeben() )
                    break;
                if( !tmp->setSkill( art ) )
                {
                    saveMSG = 0;
                    break;
                }
                for( int j = 0; j < spielerAnzahl; j++ )
                {
                    Spieler *s = spieler->z( j );
                    if( s && s->zKlient() )
                        s->zKlient()->sendeSkillNachricht( tmp->getSpielerNummer(), art, spielZeit );
                }
                break;
            }
        }
        break;
    }
    case 0xA: // Use active skill
    {
        bytes++;
        char id = *bytes;
        len--;
        for( int i = 0; i < spielerAnzahl; i++ )
        {
            Spieler *tmp = spieler->z( i );
            if( tmp && tmp->getAccountId() == accountId )
            {
                if( !tmp->istAmLeben() )
                    break;
                tmp->useSkill( id );
                for( int j = 0; j < spielerAnzahl; j++ )
                {
                    Spieler *s = spieler->z( j );
                    if( s && s->zKlient() )
                        s->zKlient()->sendeUseSkillNachricht( tmp->getSpielerNummer(), id, spielZeit );
                }
                break;
            }
        }
        break;
    }
    default:
        saveMSG = 0;
    }
    if( len )
    {
        // error
    }
    if( log && log->istOffen() && saveMSG )
    {
        char c = 1;
        log->schreibe( &c, 1 );
        int spielerNum = 0;
        for( int i = 0; i < spielerAnzahl; i++ )
        {
            Spieler *tmp = spieler->z( i );
            if( tmp && tmp->getAccountId() == msgAccount )
            {
                spielerNum = tmp->getSpielerNummer();
                break;
            }
        }
        log->schreibe( (char *)& spielerNum, 4 );
        short l = (short)msgLen;
        log->schreibe( (char *)& l, 2 );
        log->schreibe( msgBeg, l );
    }
    LeaveCriticalSection( &cs );
}

void Spiel::tick( double zeit )
{
    // Objekte updaten
    welt->tick( zeit );
    // Spieler Updaten
    for( int i = 0; i < spielerAnzahl; i++ )
    {
        Spieler *tmp = spieler->z( i );
        if( tmp )
        {
            if( tmp->doNeedWiederbelebung() )
            { // Wiederbelebung
                tmp->wiederbeleben();
                for( int j = 0; j < spielerAnzahl; j++ )
                {
                    Spieler *s = spieler->z( j );
                    if( s )
                        s->zKlient()->sendeWiederbelebung( tmp->getSpielerNummer(), spielZeit );
                }
            }
        }
    }
    // Schüsse Collision
    int anz = shots->getEintragAnzahl();
    for( int i = 0; i < anz; i++ )
    {
        Laser *tmp = shots->z( i );
        if( tmp )
        {
            if( tmp->getIntensity() <= 0 )
            { // Schuss existiert nicht mehr
                for( int j = 0; j < spielerAnzahl; j++ )
                {
                    Spieler *s = spieler->z( j );
                    if( s )
                        s->zKlient()->sendeTreffer( tmp->getId(), -1, spielZeit, 0, 0 );
                }
                welt->removeObject( tmp );
                shots->remove( i );
                anz--;
                i--;
            }
            else
            { // Schuss existiert noch
                int team = getTeamVonSpieler( tmp->getSpieler() );
                for( int j = 0; j < spielerAnzahl; j++ )
                {
                    Spieler *attacked = spieler->z( j );
                    if( attacked && attacked->zTeam() && attacked->zTeam()->id != team && attacked->istTreffer( tmp->getPosition() ) )
                    { // Treffer
                        Spieler *attacker = 0;
                        for( int k = 0; k < spielerAnzahl; k++ )
                        {
                            Spieler *tmpS = spieler->z( k );
                            if( tmpS && tmpS->getSpielerNummer() == tmp->getSpieler() )
                                attacker = tmpS;
                        }
                        double intens = tmp->getIntensity() * ( ( tmp->getSpeed() - attacked->getSpeed() ).getLength() / 200 );
                        bool kill = attacked->nimmSchaden( intens, attacker ? attacker->getLevel() : 1 );
                        if( tmp->getSpeed().getLengthSq() > 0 )
                            attacked->impuls( tmp->getPosition() - tmp->getSpeed(), tmp->getSpeed() * 0.3f );
                        int skillP = attacker->getSkillP();
                        attacker->machSchaden( intens, attacked->getLevel() );
                        float erf = attacker->getEp();
                        if( kill )
                            attacker->addKill( attacked->getLevel() );
                        for( int k = 0; k < spielerAnzahl; k++ )
                        {
                            Spieler *sp = spieler->z( k );
                            if( sp )
                                sp->zKlient()->sendeTreffer( tmp->getId(), attacked->getSpielerNummer(), spielZeit, erf, skillP );
                            if( kill && sp )
                                sp->zKlient()->sendeTod( attacked->getSpielerNummer(), tmp->getSpieler(), spielZeit );
                        }
                        if( kill )
                        {
                            if( teams->z( team - 1 ) )
                                teams->z( team - 1 )->punkte++;
                            if( teams->z( team - 1 )->punkte == teams->z( team - 1 )->maxPunkte )
                                ende = 1;
                        }
                        welt->removeObject( tmp );
                        shots->remove( i );
                        anz--;
                        i--;
                        break;
                    }
                }
                int objektAnzahl = objekte->getEintragAnzahl();
                for( int j = 0; j < objektAnzahl; j++ )
                {
                    SpielObjekt *attacked = objekte->z( j );
                    if( attacked && ( !attacked->zTeam() || attacked->zTeam()->id != team ) && attacked->doesCollideWithLaser() && attacked->istTreffer( tmp->getPosition() ) )
                    { // Treffer
                        Spieler *attacker = 0;
                        for( int k = 0; k < spielerAnzahl; k++ )
                        {
                            Spieler *tmpS = spieler->z( k );
                            if( tmpS && tmpS->getSpielerNummer() == tmp->getSpieler() )
                                attacker = tmpS;
                        }
                        double intens = tmp->getIntensity() * ( ( tmp->getSpeed() - attacked->getSpeed() ).getLength() / 200 );
                        bool kill = attacked->nimmSchaden( intens, attacker ? attacker->getLevel() : 1 );
                        if( tmp->getSpeed().getLengthSq() > 0 )
                            attacked->impuls( tmp->getPosition() - tmp->getSpeed(), tmp->getSpeed() * 0.3f );
                        int skillP = attacker->getSkillP();
                        attacker->machSchaden( intens, attacked->getLevel(), attacked->doesShotAddEp() );
                        float erf = attacker->getEp();
                        if( kill )
                            attacker->addKill( attacked->getLevel(), attacked->doesShotAddEp() );
                        for( int k = 0; k < spielerAnzahl; k++ )
                        {
                            Spieler *sp = spieler->z( k );
                            if( sp )
                                sp->zKlient()->sendeObjektTreffer( tmp->getId(), attacked->getObjektId(), spielZeit, erf, skillP );
                            if( kill && sp )
                                sp->zKlient()->sendeObjektTod( attacked->getObjektId(), tmp->getSpieler(), spielZeit );
                        }
                        if( kill )
                        {
                            if( teams->z( team - 1 ) )
                                teams->z( team - 1 )->punkte++;
                            if( teams->z( team - 1 )->punkte == teams->z( team - 1 )->maxPunkte )
                                ende = 1;
                        }
                        welt->removeObject( tmp );
                        shots->remove( i );
                        anz--;
                        i--;
                        break;
                    }
                }
                int aAnz = asteroids->getEintragAnzahl();
                for( int j = 0; j < aAnz; j++ )
                {
                    Asteroid *a = asteroids->z( j );
                    Vertex pos;
                    __int64 seed = randG.getSeed();
                    double intens = tmp->getIntensity() * ( ( tmp->getSpeed() - a->getSpeed() ).getLength() / 200 );
                    Asteroid * b = a->istTreffer( tmp, &randG, asteroidId, pos );
                    if( b )
                    {
                        float erf = 0;
                        int skillP = 0;
                        for( int k = 0; k < spielerAnzahl; k++ )
                        {
                            Spieler *s = spieler->z( k );
                            if( s && s->getSpielerNummer() == tmp->getSpieler() )
                            {
                                s->addTreffer( (float)intens, 0 );
                                erf = s->getEp();
                                skillP = s->getSkillP();
                            }
                        }
                        for( int k = 0; k < spielerAnzahl; k++ )
                        {
                            Spieler *s = spieler->z( k );
                            if( s )
                                s->zKlient()->sendeAsteroidTreffer( a->getId(), b->getId(), tmp->getId(), pos, seed, spielZeit, erf, skillP );
                        }
                        welt->removeObject( tmp );
                        shots->remove( i );
                        if( b->getMasse() > intens * 50 )
                        {
                            asteroids->add( (Asteroid *)b->getThis() );
                            welt->addObject( b );
                        }
                        else
                        {
                            Pixel *p = new Pixel( b->getPosition(), b->getSpeed(), b->getMasse() / 50, pixelId++ );
                            welt->addObject( p->getThis() );
                            pixel->add( p );
                            for( int k = 0; k < spielerAnzahl; k++ )
                            {
                                Spieler *s = spieler->z( k );
                                if( s )
                                    s->zKlient()->sendePixel( b->getId(), p->getId(), spielZeit );
                            }
                            b->release();
                        }
                        if( a->getMasse() < intens * 50 )
                        {
                            Pixel *p = new Pixel( a->getPosition(), a->getSpeed(), a->getMasse() / 50, pixelId++ );
                            welt->addObject( p->getThis() );
                            pixel->add( p );
                            for( int k = 0; k < spielerAnzahl; k++ )
                            {
                                Spieler *s = spieler->z( k );
                                if( s )
                                    s->zKlient()->sendePixel( a->getId(), p->getId(), spielZeit );
                            }
                            welt->removeObject( a );
                            asteroids->remove( j-- );
                            aAnz--;
                        }
                    }
                }
            }
        }
    }
    // Neue Schüsse hinzufügen
    for( int i = 0; i < spielerAnzahl; i++ )
    {
        Spieler *tmp = spieler->z( i );
        if( tmp )
        {
            Laser *nL = tmp->getLaser( nextSchussId );
            if( nL )
            {
                nextSchussId++;
                welt->addObject( nL->getThis() );
                shots->add( nL );
                for( int j = 0; j < spielerAnzahl; j++ )
                {
                    if( spieler->z( j ) && spieler->z( j )->zKlient() )
                        spieler->z( j )->zKlient()->sendeSchuss( nL->getId(), nL->getSpieler(), nL->getPosition(), nL->getSpeed(), nL->getIntensity(), spielZeit );
                }
            }
        }
    }
    // Asteroiden
    nextAsteroid -= zeit;
    if( nextAsteroid <= 0 )
    {
        nextAsteroid += 30 + (float)randG.rand() * 30;
        if( asteroids->getEintragAnzahl() < 30 )
        {
            Vertex pos = Vertex( (float)randG.rand() * (float)welt->getWorldInfo().size.x, (float)randG.rand() * (float)welt->getWorldInfo().size.y );
            Vertex speed = Vertex( (float)randG.rand() * 100, (float)randG.rand() * 100 );
            float rot = 2 * (float)PI * (float)randG.rand();
            float rotS = (float)randG.rand();
            int index = (int)( (float)asteroidModels->getEintragAnzahl() * (float)randG.rand() );
            Asteroid *astr = new Asteroid( asteroidId++, pos, speed, rot, rotS, asteroidModels->get( index ) );
            asteroids->add( astr );
            welt->addObject( astr->getThis() );
            for( int j = 0; j < spielerAnzahl; j++ )
            {
                if( spieler->z( j ) && spieler->z( j )->zKlient() )
                    spieler->z( j )->zKlient()->sendeAsteroid( astr->getId(), pos, speed, rot, rotS, index, spielZeit );
            }
        }
    }
    // Pixel
    int pixelAnz = pixel->getEintragAnzahl();
    for( int i = 0; i < pixelAnz; i++ )
    {
        Pixel *p = pixel->z( i );
        if( p->getEp() <= 0 )
        {
            for( int j = 0; j < spielerAnzahl; j++ )
            {
                if( spieler->z( j ) && spieler->z( j )->zKlient() )
                    spieler->z( j )->zKlient()->sendeEp( p->getId(), -1, spielZeit );
            }
            pixel->remove( i-- );
            welt->removeObject( p );
            pixelAnz--;
        }
        else
        {
            for( auto s = spieler->getIterator(); s; s++ )
            {
                if( s->istTreffer( p->getPosition() ) )
                {
                    s->addEp( p->getEp() );
                    for( int j = 0; j < spielerAnzahl; j++ )
                    {
                        if( spieler->z( j ) && spieler->z( j )->zKlient() )
                            spieler->z( j )->zKlient()->sendeEp( p->getId(), s->getSpielerNummer(), spielZeit );
                    }
                    pixel->remove( i-- );
                    welt->removeObject( p );
                    pixelAnz--;
                    break;
                }
            }
        }
    }
}

void Spiel::run()
{
    Text *pfad = psqldb->getSpielPfad( karteId );
    if( pfad )
        pfad->append( "/" );
    pfad->append( "models/asteroids.m2" );
    M2Datei *aDat = new M2Datei();
    aDat->setPfadZ( pfad );
    aDat->leseDaten();
    int anz = aDat->getModelAnzahl();
    for( int i = 0; i < anz; i++ )
    {
        asteroidModels->add( aDat->ladeModel( aDat->zModelName( i )->getText() ) );
    }
    log = new Datei();
    pfad = new Text( "../spiel log/" );
    pfad->append( spielId );
    pfad->append( "/verlauf.ksggl" );
    log->setDatei( pfad );
    log->remove();
    log->erstellen();
    log->open( Datei::Style::schreiben );
    time_t t;
    time( &t );
    srand( (unsigned int)t );
    log->schreibe( (char *)& spielerAnzahl, 4 );
    for( int i = 0; i < spielerAnzahl; i++ )
    {
        Spieler *tmp = spieler->z( i );
        if( tmp && tmp->zKlient() )
        {
            tmp->addSkill( new ShieldBoost() );
            tmp->addSkill( new SpeedBoost() );
            tmp->zKlient()->sendeInit( spieler, -1 );
            log->schreibe( (char *)& i, 4 );
            int sNum = tmp->getSpielerNummer();
            log->schreibe( (char *)& sNum, 4 );
            tmp->zKlient()->sendeSpielerNummer( sNum, -1 );
            int team = tmp->zTeam()->id;
            log->schreibe( (char *)& team, 4 );
            int farbe = tmp->getSpielerFarbe();
            log->schreibe( (char *)& farbe, 4 );
            farbe = tmp->zTeam()->farbe;
            log->schreibe( (char *)& farbe, 4 );
            Text * name = psqldb->getAccountRufName( tmp->getAccountId() );
            char len = (char)( name ? name->getLength() : 0 );
            log->schreibe( &len, 1 );
            if( len )
                log->schreibe( name->getText(), len );
            if( name )
                name->release();
            name = sts->teamName->z( team );
            len = (char)( name ? name->getLength() : 0 );
            log->schreibe( &len, 1 );
            if( len )
                log->schreibe( name->getText(), len );
        }
    }
    __int64 randSeed = randG.getSeed();
    log->schreibe( (char *)& randSeed, 8 );
    Array< char > spielerStatus;
    ZeitMesser * zeit = new ZeitMesser();
    zeit->messungStart();
    isRunning = 1;
    ende = 0;
    double ausgleich = 0;
    double sZ = 0;
    spielZeit = -1;
    for( int i = 0; i < spielerAnzahl; i++ )
    {
        Spieler *tmp = spieler->z( i );
        if( tmp && tmp->zKlient() )
            tmp->zKlient()->sendeStart( spielZeit );
    }
    double rZeit = 0;
    while( !ende )
    {
        zeit->messungEnde();
        zeit->messungStart();
        double z = zeit->getSekunden();
        ausgleich += TICK - z;
        if( ausgleich > 0 )
            Sleep( (int)( ausgleich * 1000 ) );
        rZeit += z;
        while( sZ + TICK < rZeit && !ende )
        {
            EnterCriticalSection( &cs );
            sZ += TICK;
            spielZeit++;
            char c = 0;
            log->schreibe( &c, 1 );
            tick( TICK );
            LeaveCriticalSection( &cs );
        }
    }
    zeit->messungEnde();
    zeit->release();
    for( int i = 0; i < spielerAnzahl; i++ )
    {
        if( spieler->z( i ) && spieler->z( i )->zKlient() )
        {
            if( spieler->z( i )->zTeam()->punkte < spieler->z( i )->zTeam()->maxPunkte )
            {
                spielerStatus.set( 1, i ); // Datenbank Verloren
                spieler->z( i )->zKlient()->sendeSpielEnde( 0, 0 );
            }
            else
            {
                spielerStatus.set( 2, i ); // Datenbank Gewonnen
                spieler->z( i )->zKlient()->sendeSpielEnde( 1, 0 );
            }
        }
        if( spieler->z( i ) && ( !spieler->z( i )->zKlient() || !spieler->z( i )->istOnline() ) )
            spielerStatus.set( 3, i );
    }
    if( teamAnzahl == 1 )
        psqldb->setSpielStatusBeendet( spielId, 6 );
    else
        psqldb->setSpielStatusBeendet( spielId, 5 );
    for( int i = 0; i < spielerAnzahl; i++ )
    {
        Spieler *tmp = spieler->z( i );
        if( tmp )
        {
            psqldb->setSpielSpielerStatus( spielId, tmp->getAccountId(), tmp->getPunkte(), spielerStatus.get( i ) );
            if( teamAnzahl > 1 )
                psqldb->addSpielerStatistik( tmp->getAccountId(), spielId );
        }
    }
    log->close();
    log = log->release();
    isRunning = 0;
}

// constant
StatistikV *Spiel::getStatistik() const
{
    return stat->getThis();
}

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

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