#include "EditorKarte.h"

using namespace Editor;

KarteDaten::KarteDaten( EditorKlient *client )
{
    this->client = client;
    sts = new SpielerTeamStruktur();
    client->loadSpieler( spieler );
    client->loadTeams( teams );
    client->loadObjekte( objekte );
    exit = 0;
    ref = 1;
    start();
}

KarteDaten::~KarteDaten()
{
    exit = 1;
    if( isRunning() )
        warteAufThread( INT_MAX );
    cs.lock();
    for( auto i = objekte.getIterator(); i; i++ )
        delete i;
    for( auto i = spieler.getIterator(); i; i++ )
        delete i;
    for( auto i = teams.getIterator(); i; i++ )
        delete i;
    sts->release();
    client->release();
}

void KarteDaten::addObjekt( ObjektDaten &daten )
{
    ObjektDaten *nd = new ObjektDaten( daten );
    cs.lock();
    nd->id = objekte.getEintragAnzahl();
    objekte.add( nd );
    ObjektDaten td = *nd;
    EditorKlient *c = client;
    aktionen.add( [ td, c ]()
    {
        c->saveObjekt( &td );
    } );
    cs.unlock();
}

void KarteDaten::removeObjekt( int index )
{
    cs.lock();
    int id = objekte.get( index )->id;
    delete objekte.get( index );
    objekte.remove( index );
    EditorKlient *c = client;
    aktionen.add( [ id, c ]()
    {
        c->deleteObjekt( id );
    } );
    cs.unlock();
}

void KarteDaten::getObjekt( int index, std::function< bool( ObjektDaten* ) > callBack )
{
    cs.lock();
    if( callBack( objekte.get( index ) ) )
    {
        ObjektDaten td = *objekte.get( index );
        EditorKlient *c = client;
        aktionen.add( [ td, c ]()
        {
            c->saveObjekt( &td );
        } );
    }
    cs.unlock();
}

void KarteDaten::getSpieler( int index, std::function< bool( SpielerDaten* ) > callBack )
{
    cs.lock();
    if( callBack( spieler.get( index ) ) )
    {
        SpielerDaten td = *spieler.get( index );
        EditorKlient *c = client;
        aktionen.add( [ td, c ]()
        {
            c->saveSpieler( &td );
        } );
    }
    cs.unlock();
}

void KarteDaten::getTeam( int index, std::function< bool( TeamDaten* ) > callBack )
{
    cs.lock();
    if( callBack( teams.get( index ) ) )
    {
        TeamDaten td = *teams.get( index );
        EditorKlient *c = client;
        aktionen.add( [ td, c ](){
            c->saveTeam( &td );
        } );
    }
    cs.unlock();
}

void KarteDaten::thread()
{
    while( !exit )
    {
        cs.lock();
        while( hasAktions() )
        {
            std::function< void() > ak = aktionen.get( 0 );
            cs.unlock();
            ak();
            cs.lock();
            aktionen.remove( 0 );
        }
        cs.unlock();
        Sleep( 100 );
    }
}

const ObjektDaten *KarteDaten::getObjekt( int index )
{
    ObjektDaten *ret = 0;
    cs.lock();
    ret = objekte.get( index );
    cs.unlock();
    return ret;
}

const SpielerDaten *KarteDaten::getSpieler( int index )
{
    SpielerDaten *ret = 0;
    cs.lock();
    ret = spieler.get( index );
    cs.unlock();
    return ret;
}

const TeamDaten *KarteDaten::getTeam( int index )
{
    TeamDaten *ret = 0;
    cs.lock();
    ret = teams.get( index );
    cs.unlock();
    return ret;
}

int KarteDaten::getSpielerIndexById( int id )
{
    int index = 0;
    cs.lock();
    for( auto i = spieler.getIterator(); i; i++ )
    {
        if( i->id == id )
            break;
        index++;
    }
    cs.unlock();
    return index;
}

int KarteDaten::getSpielerAnzahl() const
{
    return spieler.getEintragAnzahl();
}

int KarteDaten::getTeamIndexById( int id )
{
    int index = 0;
    cs.lock();
    for( auto i = teams.getIterator(); i; i++ )
    {
        if( i->id == id )
            break;
        index++;
    }
    cs.unlock();
    return index;
}

int KarteDaten::getTeamAnzahl() const
{
    return teams.getEintragAnzahl();
}

int KarteDaten::getObjektAnzahl() const
{
    return objekte.getEintragAnzahl();
}

bool KarteDaten::hasError() const
{
    return !error.istGleich( "" );
}

char *KarteDaten::getError() const
{
    return error;
}

bool KarteDaten::hasAktions() const
{
    return aktionen.getEintragAnzahl() > 0;
}

KarteDaten *KarteDaten::getThis()
{
    ref++;
    return this;
}

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