#include "KartenServer.h"
#include <iostream>
#include <Klient.h>
#include <Globals.h>

// Inhalt der KartenServer Klasse aus KartenServer.h
// Konstruktor 
KartenServer::KartenServer( InitDatei *zIni )
    : Thread()
{
    Network::Start( 100 );
    std::cout << "KS: Verbindung mit Datenbank wird hergestellt...\n";
    db = new KSDatenbank( zIni );
    klientAnzahl = 0;
    klients = new RCArray< KSKlient >();
    empfangen = 0;
    gesendet = 0;
    fehler = new Text();
    ini = zIni->getThis();
    id = *zIni->zWert( "ServerId" );
    server = new Server();
    aServer = new Server();
    std::cout << "KS: Starten des Admin Servers...\n";
    if( !aServer->verbinde( (unsigned short)TextZuInt( ini->zWert( "AdminServerPort" )->getText(), 10 ), 10 ) )
    {
        std::cout << "KS: Der Admin Server konnte nicht gestartet werden. Das Programm wird beendet.\n";
        exit( 1 );
    }
    db->setServerStatus( id, 2 );
    end = 0;
    nichtPausiert = 0;
    updateKarte = 0;
    InitializeCriticalSection( &cs );
    ref = 1;
    if( zIni->zWert( "Aktiv" )->istGleich( "TRUE" ) )
    {
        serverStarten();
        serverFortsetzen();
    }
    updater = new Updater( getThis() );
}

// Destruktor 
KartenServer::~KartenServer()
{
    updater->release();
    fehler->release();
    server->trenne();
    server->release();
    aServer->trenne();
    aServer->release();
    if( klients )
        klients->release();
    ini->release();
    db->release();
    DeleteCriticalSection( &cs );
}

// nicht constant 
void KartenServer::runn()
{
    while( !end )
    {
        SKlient *klient;
        klient = aServer->getKlient();
        if( end && klient )
        {
            klient->trenne();
            klient = klient->release();
            Sleep( 1000 );
            return;
        }
        if( !klient )
            return;
        KSAKlient *clHandle = new KSAKlient( klient, getThis() );
        clHandle->start();
    }
}

void KartenServer::thread()
{
    while( 1 )
    {
        SKlient *klient;
        klient = server->getKlient();
        if( !klient )
            break;
		Framework::getThreadRegister()->cleanUpClosedThreads();
        KSKlient *clHandle = new KSKlient( klient, getThis() );
        EnterCriticalSection( &cs );
        klients->set( clHandle, klientAnzahl );
        klientAnzahl++;
        LeaveCriticalSection( &cs );
        clHandle->start();
    }
}

void KartenServer::close()
{
    db->setServerStatus( id, 1 );
    server->trenne();
#ifdef WIN32
    warteAufThread( 1000 );
#endif
    EnterCriticalSection( &cs );
    for( int i = 0; i < klientAnzahl; i++ )
        klients->z( i )->absturz();
    klients = klients->release();
    klientAnzahl = 0;
    LeaveCriticalSection( &cs );
    ende();
    run = 0;
    end = 1;
    Klient *klient = new Klient();
    klient->verbinde( aServer->getPort(), "127.0.0.1" );
    Sleep( 500 );
    aServer->trenne();
    klient->release();
}

bool KartenServer::serverStarten()
{
    if( nichtPausiert )
    {
        fehler->setText( "Der Server konnte nicht gestartet werden: Der Server läuft bereits." );
        return 0;
    }
    if( server )
        server->release();
    server = new Server();
    if( server->verbinde( (unsigned short)TextZuInt( ini->zWert( "ServerPort" )->getText(), 10 ), 10 ) )
    {
        nichtPausiert = 1;
        start();
        return 1;
    }
    else
    {
        serverBeenden();
        fehler->setText( "Der Server konnte nicht gestartet werden: Eventuell ist der Port in benutzung." );
        return 0;
    }
}

bool KartenServer::serverPause()
{
    if( !nichtPausiert )
    {
        fehler->setText( "Der Server konnte nicht pausiert werden: Der Server läuft nicht." );
        return 0;
    }
    if( !db->setServerStatus( id, 2 ) )
    {
        fehler->setText( "Der Server konnte nicht pausiert werden: " );
        fehler->append( db->getLetzterFehler() );
        return 0;
    }
    return 1;
}

bool KartenServer::serverFortsetzen()
{
    if( !nichtPausiert )
    {
        fehler->setText( "Der Server konnte nicht fortgesetzt werden: Der Server läuft nicht." );
        return 0;
    }
    if( !db->setServerStatus( id, 3 ) )
    {
        fehler->setText( "Der Server konnte nicht fortgesetzt werden: " );
        fehler->append( db->getLetzterFehler() );
        return 0;
    }
    return 1;
}

bool KartenServer::serverBeenden()
{
    if( !nichtPausiert )
    {
        fehler->setText( "Der Server konnte nicht beendet werden: Der Server läuft nicht." );
        return 0;
    }
    if( db->serverIstNichtPausiert( id ) )
    {
        fehler->setText( "Der Server konnte nicht beendet werden: Der Server muss erst pausiert werden." );
        return 0;
    }
    nichtPausiert = 0;
    ende();
    if( server )
        server->trenne();
    return 1;
}

bool KartenServer::setMaxKarten( int mk )
{
    if( !db->setMaxKarten( id, mk ) )
    {
        fehler->setText( "Die maximale Anzahl der Karten konnte nicht gesetzt werden:\n" );
        fehler->append( db->getLetzterFehler() );
        return 0;
    }
    ini->setWert( "MaxKarten", Text() += mk );
    return 1;
}

bool KartenServer::absturzKlient( int klientId )
{
    bool gefunden = 0;
    EnterCriticalSection( &cs );
    for( int i = 0; i < klientAnzahl; i++ )
    {
        if( klients->z( i )->getKlientNummer() == klientId )
        {
            klients->z( i )->absturz();
            klients->remove( i );
            klientAnzahl--;
            gefunden = 1;
            break;
        }
    }
    LeaveCriticalSection( &cs );
    return gefunden;
}

bool KartenServer::removeKlient( KSKlient *zKlient )
{
    bool gefunden = 0;
    EnterCriticalSection( &cs );
    for( int i = 0; i < klientAnzahl; i++ )
    {
        if( klients->z( i ) == zKlient )
        {
            klients->remove( i );
            klientAnzahl--;
            gefunden = 1;
            break;
        }
    }
    LeaveCriticalSection( &cs );
    return gefunden;
}

void KartenServer::addGesendet( int bytes )
{
    gesendet += bytes;
}

void KartenServer::addEmpfangen( int bytes )
{
    empfangen += bytes;
}

void KartenServer::karteUpdateStart( int karteId )
{
    updateKarte = karteId;
}

void KartenServer::karteUpdateEnde()
{
    updateKarte = 0;
}

// constant 
bool KartenServer::istAn() const
{
    return db->serverIstNichtPausiert( id );
}

Server *KartenServer::zServer() const
{
    return server;
}

KSDatenbank *KartenServer::zDB() const
{
    return db;
}

InitDatei *KartenServer::zIni() const
{
    return ini;
}

bool KartenServer::hatClients() const
{
    return klientAnzahl > 0;
}

int KartenServer::getId() const
{
    return id;
}

char *KartenServer::getLetzterFehler() const
{
    return fehler->getText();
}

bool KartenServer::wirdKarteGeupdatet( int id ) const
{
    return id == updateKarte;
}

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

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


// Inhalt der KSAKlient Klasse aus KartenServer.h
// Konstruktor 
KSAKlient::KSAKlient( SKlient *klient, KartenServer *ks )
    : Thread()
{
    this->klient = klient;
    unsigned char key[ 20 ] = { 179, 126, 247, 108, 30, 201, 180, 160, 131, 216, 16, 47, 42, 31, 193, 200, 157, 86, 175, 133 };
    klient->setSendeKey( (char*)key, 20 );
    klient->setEmpfangKey( (char*)key, 20 );
    name = new Text( "" );
    passwort = new Text( "" );
    adminId = 0;
    this->ks = ks;
}

// Destruktor 
KSAKlient::~KSAKlient()
{
    klient->trenne();
    klient->release();
    ks->release();
    name->release();
    passwort->release();
}

// nicht constant 
void KSAKlient::thread()
{
    while( 1 )
    {
        char c = 0;
        if( !klient->getNachrichtEncrypted( &c, 1 ) )
            break;
        else
        {
            bool br = 0;
            switch( c )
            {
            case 1: // Login
                if( 1 )
                {
                    klient->sendeEncrypted( "\1", 1 );
                    unsigned char nLen = 0;
                    klient->getNachrichtEncrypted( (char*)&nLen, 1 );
                    char *n = new char[ nLen + 1 ];
                    n[ (int)nLen ] = 0;
                    if( nLen )
                        klient->getNachrichtEncrypted( n, nLen );
                    unsigned char pLen = 0;
                    klient->getNachrichtEncrypted( (char*)&pLen, 1 );
                    char *p = new char[ pLen + 1 ];
                    p[ (int)pLen ] = 0;
                    if( pLen )
                        klient->getNachrichtEncrypted( p, pLen );
                    int adminId = ks->zDB()->istAdministrator( n, p );
                    if( adminId )
                    {
                        klient->sendeEncrypted( "\1", 1 );
                        name->setText( n );
                        passwort->setText( p );
                        this->adminId = adminId;
                    }
                    else
                        errorZuKlient( "Falsche Kombination aus Name und Passwort." );
                    delete[] n;
                    delete[] p;
                }
                break;
            case 2: // Logout
                adminId = 0;
                name->setText( "" );
                passwort->setText( "" );
                klient->sendeEncrypted( "\1", 1 );
                break;
            case 3: // Trennen
                br = 1;
                klient->sendeEncrypted( "\1", 1 );
                break;
            case 4: // Server starten
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    if( ks->zDB()->adminHatRecht( adminId, Admin_Recht::KSStarten ) )
                    {
                        if( !ks->serverStarten() )
                        {
                            Text *err = new Text();
                            err->append( ks->getLetzterFehler() );
                            errorZuKlient( err->getText() );
                            err->release();
                        }
                        else
                            klient->sendeEncrypted( "\1", 1 );
                    }
                    else
                        errorZuKlient( "Du bist nicht berechtigt den Server zu starten." );
                }
                break;
            case 5: // Server beenden
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    if( ks->zDB()->adminHatRecht( adminId, Admin_Recht::KSBeenden ) )
                    {
                        if( ks->serverBeenden() )
                            klient->sendeEncrypted( "\1", 1 );
                        else
                        {
                            Text *err = new Text();
                            err->append( ks->getLetzterFehler() );
                            errorZuKlient( err->getText() );
                            err->release();
                        }
                    }
                    else
                        errorZuKlient( "Du bist nicht berechtigt den Server zu beenden." );
                }
                break;
            case 6: // Programm Schließen
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    bool ok = 0;
                    if( ks->isRunning() )
                    {
                        if( ks->zDB()->adminHatRecht( adminId, Admin_Recht::KSBeenden ) )
                        {
                            if( ks->serverBeenden() )
                                ok = 1;
                            else
                            {
                                Text *err = new Text();
                                err->append( ks->getLetzterFehler() );
                                errorZuKlient( err->getText() );
                                err->release();
                            }
                        }
                        else
                            errorZuKlient( "Du bist nicht berechtigt den Server zu beenden." );
                    }
                    else
                        ok = 1;
                    if( ok && ks->hatClients() )
                    {
                        errorZuKlient( "Es sind noch Klients Online. Bitte versuche es später erneut." );
                        break;
                    }
                    if( ok )
                    {
                        klient->sendeEncrypted( "\1", 1 );
                        std::cout << "KS: Der Server wird von Benutzer " << adminId << " heruntergefahren.\n";
                        ks->close();
                        br = 1;
                    }
                }
                break;
            case 7: // Progtamm abstürzen
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    bool ok = 0;
                    if( ks->isRunning() )
                    {
                        if( ks->zDB()->adminHatRecht( adminId, Admin_Recht::KSBeenden ) )
                        {
                            ks->serverBeenden();
                            ok = 1;
                        }
                        else
                            errorZuKlient( "Du bist nicht berechtigt den Server zu beenden." );
                    }
                    else
                        ok = 1;
                    if( ok )
                    {
                        klient->sendeEncrypted( "\1", 1 );
                        std::cout << "KS: Der Server wurde von Benutzer " << adminId << " terminiert.\n";
                        ks->close();
                        br = 1;
                    }
                }
                break;
            case 8: // Status Frage
                if( 1 )
                {
                    char status = 0;
                    if( ks->isRunning() )
                    {
                        status = 1;
                        if( ks->istAn() )
                            status = 2;
                    }
                    klient->sendeEncrypted( "\1", 1 );
                    klient->sendeEncrypted( &status, 1 );
                }
                break;
            case 9: // Server pausieren
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    klient->sendeEncrypted( "\1", 1 );
                    char pause = 0;
                    klient->getNachrichtEncrypted( &pause, 1 );
                    if( ks->zDB()->adminHatRecht( adminId, Admin_Recht::KSPausieren ) )
                    {
                        bool ok = 0;
                        if( pause )
                            ok = ks->serverPause();
                        else
                            ok = ks->serverFortsetzen();
                        if( ok )
                            klient->sendeEncrypted( "\1", 1 );
                        else
                        {
                            Text *err = new Text();
                            err->append( ks->getLetzterFehler() );
                            errorZuKlient( err->getText() );
                            err->release();
                        }
                    }
                    else
                    {
                        if( pause )
                            errorZuKlient( "Du bist nicht berechtigt den Server zu pausieren." );
                        else
                            errorZuKlient( "Du bist nicht berechtigt den Server fortzusetzen." );
                    }
                }
                break;
            case 0xA: // maximale Anzahl der Clients setzen
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    klient->sendeEncrypted( "\1", 1 );
                    int maxK = 0;
                    klient->getNachrichtEncrypted( (char*)&maxK, 4 );
                    if( ks->zDB()->adminHatRecht( adminId, Admin_Recht::KSMKChange ) )
                    {
                        if( ks->setMaxKarten( maxK ) )
                            klient->sendeEncrypted( "\1", 1 );
                        else
                        {
                            Text *err = new Text();
                            err->append( ks->getLetzterFehler() );
                            errorZuKlient( err->getText() );
                            err->release();
                        }
                    }
                    else
                        errorZuKlient( "Du bist nicht berechtigt die maximale Anzahl der Karten zu verändern." );
                }
                break;
            case 0xC: // klient absturtz
                if( 1 )
                {
                    klient->sendeEncrypted( "\1", 1 );
                    int klientId = 0;
                    klient->getNachrichtEncrypted( (char*)&klientId, 4 );
                    if( klientId && ks->absturzKlient( klientId ) )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                        klient->sendeEncrypted( "\0", 1 );
                }
                break;
            default:
                errorZuKlient( "Unbekannte Nachricht!" );
                break;
            }
            if( br )
                break;
            ks->addEmpfangen( klient->getDownloadBytes( 1 ) );
            ks->addGesendet( klient->getUploadBytes( 1 ) );
        }
    }
    ks->addEmpfangen( klient->getDownloadBytes( 1 ) );
    ks->addGesendet( klient->getUploadBytes( 1 ) );
    delete this;
}

void KSAKlient::errorZuKlient( const char *nachricht ) const // sendet eine Fehlernachricht zum Klient
{
    klient->sendeEncrypted( "\3", 1 );
    char len = (char)textLength( nachricht );
    klient->sendeEncrypted( &len, 1 );
    klient->sendeEncrypted( nachricht, len );
}


// Inhalt der KSKlient aus KartenServer.h
// Konstruktor 
KSKlient::KSKlient( SKlient *klient, KartenServer *ks )
    : Thread()
{
    this->klient = klient;
    unsigned char key[ 20 ] = { 24, 15, 53, 87, 38, 73, 154, 38, 246, 90, 39, 133, 11, 199, 22, 80, 26, 132, 95, 54 };
    klient->setSendeKey( (char*)key, 20 );
    klient->setEmpfangKey( (char*)key, 20 );
    klientNummer = 0;
    this->ks = ks;
    ref = 1;
}

// Destruktor 
KSKlient::~KSKlient()
{
    klient->release();
    ks->release();
}

// privat
void KSKlient::suchDateien( const char *pf, RCArray< Text > *zDL, const char *rem )
{
    Datei d;
    d.setDatei( pf );
    if( d.istOrdner() )
    {
        RCArray< Text > *list = d.getDateiListe();
        if( list )
        {
            int anz = list->getEintragAnzahl();
            for( int i = 0; i < anz; i++ )
            {
                Text pfad = pf;
                pfad += "/";
                pfad += list->z( i )->getText();
                suchDateien( pfad, zDL, rem );
            }
            list->release();
        }
    }
    else
    {
        Text *pfad = new Text( pf );
        pfad->remove( 0, textLength( rem ) );
        zDL->add( pfad );
    }
}

// nicht constant
void KSKlient::absturz()
{
    ende();
    klient->trenne();
    ks->zDB()->unregisterKlient( klientNummer, ks->getId() );
}

void KSKlient::thread()
{
    while( 1 )
    {
        char c = 0;
        if( !klient->getNachrichtEncrypted( &c, 1 ) )
            break;
        else
        {
            bool br = 0;
            switch( c )
            {
            case 1: // Klient identifikation
                klient->getNachrichtEncrypted( (char*)&klientNummer, 4 );
                if( !ks->zDB()->proveKlient( klientNummer, ks->getId() ) )
                {
                    klientNummer = 0;
                    errorZuKlient( "Du bist nicht für diesen Server eingetragen" );
                }
                else
                {
                    Text *key = ks->zDB()->getKlientKey( klientNummer );
                    if( !key )
                        errorZuKlient( "Es konnte kein Schlüssel ermittelt werden." );
                    else
                    {
                        klient->sendeEncrypted( "\1", 1 );
                        klient->setEmpfangKey( *key, key->getLength() );
                        klient->setSendeKey( *key, key->getLength() );
                        key->release();
                    }
                }
                break;
            case 2: // Main / Erhaltung Server message
                if( 1 )
                {
                    char befehl = 0;
                    klient->getNachrichtEncrypted( &befehl, 1 );
                    switch( befehl )
                    {
                    case 2: // klient absturtz
                        if( 1 )
                        {
                            int klientId = 0;
                            klient->getNachrichtEncrypted( (char*)&klientId, 4 );
                            if( klientId && ks->absturzKlient( klientId ) )
                                klient->sendeEncrypted( "\1", 1 );
                            else
                                klient->sendeEncrypted( "\0", 1 );
                        }
                        break;
                    default:
                        errorZuKlient( "Befehl nicht bekannt!" );
                        break;
                    }
                }
                break;
            case 3: // Verbindungsende
                br = 1;
                klient->sendeEncrypted( "\1", 1 );
                break;
            case 4: // unregister Klient
                if( !klientNummer )
                {
                    errorZuKlient( "Du bist nicht Identifiziert." );
                    break;
                }
                ks->zDB()->unregisterKlient( klientNummer, ks->getId() );
                klient->sendeEncrypted( "\1", 1 );
                break;
            case 5: // keep alive
                if( !klientNummer )
                {
                    errorZuKlient( "Du bist nicht Identifiziert." );
                    break;
                }
                klient->sendeEncrypted( "\1", 1 );
                break;
            case 6: // download Karte (Klient)
                if( !klientNummer )
                {
                    errorZuKlient( "Du bist nicht Identifiziert." );
                    break;
                }
                else
                {
                    klient->sendeEncrypted( "\1", 1 );
                    int id = 0;
                    klient->getNachrichtEncrypted( (char*)&id, 4 );
                    if( !ks->zDB()->proveKarte( id, ks->getId() ) )
                    {
                        errorZuKlient( "Die Karte wurde nicht gefunden." );
                        break;
                    }
                    if( ks->wirdKarteGeupdatet( id ) )
                    {
                        char c = 2;
                        klient->sendeEncrypted( &c, 1 );
                        break;
                    }
                    klient->sendeEncrypted( "\1", 1 );
                    Text pfad = ks->zIni()->zWert( "KartenPfad" )->getText();
                    pfad += "/";
                    pfad += id;
                    pfad += "/client/map";
                    RCArray< Text > *dList = new RCArray< Text >();
                    suchDateien( pfad, dList, pfad );
                    int anz = dList->getEintragAnzahl();
                    klient->sendeEncrypted( (char*)&anz, 4 );
                    for( int i = 0; i < anz; i++ )
                    {
                        Text pf = dList->z( i )->getText();
                        unsigned char len = (unsigned char)pf.getLength();
                        Text dp = pf.getText();
                        dp.insert( 0, (char*)pfad );
                        Datei d;
                        d.setDatei( dp );
                        if( !len || !d.open( Datei::Style::lesen ) )
                        {
                            klient->sendeEncrypted( "\0", 1 );
                            continue;
                        }
                        klient->sendeEncrypted( (char*)&len, 1 );
                        klient->sendeEncrypted( pf, len );
                        __int64 size = d.getSize();
                        klient->sendeEncrypted( (char*)&size, 8 );
                        char *buffer = new char[ 2048 ];
                        while( size )
                        {
                            int l = size >= 2048 ? 2048 : (int)size;
                            d.lese( buffer, l );
                            klient->sende( buffer, l );
                            size -= l;
                        }
                        delete[] buffer;
                        d.close();
                    }
                    dList->release();
                }
                break;
            case 7: // download Karte (Server)
                if( klientNummer )
                {
                    errorZuKlient( "Du bist nicht berechtigt." );
                    break;
                }
                else
                {
                    klient->sendeEncrypted( "\1", 1 );
                    int id = 0;
                    klient->getNachrichtEncrypted( (char*)&id, 4 );
                    if( !ks->zDB()->proveKarte( id, ks->getId() ) )
                    {
                        errorZuKlient( "Die Karte wurde nicht gefunden." );
                        break;
                    }
                    if( ks->wirdKarteGeupdatet( id ) )
                    {
                        char c = 2;
                        klient->sendeEncrypted( &c, 1 );
                        break;
                    }
                    klient->sendeEncrypted( "\1", 1 );
                    Text pfad = ks->zIni()->zWert( "KartenPfad" )->getText();
                    pfad += "/";
                    pfad += id;
                    pfad += "/server";
                    RCArray< Text > *dList = new RCArray< Text >();
                    suchDateien( pfad, dList, pfad );
                    int anz = dList->getEintragAnzahl();
                    klient->sendeEncrypted( (char*)&anz, 4 );
                    for( int i = 0; i < anz; i++ )
                    {
                        Text pf = dList->z( i )->getText();
                        unsigned char len = (unsigned char)pf.getLength();
                        Text dp = pf.getText();
                        dp.insert( 0, (char*)pfad );
                        Datei d;
                        d.setDatei( dp );
                        if( !len || !d.open( Datei::Style::lesen ) )
                            continue;
                        klient->sendeEncrypted( (char*)&len, 1 );
                        klient->sendeEncrypted( pf, len );
                        __int64 size = d.getSize();
                        klient->sendeEncrypted( (char*)&size, 8 );
                        char *buffer = new char[ 2048 ];
                        while( size )
                        {
                            int l = size >= 2048 ? 2048 : (int)size;
                            d.lese( buffer, l );
                            klient->sende( buffer, l );
                            size -= l;
                        }
                        delete[] buffer;
                        d.close();
                    }
                    dList->release();
                }
                break;
            case 8: // Karte Titel Bild laden
                if( !klientNummer )
                {
                    errorZuKlient( "Du bist nicht Identifiziert." );
                    break;
                }
                else
                {
                    klient->sendeEncrypted( "\1", 1 );
                    int id = 0;
                    klient->getNachrichtEncrypted( (char*)&id, 4 );
                    if( !ks->zDB()->proveKarte( id, ks->getId() ) )
                    {
                        errorZuKlient( "Die Karte wurde nicht gefunden." );
                        break;
                    }
                    if( ks->wirdKarteGeupdatet( id ) )
                    {
                        char c = 2;
                        klient->sendeEncrypted( &c, 1 );
                        break;
                    }
                    Text pfad = ks->zIni()->zWert( "KartenPfad" )->getText();
                    pfad += "/";
                    pfad += id;
                    pfad += "/client/titel.ltdb";
                    Datei d;
                    d.setDatei( pfad );
                    if( d.open( Datei::Style::lesen ) )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                        errorZuKlient( "Fehler beim lesen der Datei." );
                    __int64 size = d.getSize();
                    klient->sendeEncrypted( (char*)&size, 8 );
                    char *buffer = new char[ 2048 ];
                    while( size )
                    {
                        int l = size >= 2048 ? 2048 : (int)size;
                        d.lese( buffer, l );
                        klient->sende( buffer, l );
                        size -= l;
                    }
                    delete[] buffer;
                    d.close();
                }
                break;
            case 9: // Karte Beschreibung
                if( !klientNummer )
                {
                    errorZuKlient( "Du bist nicht Identifiziert." );
                    break;
                }
                else
                {
                    klient->sendeEncrypted( "\1", 1 );
                    int id = 0;
                    klient->getNachrichtEncrypted( (char*)&id, 4 );
                    if( !ks->zDB()->proveKarte( id, ks->getId() ) )
                    {
                        errorZuKlient( "Die Karte wurde nicht gefunden." );
                        break;
                    }
                    if( ks->wirdKarteGeupdatet( id ) )
                    {
                        char c = 2;
                        klient->sendeEncrypted( &c, 1 );
                        break;
                    }
                    Text pfad = ks->zIni()->zWert( "KartenPfad" )->getText();
                    pfad += "/";
                    pfad += id;
                    pfad += "/client/beschreibung.ksgs";
                    Datei d;
                    d.setDatei( pfad );
                    if( d.open( Datei::Style::lesen ) )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                        errorZuKlient( "Fehler beim lesen der Datei." );
                    __int64 size = d.getSize();
                    klient->sendeEncrypted( (char*)&size, 8 );
                    char *buffer = new char[ 2048 ];
                    while( size )
                    {
                        int l = size >= 2048 ? 2048 : (int)size;
                        d.lese( buffer, l );
                        klient->sende( buffer, l );
                        size -= l;
                    }
                    delete[] buffer;
                    d.close();
                }
                break;
            case 10: // Karte Minimap
                if( !klientNummer )
                {
                    errorZuKlient( "Du bist nicht Identifiziert." );
                    break;
                }
                else
                {
                    klient->sendeEncrypted( "\1", 1 );
                    int id = 0;
                    klient->getNachrichtEncrypted( (char*)&id, 4 );
                    if( !ks->zDB()->proveKarte( id, ks->getId() ) )
                    {
                        errorZuKlient( "Die Karte wurde nicht gefunden." );
                        break;
                    }
                    if( ks->wirdKarteGeupdatet( id ) )
                    {
                        char c = 2;
                        klient->sendeEncrypted( &c, 1 );
                        break;
                    }
                    Text pfad = ks->zIni()->zWert( "KartenPfad" )->getText();
                    pfad += "/";
                    pfad += id;
                    pfad += "/client/minimap.ltdb";
                    Datei d;
                    d.setDatei( pfad );
                    if( d.open( Datei::Style::lesen ) )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                        errorZuKlient( "Fehler beim lesen der Datei." );
                    __int64 size = d.getSize();
                    klient->sendeEncrypted( (char*)&size, 8 );
                    char *buffer = new char[ 2048 ];
                    while( size )
                    {
                        int l = size >= 2048 ? 2048 : (int)size;
                        d.lese( buffer, l );
                        klient->sende( buffer, l );
                        size -= l;
                    }
                    delete[] buffer;
                    d.close();
                }
                break;
            case 11: // Karte Ladebild
                if( !klientNummer )
                {
                    errorZuKlient( "Du bist nicht Identifiziert." );
                    break;
                }
                else
                {
                    klient->sendeEncrypted( "\1", 1 );
                    int id = 0;
                    klient->getNachrichtEncrypted( (char*)&id, 4 );
                    if( !ks->zDB()->proveKarte( id, ks->getId() ) )
                    {
                        errorZuKlient( "Die Karte wurde nicht gefunden." );
                        break;
                    }
                    if( ks->wirdKarteGeupdatet( id ) )
                    {
                        char c = 2;
                        klient->sendeEncrypted( &c, 1 );
                        break;
                    }
                    Text pfad = ks->zIni()->zWert( "KartenPfad" )->getText();
                    pfad += "/";
                    pfad += id;
                    pfad += "/client/ladebild.ltdb";
                    Datei d;
                    d.setDatei( pfad );
                    if( d.open( Datei::Style::lesen ) )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                        errorZuKlient( "Fehler beim lesen der Datei." );
                    __int64 size = d.getSize();
                    klient->sendeEncrypted( (char*)&size, 8 );
                    char *buffer = new char[ 2048 ];
                    while( size )
                    {
                        int l = size >= 2048 ? 2048 : (int)size;
                        d.lese( buffer, l );
                        klient->sende( buffer, l );
                        size -= l;
                    }
                    delete[] buffer;
                    d.close();
                }
                break;
            default:
                errorZuKlient( "Unbekannte Nachricht!" );
                break;
            }
            if( br )
                break;
            ks->addEmpfangen( klient->getDownloadBytes( 1 ) );
            ks->addGesendet( klient->getUploadBytes( 1 ) );
        }
    }
    ks->addEmpfangen( klient->getDownloadBytes( 1 ) );
    ks->addGesendet( klient->getUploadBytes( 1 ) );
    ks->removeKlient( this ); // delete this
}

// constant
void KSKlient::errorZuKlient( const char *nachricht ) const // sendet eine Fehlernachricht zum Klient
{
    klient->sendeEncrypted( "\3", 1 );
    char len = (char)textLength( nachricht );
    klient->sendeEncrypted( &len, 1 );
    klient->sendeEncrypted( nachricht, len );
}

int KSKlient::getKlientNummer() const // gibt die KlientId zurück
{
    return klientNummer;
}

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

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