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

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

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

// nicht constant 
void LoginServer::runn()
{
    while( !end && aServer->isConnected() )
    {
        SSLSKlient *klient;
        klient = aServer->getKlient();
        if( end && klient )
        {
            klient->trenne();
            klient = (SSLSKlient *)klient->release();
            Sleep( 1000 );
            return;
        }
        if( !klient )
            continue;
        LSAKlient *clHandle = new LSAKlient( klient, dynamic_cast<LoginServer *>( getThis() ) );
        clHandle->start();
    }
}

void LoginServer::thread()
{
    while( server->isConnected() )
    {
        SKlient *klient;
        klient = server->getKlient();
        if( !klient )
            continue;
        Framework::getThreadRegister()->cleanUpClosedThreads();
        LSKlient *clHandle = new LSKlient( klient, dynamic_cast<LoginServer *>( getThis() ) );
        EnterCriticalSection( &cs );
        klients->add( clHandle );
        LeaveCriticalSection( &cs );
        clHandle->start();
    }
}

void LoginServer::close()
{
    db->setServerStatus( id, 1 );
    server->trenne();
#ifdef WIN32
    warteAufThread( 1000 );
#endif
    EnterCriticalSection( &cs );
    for( LSKlient *client : *klients )
        client->absturz();
    klients = ( RCArray<LSKlient>* )klients->release();
    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 LoginServer::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 LoginServer::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 LoginServer::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 LoginServer::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 LoginServer::setMaxKlients( int mc )
{
    if( !db->setMaxClients( id, mc ) )
    {
        fehler->setText( "Die maximale Anzahl der Clients konnte nicht gesetzt werden:\n" );
        fehler->append( db->getLetzterFehler() );
        return 0;
    }
    ini->setWert( "MaxClients", Text() += mc );
    return 1;
}

bool LoginServer::absturzKlient( int klientId )
{
    bool gefunden = 0;
    EnterCriticalSection( &cs );
    int index = 0;
    for( LSKlient* client : *klients )
    {
        if( client->getKlientNummer() == klientId )
        {
            client->absturz();
            klients->remove( index );
            gefunden = 1;
            break;
        }
        index++;
    }
    LeaveCriticalSection( &cs );
    return gefunden;
}

bool LoginServer::removeKlient( LSKlient *zKlient )
{
    bool gefunden = 0;
    EnterCriticalSection( &cs );
    int index = 0;
    for( LSKlient* client : *klients )
    {
        if( client == zKlient )
        {
            klients->remove( index );
            gefunden = 1;
            break;
        }
        index++;
    }
    LeaveCriticalSection( &cs );
    return gefunden;
}

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

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

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

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

LSDatenbank *LoginServer::zDB() const
{
    return db;
}

bool LoginServer::hatClients() const
{
    return klients->hat(0);
}

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

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


// Inhalt der LSAKlient Klasse aus LoginServer.h
// Konstruktor 
LSAKlient::LSAKlient( SSLSKlient *klient, LoginServer *ls )
    : Thread()
{
    this->klient = klient;
    name = new Text( "" );
    passwort = new Text( "" );
    adminId = 0;
    version = 0;
    this->ls = ls;
}

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

// nicht constant 
void LSAKlient::thread()
{
    while( 1 )
    {
        char c = 0;
        if( !klient->getNachricht( &c, 1 ) )
            break;
        else
        {
            bool br = 0;
            switch( c )
            {
            case 1: // Login
                if( 1 )
                {
                    klient->sende( "\1", 1 );
                    unsigned char nLen = 0;
                    klient->getNachricht( (char *)&nLen, 1 );
                    char *n = new char[ nLen + 1 ];
                    n[ (int)nLen ] = 0;
                    if( nLen )
                        klient->getNachricht( n, nLen );
                    unsigned char pLen = 0;
                    klient->getNachricht( (char *)&pLen, 1 );
                    char *p = new char[ pLen + 1 ];
                    p[ (int)pLen ] = 0;
                    if( pLen )
                        klient->getNachricht( p, pLen );
                    int adminId = ls->zDB()->istAdministrator( n, p );
                    if( adminId )
                    {
                        klient->sende( "\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->sende( "\1", 1 );
                break;
            case 3: // Trennen
                br = 1;
                klient->sende( "\1", 1 );
                break;
            case 4: // Server starten
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    if( ls->zDB()->adminHatRecht( adminId, Admin_Recht::LSStarten ) )
                    {
                        if( !ls->serverStarten() )
                        {
                            Text *err = new Text();
                            err->append( ls->getLetzterFehler() );
                            errorZuKlient( err->getText() );
                            err->release();
                        }
                        else
                            klient->sende( "\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( ls->zDB()->adminHatRecht( adminId, Admin_Recht::LSBeenden ) )
                    {
                        if( ls->serverBeenden() )
                            klient->sende( "\1", 1 );
                        else
                        {
                            Text *err = new Text();
                            err->append( ls->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( ls->isRunning() )
                    {
                        if( ls->zDB()->adminHatRecht( adminId, Admin_Recht::LSBeenden ) )
                        {
                            if( ls->serverBeenden() )
                                ok = 1;
                            else
                            {
                                Text *err = new Text();
                                err->append( ls->getLetzterFehler() );
                                errorZuKlient( err->getText() );
                                err->release();
                            }
                        }
                        else
                            errorZuKlient( "Du bist nicht berechtigt den Server zu beenden." );
                    }
                    else
                        ok = 1;
                    if( ok && ls->hatClients() )
                    {
                        errorZuKlient( "Es sind noch Klients Online. Bitte versuche es später erneut." );
                        break;
                    }
                    if( ok )
                    {
                        klient->sende( "\1", 1 );
                        std::cout << "LS: Der Server wird von Benutzer " << adminId << " heruntergefahren.\n";
                        ls->close();
                        br = 1;
                    }
                }
                break;
            case 7: // Progtamm abstürzen
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    bool ok = 0;
                    if( ls->isRunning() )
                    {
                        if( ls->zDB()->adminHatRecht( adminId, Admin_Recht::LSBeenden ) )
                        {
                            ls->serverBeenden();
                            ok = 1;
                        }
                        else
                            errorZuKlient( "Du bist nicht berechtigt den Server zu beenden." );
                    }
                    else
                        ok = 1;
                    if( ok )
                    {
                        klient->sende( "\1", 1 );
                        std::cout << "LS: Der Server wurde von Benutzer " << adminId << " terminiert.\n";
                        ls->close();
                        br = 1;
                    }
                }
                break;
            case 8: // Status Frage
                if( 1 )
                {
                    char status = 0;
                    if( ls->isRunning() )
                    {
                        status = 1;
                        if( ls->istAn() )
                            status = 2;
                    }
                    klient->sende( "\1", 1 );
                    klient->sende( &status, 1 );
                }
                break;
            case 9: // Server pausieren
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    klient->sende( "\1", 1 );
                    char pause = 0;
                    klient->getNachricht( &pause, 1 );
                    if( ls->zDB()->adminHatRecht( adminId, Admin_Recht::LSPausieren ) )
                    {
                        bool ok = 0;
                        if( pause )
                            ok = ls->serverPause();
                        else
                            ok = ls->serverFortsetzen();
                        if( ok )
                            klient->sende( "\1", 1 );
                        else
                        {
                            Text *err = new Text();
                            err->append( ls->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->sende( "\1", 1 );
                    int maxC = 0;
                    klient->getNachricht( (char *)&maxC, 4 );
                    if( ls->zDB()->adminHatRecht( adminId, Admin_Recht::LSMCChange ) )
                    {
                        if( ls->setMaxKlients( maxC ) )
                            klient->sende( "\1", 1 );
                        else
                        {
                            Text *err = new Text();
                            err->append( ls->getLetzterFehler() );
                            errorZuKlient( err->getText() );
                            err->release();
                        }
                    }
                    else
                        errorZuKlient( "Du bist nicht berechtigt die maximale Anzahl der Clients zu verändern." );
                }
                break;
            case 0xC: // klient absturtz
                if( 1 )
                {
                    klient->sende( "\1", 1 );
                    int klientId = 0;
                    klient->getNachricht( (char *)&klientId, 4 );
                    if( klientId && ls->absturzKlient( klientId ) )
                        klient->sende( "\1", 1 );
                    else
                        klient->sende( "\0", 1 );
                }
                break;
            default:
                errorZuKlient( "Unbekannte Nachricht!" );
                break;
            }
            if( br )
                break;
            ls->addEmpfangen( klient->getDownloadBytes( 1 ) );
            ls->addGesendet( klient->getUploadBytes( 1 ) );
        }
    }
    ls->addEmpfangen( klient->getDownloadBytes( 1 ) );
    ls->addGesendet( klient->getUploadBytes( 1 ) );
    delete this;
}

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


// Inhalt der LSKlient aus LoginServer.h
// Konstruktor
LSKlient::LSKlient( SKlient *klient, LoginServer *ls )
    : Thread()
{
    this->klient = klient;
    unsigned char key[ 20 ] = { 143, 166, 245, 235, 76, 75, 116, 80, 26, 178, 142, 176, 109, 53, 106, 222, 223, 55, 139, 111 };
    klient->setSendeKey( (char *)key, 20 );
    klient->setEmpfangKey( (char *)key, 20 );
    klientNummer = 0;
    this->ls = ls;
}

// Destruktor 
LSKlient::~LSKlient()
{
    klient->release();
    ls->release();
}

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

void LSKlient::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( !ls->zDB()->proveKlient( klientNummer, ls->getId() ) )
                {
                    klientNummer = 0;
                    errorZuKlient( "Du bist nicht für diesen Server eingetragen" );
                }
                else
                {
                    Text *key = ls->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 && ls->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;
                }
                ls->zDB()->unregisterKlient( klientNummer, ls->getId() );
                klient->sendeEncrypted( "\1", 1 );
                break;
            case 5: // Klient loggt sich ein
                if( 1 )
                {
                    if( !klientNummer )
                    {
                        errorZuKlient( "Du bist nicht Identifiziert." );
                        break;
                    }
                    klient->sendeEncrypted( "\1", 1 );
                    unsigned char byte = 0;
                    klient->getNachrichtEncrypted( (char *)&byte, 1 );
                    char *name = new char[ byte + 1 ];
                    name[ byte ] = 0;
                    klient->getNachrichtEncrypted( name, byte );
                    klient->getNachrichtEncrypted( (char *)&byte, 1 );
                    char *passwort = new char[ byte + 1 ];
                    passwort[ byte ] = 0;
                    klient->getNachrichtEncrypted( passwort, byte );
                    int accountId = ls->zDB()->getAccountId( name, passwort );
                    delete[]name;
                    delete[]passwort;
                    if( !accountId )
                        errorZuKlient( "Falsche Kombination von Name und Passwort." );
                    else
                    {
                        int ok = ls->zDB()->loginKlient( klientNummer, accountId );
                        if( ok != 1 )
                        {
                            if( ok == 0 )
                                errorZuKlient( "Falsche Kombination von Name und Passwort." );
                            if( ok == -1 )
                                errorZuKlient( "Du bist bereits eingeloggt." );
                            if( ok == -2 )
                            {
                                errorZuKlient( "Der Account ist bereits online." );
                                /*
                                klient->sende( "\2", 1 );
                                klient->getNachricht( (char*)&byte, 1 );
                                if( byte )
                                {
                                char *geheim = new char[ byte + 1 ];
                                geheim[ byte ] = 0;
                                klient->getNachricht( geheim, byte );
                                if( ls->zDB()->accountGeheim( accountId, geheim ) )
                                {
                                int *ret = ls->zDB()->kickKlient( accountId );
                                if( ret[ 0 ] )
                                {
                                Text **chatServer = ls->zDB()->getChatServerIpPort( ret[ 0 ] );
                                Klient *server = new Klient();
                                if( server->verbinde( TextZuInt( chatServer[ 1 ]->getText(), 10 ), chatServer[ 0 ]->getText() ) )
                                {
                                server->sende( "\5\1", 2 );
                                char serverReturn = 0;
                                server->getNachricht( &serverReturn, 1 );
                                if( serverReturn == 1 )
                                {
                                server->sende( (char*)&accountId, 4 );
                                server->getNachricht( &serverReturn, 1 );
                                }
                                server->sende( "\3", 1 );
                                server->getNachricht( &serverReturn, 1 );
                                }
                                chatServer[ 0 ]->release();
                                chatServer[ 1 ]->release();
                                delete[]chatServer;
                                }
                                delete[]ret;
                                klient->sende( "\1", 1 );
                                unsigned char klientLocIp[ 4 ];
                                klient->getNachricht( (char*)klientLocIp, 4 );
                                klient->getNachricht( (char*)&byte, 1 );
                                char *pcName = new char[ byte + 1 ];
                                pcName[ byte ] = 0;
                                klient->getNachricht( pcName, byte );
                                ls->zDB()->accountOnline( accountId, (char*)klient->getIp(), klientLocIp, pcName );
                                delete[]pcName;
                                klient->sende( (char*)&accountId, 4 );
                                }
                                else
                                klient->sende( "\0", 1 );
                                delete[]geheim;
                                }*/
                            }
                        }
                        else
                        {
                            klient->sendeEncrypted( "\1", 1 );
                            unsigned char klientLocIp[ 4 ];
                            klient->getNachrichtEncrypted( (char *)klientLocIp, 4 );
                            klient->getNachrichtEncrypted( (char *)&byte, 1 );
                            char *pcName = new char[ byte + 1 ];
                            pcName[ byte ] = 0;
                            klient->getNachrichtEncrypted( pcName, byte );
                            ls->zDB()->accountOnline( accountId, (char *)klient->getIp(), klientLocIp, pcName );
                            delete[]pcName;
                            klient->sendeEncrypted( (char *)&accountId, 4 );
                        }
                    }
                }
                break;
            case 6: // Klient loggt sich aus
                if( 1 )
                {
                    if( !klientNummer )
                    {
                        errorZuKlient( "Du bist nicht Identifiziert." );
                        break;
                    }
                    klient->sendeEncrypted( "\1", 1 );
                    int accountId = 0;
                    klient->getNachrichtEncrypted( (char *)&accountId, 4 );
                    Array< int > *ret = new Array< int >();
                    int anzahl = ls->zDB()->logoutKlient( klientNummer, ret );
                    if( anzahl > 0 )
                    {
                        int jetzt = 0;
                        int chAnz = ret->get( jetzt );
                        jetzt++;
                        for( int i = 0; i < chAnz; i++ )
                        {
                            int chatroomId = ret->get( jetzt );
                            jetzt++;
                            if( chatroomId )
                            {
                                MSGWeiterleitung *weiter = new MSGWeiterleitung( dynamic_cast<LoginServer *>( ls->getThis() ) );
                                weiter->spielerLeavesChatroom( chatroomId, accountId );
                                weiter->release();
                                if( ret->get( jetzt ) )
                                {
                                    MSGWeiterleitung *weiter = new MSGWeiterleitung( dynamic_cast<LoginServer *>( ls->getThis() ) );
                                    weiter->setChatroomAdmin( chatroomId, ls->zDB()->getChatroomAdmin( chatroomId ) );
                                    weiter->release();
                                }
                                jetzt++;
                            }
                        }
                        if( ret->get( jetzt ) == 1 )
                        {
                            jetzt++;
                            MSGWeiterleitung *weiter = new MSGWeiterleitung( dynamic_cast<LoginServer *>( ls->getThis() ) );
                            weiter->spielErstelltAbbrechen( ret->get( jetzt ) );
                            weiter->release();
                        }
                        jetzt++;
                        if( ret->get( jetzt ) == 1 )
                        {
                            jetzt++;
                            int gruppeId = ret->get( jetzt );
                            MSGWeiterleitung *weiter = new MSGWeiterleitung( dynamic_cast<LoginServer *>( ls->getThis() ) );
                            weiter->spielerLeavesGruppe( gruppeId, accountId );
                            weiter->release();
                            jetzt++;
                            if( ret->get( jetzt ) )
                            {
                                MSGWeiterleitung *weiter = new MSGWeiterleitung( dynamic_cast<LoginServer *>( ls->getThis() ) );
                                weiter->setGruppeAdmin( gruppeId, ls->zDB()->getGruppeAdmin( gruppeId ) );
                                weiter->release();
                            }
                        }
                        else if( ret->get( jetzt ) == 2 )
                        {
                            jetzt++;
                            int gruppeId = ret->get( jetzt );
                            MSGWeiterleitung *weiter = new MSGWeiterleitung( dynamic_cast<LoginServer *>( ls->getThis() ) );
                            weiter->kickSpielerAusGruppe( gruppeId );
                            weiter->release();
                        }
                        jetzt++;
                        if( ret->get( jetzt ) == 1 )
                            klient->sendeEncrypted( "\1", 1 );
                        else
                            errorZuKlient( "Logout nicht erfolgreich." );
                    }
                    else
                        errorZuKlient( "Logout nicht erfolgreich." );
                    ret->release();
                }
                break;
            case 0x7: // ping
                if( 1 )
                {
                    if( !klientNummer )
                    {
                        errorZuKlient( "Du bist nicht Identifiziert." );
                        break;
                    }
                    klient->sendeEncrypted( "\1", 1 );
                }
                break;
            default:
                errorZuKlient( "Unbekannte Nachricht!" );
                break;
            }
            if( br )
                break;
            ls->addEmpfangen( klient->getDownloadBytes( 1 ) );
            ls->addGesendet( klient->getUploadBytes( 1 ) );
        }
    }
    ls->addEmpfangen( klient->getDownloadBytes( 1 ) );
    ls->addGesendet( klient->getUploadBytes( 1 ) );
    ls->removeKlient( this ); // delete this
}

// constant
void LSKlient::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 LSKlient::getKlientNummer() const // gibt die KlientId zurück
{
    return klientNummer;
}

// Inhalt der MSGWeiterleitung Klasse aus LoginServer.h
// Konstruktor
MSGWeiterleitung::MSGWeiterleitung( LoginServer *ls )
    : ReferenceCounter()
{
    this->ls = ls;
}

// Destruktor
MSGWeiterleitung::~MSGWeiterleitung()
{
    ls->release();
}

// nicht constant
bool MSGWeiterleitung::spielErstelltAbbrechen( int spielErstelltId )
{
    bool ret = 1;
    Text *ip = new Text( "" );
    unsigned short port = 0;
    ret &= ls->zDB()->getSpielServerPortIp( spielErstelltId, &port, ip );
    if( ip->getLength() )
    {
        Klient *klient = new Klient();
        unsigned char key[ 20 ] = { 253, 234, 211, 132, 121, 230, 95, 145, 201, 13, 43, 77, 153, 223, 253, 69, 234, 43, 52, 99 };
        klient->setSendeKey( (char *)key, 20 );
        klient->setEmpfangKey( (char *)key, 20 );
        ret &= klient->verbinde( port, ip->getText() );
        ret &= klient->sendeEncrypted( "\x8\x1", 2 );
        char res = 0;
        ret &= klient->getNachrichtEncrypted( &res, 1 );
        if( res )
        {
            ret &= klient->sendeEncrypted( (char *)&spielErstelltId, 4 );
            ret &= klient->getNachrichtEncrypted( &res, 1 );
        }
        ret = (char)ret & res;
        ret &= klient->sendeEncrypted( "\x8\x0", 2 );
        ret &= klient->getNachrichtEncrypted( &res, 1 );
        ret = (char)ret & res;
        ls->addEmpfangen( klient->getDownloadBytes( 1 ) );
        ls->addGesendet( klient->getUploadBytes( 1 ) );
        klient->trenne();
        klient = (Klient *)klient->release();
        ip->release();
    }
    return ret;
}

bool MSGWeiterleitung::spielerLeavesGruppe( int gruppeId, int accountId )
{
    bool ret = 1;
    Array< int > *accId = new Array< int >();
    int anzahl = ls->zDB()->getSpielerAusGruppe( gruppeId, accId );
    for( int i = 0; i < anzahl; i++ )
    {
        int account = accId->get( i );
        if( account == accountId )
            continue;
        Text *ip = new Text( "" );
        unsigned short port = 0;
        ret &= ls->zDB()->getChatServerPortIp( account, &port, ip );
        if( ip->getLength() )
        {
            Klient *klient = new Klient();
            unsigned char key[ 20 ] = { 78, 20, 190, 133, 10, 175, 51, 96, 62, 1, 180, 194, 126, 50, 211, 154, 105, 227, 22, 101 };
            klient->setSendeKey( (char *)key, 20 );
            klient->setEmpfangKey( (char *)key, 20 );
            ret &= klient->verbinde( port, ip->getText() );
            ret &= klient->sendeEncrypted( "\5\x15", 2 );
            char res = 0;
            ret &= klient->getNachrichtEncrypted( &res, 1 );
            if( res )
            {
                ret &= klient->sendeEncrypted( (char *)&account, 4 );
                ret &= klient->sendeEncrypted( (char *)&accountId, 4 );
                ret &= klient->sendeEncrypted( (char *)&gruppeId, 4 );
                ret &= klient->getNachrichtEncrypted( &res, 1 );
            }
            ret = (char)ret & res;
            ret &= klient->sendeEncrypted( "\5\x18", 2 );
            res = 0;
            ret &= klient->getNachrichtEncrypted( &res, 1 );
            if( res )
            {
                ret &= klient->sendeEncrypted( (char *)&account, 4 );
                ret &= klient->sendeEncrypted( (char *)&gruppeId, 4 );
                ret &= klient->getNachrichtEncrypted( &res, 1 );
            }
            ret = (char)ret & res;
            ls->addEmpfangen( klient->getDownloadBytes( 1 ) );
            ls->addGesendet( klient->getUploadBytes( 1 ) );
            klient->trenne();
            klient = (Klient *)klient->release();
        }
        ip->release();
    }
    accId->release();
    return ret;
}

bool MSGWeiterleitung::setGruppeAdmin( int gruppeId, int adminId )
{
    if( !adminId || !gruppeId )
        return 0;
    bool ret = 1;
    Array< int > *accId = new Array< int >();
    int anzahl = ls->zDB()->getSpielerAusGruppe( gruppeId, accId );
    for( int i = 0; i < anzahl; i++ )
    {
        int account = accId->get( i );
        Text *ip = new Text( "" );
        unsigned short port = 0;
        ret &= ls->zDB()->getChatServerPortIp( account, &port, ip );
        if( ip->getLength() )
        {
            Klient *klient = new Klient();
            unsigned char key[ 20 ] = { 78, 20, 190, 133, 10, 175, 51, 96, 62, 1, 180, 194, 126, 50, 211, 154, 105, 227, 22, 101 };
            klient->setSendeKey( (char *)key, 20 );
            klient->setEmpfangKey( (char *)key, 20 );
            ret &= klient->verbinde( port, ip->getText() );
            ret &= klient->sendeEncrypted( "\5\x1B", 2 );
            char res = 0;
            ret &= klient->getNachrichtEncrypted( &res, 1 );
            if( res )
            {
                ret &= klient->sendeEncrypted( (char *)&account, 4 );
                ret &= klient->sendeEncrypted( (char *)&adminId, 4 );
                ret &= klient->sendeEncrypted( (char *)&gruppeId, 4 );
                ret &= klient->getNachrichtEncrypted( &res, 1 );
            }
            ret = (char)ret & res;
            ls->addEmpfangen( klient->getDownloadBytes( 1 ) );
            ls->addGesendet( klient->getUploadBytes( 1 ) );
            klient->trenne();
            klient = (Klient *)klient->release();
        }
        ip->release();
    }
    accId->release();
    return ret;
}

bool MSGWeiterleitung::spielerLeavesChatroom( int chatroomId, int accountId )
{
    bool ret = 1;
    Array< int > *accId = new Array< int >();
    int anzahl = ls->zDB()->getSpielerAusChatroom( chatroomId, accId );
    for( int i = 0; i < anzahl; i++ )
    {
        int account = accId->get( i );
        if( account == accountId )
            continue;
        Text *ip = new Text( "" );
        unsigned short port = 0;
        ret &= ls->zDB()->getChatServerPortIp( account, &port, ip );
        if( ip->getLength() )
        {
            Klient *klient = new Klient();
            unsigned char key[ 20 ] = { 78, 20, 190, 133, 10, 175, 51, 96, 62, 1, 180, 194, 126, 50, 211, 154, 105, 227, 22, 101 };
            klient->setSendeKey( (char *)key, 20 );
            klient->setEmpfangKey( (char *)key, 20 );
            ret &= klient->verbinde( port, ip->getText() );
            ret &= klient->sendeEncrypted( "\5\xE", 2 );
            char res = 0;
            ret &= klient->getNachrichtEncrypted( &res, 1 );
            if( res )
            {
                ret &= klient->sendeEncrypted( (char *)&accountId, 4 );
                ret &= klient->sendeEncrypted( (char *)&account, 4 );
                ret &= klient->sendeEncrypted( (char *)&chatroomId, 4 );
                ret &= klient->getNachrichtEncrypted( &res, 1 );
            }
            ret = (char)ret & res;
            ls->addEmpfangen( klient->getDownloadBytes( 1 ) );
            ls->addGesendet( klient->getUploadBytes( 1 ) );
            klient->trenne();
            klient = (Klient *)klient->release();
        }
        ip->release();
    }
    accId->release();
    return ret;
}

bool MSGWeiterleitung::setChatroomAdmin( int chatroomId, int adminId )
{
    if( !adminId || !chatroomId )
        return 0;
    bool ret = 1;
    Text *ip = new Text( "" );
    unsigned short port = 0;
    ret &= ls->zDB()->getChatServerPortIp( adminId, &port, ip );
    if( ip->getLength() )
    {
        Klient *klient = new Klient();
        unsigned char key[ 20 ] = { 78, 20, 190, 133, 10, 175, 51, 96, 62, 1, 180, 194, 126, 50, 211, 154, 105, 227, 22, 101 };
        klient->setSendeKey( (char *)key, 20 );
        klient->setEmpfangKey( (char *)key, 20 );
        ret &= klient->verbinde( port, ip->getText() );
        ret &= klient->sendeEncrypted( "\5\x12", 2 );
        char res = 0;
        ret &= klient->getNachrichtEncrypted( &res, 1 );
        if( res )
        {
            ret &= klient->sendeEncrypted( (char *)&adminId, 4 );
            ret &= klient->sendeEncrypted( (char *)&chatroomId, 4 );
            ret &= klient->getNachrichtEncrypted( &res, 1 );
        }
        ret = (char)ret & res;
        ls->addEmpfangen( klient->getDownloadBytes( 1 ) );
        ls->addGesendet( klient->getUploadBytes( 1 ) );
        klient->trenne();
        klient = (Klient *)klient->release();
    }
    ip->release();
    return ret;
}

bool MSGWeiterleitung::kickSpielerAusGruppe( int gruppeId )
{
    if( !gruppeId )
        return 0;
    bool ret = 1;
    Array< int > *accId = new Array< int >();
    int anzahl = ls->zDB()->getSpielerAusGruppe( gruppeId, accId );
    for( int i = 0; i < anzahl; i++ )
    {
        int account = accId->get( i );
        Text *ip = new Text( "" );
        unsigned short port = 0;
        ret = ret && ls->zDB()->getChatServerPortIp( account, &port, ip );
        if( ip->getLength() )
        {
            Klient *klient = new Klient();
            unsigned char key[ 20 ] = { 78, 20, 190, 133, 10, 175, 51, 96, 62, 1, 180, 194, 126, 50, 211, 154, 105, 227, 22, 101 };
            klient->setSendeKey( (char *)key, 20 );
            klient->setEmpfangKey( (char *)key, 20 );
            ret = ret && klient->verbinde( port, ip->getText() );
            ret = ret && klient->sendeEncrypted( "\5\x16", 2 );
            char res = 0;
            ret = ret && klient->getNachrichtEncrypted( &res, 1 );
            if( res )
            {
                ret = ret && klient->sendeEncrypted( (char *)&account, 4 );
                ret = ret && klient->sendeEncrypted( (char *)&gruppeId, 4 );
                ret = ret && klient->getNachrichtEncrypted( &res, 1 );
            }
            ret = (char)ret & res;
            ls->addEmpfangen( klient->getDownloadBytes( 1 ) );
            ls->addGesendet( klient->getUploadBytes( 1 ) );
            klient->trenne();
            klient = (Klient *)klient->release();
        }
        ls->zDB()->kickSpielerAusGruppe( gruppeId, account );
        ip->release();
    }
    accId->release();
    return ret;
}