#include "AppServer.h"
#include "Datenbank.h"
#include <Text.h>
#include <iostream>
#include <Klient.h>
#include <Globals.h>

// Inhalt der AppServer Klasse aus AppServer.h
// Konstruktor 
AppServer::AppServer( InitDatei *zDat )
    : Thread()
{
    Network::Start( 100 );
    std::cout << "AppS: Verbindung mit Datenbank wird hergestellt...\n";
    db = new AppSDatenbank( zDat );
    clients = 0;
    empfangen = 0;
    gesendet = 0;
    dat = zDat->getThis();
    server = new Server();
    aServer = new SSLServer();
    aServer->setPrivateKeyPassword( zDat->zWert( "SSLPasswort" )->getText() );
    aServer->setPrivateKeyFile( zDat->zWert( "SSLKey" )->getText() );
    aServer->setCertificateFile( zDat->zWert( "SSLCert" )->getText() );
    std::cout << "AppS: Starten des Admin Servers...\n";
    if( !aServer->verbinde( (unsigned short)TextZuInt( zDat->zWert( "AppSAPort" )->getText(), 10 ), 10 ) )
    {
        std::cout << "AppS: Der Admin Server konnte nicht gestartet werden. Das Programm wird beendet.\n";
        exit( 1 );
    }
    end = 0;
    InitializeCriticalSection( &cs );
    if( zDat->wertExistiert( "Aktiv" ) && zDat->zWert( "Aktiv" )->istGleich( "TRUE" ) )
        serverStarten();
}

// Destruktor 
AppServer::~AppServer()
{
    ende();
    server->trenne();
    server->release();
    aServer->trenne();
    aServer->release();
    dat->release();
    db->release();
    Network::Exit();
    DeleteCriticalSection( &cs );
}

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

void AppServer::thread()
{
    while( server->isConnected() )
    {
        SKlient *klient;
        klient = server->getKlient();
        if( !klient )
            continue;
        Framework::getThreadRegister()->cleanUpClosedThreads();
        AppSKlient * clHandle = new AppSKlient( klient, (AppServer *)getThis() );
        clHandle->start();
        clients++;
    }
    run = 0;
}

void AppServer::close()
{
    server->trenne();
#ifdef WIN32
    warteAufThread( 1000 );
#endif
    ende();
    run = 0;
    end = 1;
    Klient *klient = new Klient();
    klient->verbinde( aServer->getPort(), "127.0.0.1" );
    Sleep( 500 );
    aServer->trenne();
    klient->release();
}

bool AppServer::serverStarten()
{
    if( run )
        return 1;
    bool ret = server->verbinde( (unsigned short)TextZuInt( dat->zWert( "AppSPort" )->getText(), 10 ), 10 );
    start();
    return ret;
}

void AppServer::serverBeenden()
{
    if( !run )
        return;
    server->trenne();
#ifdef WIN32
    warteAufThread( 1000 );
#endif
    ende();
    server->release();
    server = new Server();
    run = 0;
}

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

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

void AppServer::clientTrennung()
{
    clients--;
}

// constant 
InitDatei *AppServer::zIni() const
{
    return dat;
}

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

AppSDatenbank *AppServer::zDB() const
{
    return db;
}

int AppServer::getClients() const
{
    return clients;
}

bool AppServer::hatClients() const
{
    return clients > 0;
}


// Inhalt der AppSKlient Klasse aus AppServer.h
// Konstruktor 
AppSAKlient::AppSAKlient( SSLSKlient * klient, AppServer * appS )
    : Thread()
{
    this->klient = klient;
    name = new Text( "" );
    passwort = new Text( "" );
    adminId = 0;
    this->appS = appS;
}

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

// nicht constant 
void AppSAKlient::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 = appS->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( appS->zDB()->adminHatRecht( adminId, Admin_Recht::AppSStarten ) )
                    {
                        if( !appS->serverStarten() )
                            errorZuKlient( "Beim starten des Servers ist ein Fehler aufgetreten." );
                        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( appS->zDB()->adminHatRecht( adminId, Admin_Recht::AppSBeenden ) )
                    {
                        appS->serverBeenden();
                        klient->sende( "\1", 1 );
                    }
                    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( appS->isRunning() )
                    {
                        if( appS->zDB()->adminHatRecht( adminId, Admin_Recht::AppSBeenden ) )
                        {
                            appS->serverBeenden();
                            ok = 1;
                        }
                        else
                            errorZuKlient( "Du bist nicht berechtigt den Server zu beenden." );
                    }
                    else
                        ok = 1;
                    if( ok &&appS->hatClients() )
                    {
                        errorZuKlient( "Es sind noch Klients Online. Bitte versuche es später erneut." );
                        break;
                    }
                    if( ok )
                    {
                        klient->sende( "\1", 1 );
                        std::cout << "AppS: Der Server wird von Benutzer " << adminId << " heruntergefahren.\n";
                        appS->close();
                        br = 1;
                    }
                }
                break;
            case 7: // Progtamm abstürzen
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    bool ok = 0;
                    if( appS->isRunning() )
                    {
                        if( appS->zDB()->adminHatRecht( adminId, Admin_Recht::AppSBeenden ) )
                        {
                            appS->serverBeenden();
                            ok = 1;
                        }
                        else
                            errorZuKlient( "Du bist nicht berechtigt den Server zu beenden." );
                    }
                    else
                        ok = 1;
                    if( ok )
                    {
                        klient->sende( "\1", 1 );
                        std::cout << "AppS: Der Server wurde von Benutzer " << adminId << " terminiert.\n";
                        appS->close();
                        br = 1;
                    }
                }
                break;
            case 8: // Status Frage
                if( 1 )
                {
                    klient->sende( "\1", 1 );
                    char status = (int)appS->isRunning();
                    klient->sende( &status, 1 );
                }
                break;
            default:
                errorZuKlient( "Unbekannte Nachricht!" );
                br = true;
                break;
            }
            if( br )
                break;
            appS->addEmpfangen( klient->getDownloadBytes( 1 ) );
            appS->addGesendet( klient->getUploadBytes( 1 ) );
        }
    }
    appS->addEmpfangen( klient->getDownloadBytes( 1 ) );
    appS->addGesendet( klient->getUploadBytes( 1 ) );
    delete this;
}

void AppSAKlient::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 AppSKlient Klasse aus AppServer.h
// Konstruktor 
AppSKlient::AppSKlient( SKlient * klient, AppServer * appS )
    : Thread()
{
    std::cout << "New Client aktuell:" << appS->getClients() << "\n";
    this->klient = klient;
    unsigned char key[ 20 ] = { 74, 103, 6, 115, 185, 240, 35, 53, 108, 55, 120, 253, 1, 232, 78, 254, 183, 223, 101, 9 };
    klient->setSendeKey( (char *)key, 20 );
    klient->setEmpfangKey( (char *)key, 20 );
    this->appS = appS;
    accountId = 0;
    tmo = new AppSKTimeOut( this );
}

// Destruktor 
AppSKlient::~AppSKlient()
{
    tmo->stop();
    tmo->warteAufThread( 1000 );
    delete tmo;
    appS->clientTrennung();
    appS->release();
    klient->release();
    std::cout << "Client Deleted aktuell:" << appS->getClients() << "\n";
}

// nicht constant 
void AppSKlient::thread()
{
    while( 1 )
    {
        char c = 0;
        if( !klient->getNachrichtEncrypted( &c, 1 ) )
            break;
        else
        {
            tmo->addConnect();
            bool br = 0;
            switch( c )
            {
            case 0: // Schlüssel Anfrage
                if( 1 )
                {
                    Text *s = appS->zDB()->getKey();
                    if( s )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                    {
                        errorZuKlient( "Fehler beim Aufbauen der verschlüsselten Verbindung zum Server." );
                        break;
                    }
                    char l = (char)s->getLength();
                    klient->sendeEncrypted( &l, 1 );
                    klient->sendeEncrypted( s->getText(), l );
                    klient->setSendeKey( s->getText(), s->getLength() );
                    klient->setEmpfangKey( s->getText(), s->getLength() );
                    s->release();
                    break;
                }
            case 1: // Login 5 Minigames
                if( 1 )
                {
                    klient->sendeEncrypted( "\1", 1 );
                    unsigned char l = 0;
                    klient->getNachrichtEncrypted( (char *)& l, 1 );
                    char *name = new char[ l + 1 ];
                    name[ (int)l ] = 0;
                    if( l )
                        klient->getNachrichtEncrypted( name, l );
                    klient->getNachrichtEncrypted( (char *)& l, 1 );
                    char *passwort = new char[ l + 1 ];
                    passwort[ (int)l ] = 0;
                    if( l )
                        klient->getNachrichtEncrypted( passwort, l );
                    accountId = appS->zDB()->login( name, passwort );
                    delete[] name;
                    delete[] passwort;
                    if( accountId > 0 )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                        klient->sende( "\0", 1 );
                    if( accountId &&appS->zDB()->istNeu( accountId ) )
                        klient->sendeEncrypted( "\1", 1 );
                    else if( accountId )
                        klient->sendeEncrypted( "\0", 1 );
                    break;
                }
            case 2: // Frage nach Welt Blöcke Score
                if( 1 )
                {
                    klient->sendeEncrypted( "\1", 1 );
                    int num = 0;
                    klient->getNachrichtEncrypted( (char *)& num, 4 );
                    Array< int > *score = new Array< int >();
                    RCArray< Text > *namen = new RCArray< Text >();
                    num = appS->zDB()->getWeltBloeckeScore( num, score, namen );
                    klient->sendeEncrypted( (char *)& num, 4 );
                    for( int i = 0; i < num; i++ )
                    {
                        int s = score->get( i );
                        klient->sendeEncrypted( (char *)& s, 4 );
                        char l = (char)namen->z( i )->getLength();
                        klient->sendeEncrypted( &l, 1 );
                        klient->sendeEncrypted( namen->z( i )->getText(), l );
                    }
                    score->release();
                    namen->release();
                    break;
                }
            case 3: // Frage nach Welt Mauer Score
                if( 1 )
                {
                    klient->sendeEncrypted( "\1", 1 );
                    int num = 0;
                    klient->getNachrichtEncrypted( (char *)& num, 4 );
                    Array< int > *score = new Array< int >();
                    RCArray< Text > *namen = new RCArray< Text >();
                    num = appS->zDB()->getWeltMauerScore( num, score, namen );
                    klient->sendeEncrypted( (char *)& num, 4 );
                    for( int i = 0; i < num; i++ )
                    {
                        int s = score->get( i );
                        klient->sendeEncrypted( (char *)& s, 4 );
                        char l = (char)namen->z( i )->getLength();
                        klient->sendeEncrypted( &l, 1 );
                        klient->sendeEncrypted( namen->z( i )->getText(), l );
                    }
                    score->release();
                    namen->release();
                    break;
                }
            case 4: // Frage nach Welt Farben Score
                if( 1 )
                {
                    klient->sendeEncrypted( "\1", 1 );
                    int num = 0;
                    klient->getNachrichtEncrypted( (char *)& num, 4 );
                    Array< int > *score = new Array< int >();
                    RCArray< Text > *namen = new RCArray< Text >();
                    num = appS->zDB()->getWeltFarbenScore( num, score, namen );
                    klient->sendeEncrypted( (char *)& num, 4 );
                    for( int i = 0; i < num; i++ )
                    {
                        int s = score->get( i );
                        klient->sendeEncrypted( (char *)& s, 4 );
                        char l = (char)namen->z( i )->getLength();
                        klient->sendeEncrypted( &l, 1 );
                        klient->sendeEncrypted( namen->z( i )->getText(), l );
                    }
                    score->release();
                    namen->release();
                    break;
                }
            case 5: // Frage nach Welt Fangen Score
                if( 1 )
                {
                    klient->sendeEncrypted( "\1", 1 );
                    int num = 0;
                    klient->getNachrichtEncrypted( (char *)& num, 4 );
                    Array< int > *score = new Array< int >();
                    RCArray< Text > *namen = new RCArray< Text >();
                    num = appS->zDB()->getWeltFangenScore( num, score, namen );
                    klient->sendeEncrypted( (char *)& num, 4 );
                    for( int i = 0; i < num; i++ )
                    {
                        int s = score->get( i );
                        klient->sendeEncrypted( (char *)& s, 4 );
                        char l = (char)namen->z( i )->getLength();
                        klient->sendeEncrypted( &l, 1 );
                        klient->sendeEncrypted( namen->z( i )->getText(), l );
                    }
                    score->release();
                    namen->release();
                    break;
                }
            case 6: // Frage nach Welt Rennen Score
                if( 1 )
                {
                    klient->sendeEncrypted( "\1", 1 );
                    int num = 0;
                    klient->getNachrichtEncrypted( (char *)& num, 4 );
                    Array< int > *score = new Array< int >();
                    RCArray< Text > *namen = new RCArray< Text >();
                    num = appS->zDB()->getWeltRennenScore( num, score, namen );
                    klient->sendeEncrypted( (char *)& num, 4 );
                    for( int i = 0; i < num; i++ )
                    {
                        int s = score->get( i );
                        klient->sendeEncrypted( (char *)& s, 4 );
                        char l = (char)namen->z( i )->getLength();
                        klient->sendeEncrypted( &l, 1 );
                        klient->sendeEncrypted( namen->z( i )->getText(), l );
                    }
                    score->release();
                    namen->release();
                    break;
                }
            case 7: // Frage nach Welt Gesamt Score
                if( 1 )
                {
                    klient->sendeEncrypted( "\1", 1 );
                    int num = 0;
                    klient->getNachrichtEncrypted( (char *)& num, 4 );
                    Array< int > *score = new Array< int >();
                    RCArray< Text > *namen = new RCArray< Text >();
                    num = appS->zDB()->getWeltGesamtScore( num, score, namen );
                    klient->sendeEncrypted( (char *)& num, 4 );
                    for( int i = 0; i < num; i++ )
                    {
                        int s = score->get( i );
                        klient->sendeEncrypted( (char *)& s, 4 );
                        char l = (char)namen->z( i )->getLength();
                        klient->sendeEncrypted( &l, 1 );
                        klient->sendeEncrypted( namen->z( i )->getText(), l );
                    }
                    score->release();
                    namen->release();
                    break;
                }
            case 8: // Frage nach Blöcke Score
                if( 1 )
                {
                    if( accountId )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                    {
                        klient->sendeEncrypted( "\0", 1 );
                        break;
                    }
                    int score = appS->zDB()->getBloeckeScore( accountId );
                    klient->sendeEncrypted( (char *)& score, 4 );
                    break;
                }
            case 9: // Frage nach Mauer Score
                if( 1 )
                {
                    if( accountId )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                    {
                        klient->sendeEncrypted( "\0", 1 );
                        break;
                    }
                    int score = appS->zDB()->getMauerScore( accountId );
                    klient->sendeEncrypted( (char *)& score, 4 );
                    break;
                }
            case 10: // Frage nach Farben Score
                if( 1 )
                {
                    if( accountId )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                    {
                        klient->sendeEncrypted( "\0", 1 );
                        break;
                    }
                    int score = appS->zDB()->getFarbenScore( accountId );
                    klient->sendeEncrypted( (char *)& score, 4 );
                    break;
                }
            case 11: // Frage nach Fangen Score
                if( 1 )
                {
                    if( accountId )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                    {
                        klient->sendeEncrypted( "\0", 1 );
                        break;
                    }
                    int score = appS->zDB()->getFangenScore( accountId );
                    klient->sendeEncrypted( (char *)& score, 4 );
                    break;
                }
            case 12: // Frage nach Rennen Score
                if( 1 )
                {
                    if( accountId )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                    {
                        klient->sendeEncrypted( "\0", 1 );
                        break;
                    }
                    int score = appS->zDB()->getRennenScore( accountId );
                    klient->sendeEncrypted( (char *)& score, 4 );
                    break;
                }
            case 13: // Frage nach Gesamt Score
                if( 1 )
                {
                    if( accountId )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                    {
                        klient->sendeEncrypted( "\0", 1 );
                        break;
                    }
                    int score = appS->zDB()->getGesamtScore( accountId );
                    klient->sendeEncrypted( (char *)& score, 4 );
                    break;
                }
            case 14: // Frage nach Mauer Zeit
                if( 1 )
                {
                    if( accountId )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                    {
                        klient->sendeEncrypted( "\0", 1 );
                        break;
                    }
                    int level = 0;
                    klient->getNachrichtEncrypted( (char *)& level, 4 );
                    int sek = appS->zDB()->getMauerZeit( accountId, level );
                    klient->sendeEncrypted( (char *)& sek, 4 );
                    break;
                }
            case 15: // Set Blöcke Score
                if( 1 )
                {
                    if( accountId )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                    {
                        klient->sendeEncrypted( "\0", 1 );
                        break;
                    }
                    int score = 0;
                    klient->getNachrichtEncrypted( (char *)& score, 4 );
                    appS->zDB()->setBloeckeScore( accountId, score );
                    klient->sendeEncrypted( "\1", 1 );
                    break;
                }
            case 16: // Set Farben Score
                if( 1 )
                {
                    if( accountId )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                    {
                        klient->sendeEncrypted( "\0", 1 );
                        break;
                    }
                    int score = 0;
                    klient->getNachrichtEncrypted( (char *)& score, 4 );
                    appS->zDB()->setFarbenScore( accountId, score );
                    klient->sendeEncrypted( "\1", 1 );
                    break;
                }
            case 17: // Set Fangen Score
                if( 1 )
                {
                    if( accountId )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                    {
                        klient->sendeEncrypted( "\0", 1 );
                        break;
                    }
                    int score = 0;
                    klient->getNachrichtEncrypted( (char *)& score, 4 );
                    appS->zDB()->setFangenScore( accountId, score );
                    klient->sendeEncrypted( "\1", 1 );
                    break;
                }
            case 18: // Set Rennen Score
                if( 1 )
                {
                    if( accountId )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                    {
                        klient->sendeEncrypted( "\0", 1 );
                        break;
                    }
                    int score = 0;
                    klient->getNachrichtEncrypted( (char *)& score, 4 );
                    appS->zDB()->setRennenScore( accountId, score );
                    klient->sendeEncrypted( "\1", 1 );
                    break;
                }
            case 19: // Set Mauer Zeit
                if( 1 )
                {
                    if( accountId )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                    {
                        klient->sendeEncrypted( "\0", 1 );
                        break;
                    }
                    int level = 0;
                    klient->getNachrichtEncrypted( (char *)& level, 4 );
                    int zeit = 0;
                    klient->getNachrichtEncrypted( (char *)& zeit, 4 );
                    appS->zDB()->setMauerZeit( accountId, level, zeit );
                    klient->sendeEncrypted( "\1", 1 );
                    break;
                }
            case 20: // Account erstellen
                if( 1 )
                {
                    klient->sendeEncrypted( "\1", 1 );
                    unsigned char len[ 4 ] = { 0, 0, 0, 0 };
                    klient->getNachrichtEncrypted( (char *)len, 4 );
                    char *acc_name = new char[ len[ 0 ] + 1 ];
                    acc_name[ len[ 0 ] ] = 0;
                    klient->getNachrichtEncrypted( acc_name, len[ 0 ] );
                    char *acc_pass = new char[ len[ 1 ] + 1 ];
                    acc_pass[ len[ 1 ] ] = 0;
                    klient->getNachrichtEncrypted( acc_pass, len[ 1 ] );
                    char *acc_geheim = new char[ len[ 2 ] + 1 ];
                    acc_geheim[ len[ 2 ] ] = 0;
                    klient->getNachrichtEncrypted( acc_geheim, len[ 2 ] );
                    char *acc_mail = new char[ len[ 3 ] + 1 ];
                    acc_mail[ len[ 3 ] ] = 0;
                    klient->getNachrichtEncrypted( acc_mail, len[ 3 ] );
                    unsigned short acc_geb_jahr = 0;
                    klient->getNachrichtEncrypted( (char *)& acc_geb_jahr, 2 );
                    char acc_geb_monat = 0;
                    klient->getNachrichtEncrypted( &acc_geb_monat, 1 );
                    char acc_geb_tag = 0;
                    klient->getNachrichtEncrypted( &acc_geb_tag, 1 );
                    int pres = appS->zDB()->pruefNeuAccount( acc_name, acc_mail );
                    if( !pres )
                    {
                        Text *gebDatum = new Text( "" );
                        gebDatum->append( (int)acc_geb_jahr );
                        gebDatum->append( "-" );
                        gebDatum->append( (int)acc_geb_monat );
                        gebDatum->append( "-" );
                        gebDatum->append( (int)acc_geb_tag );
                        if( !appS->zDB()->neuAccount( acc_name, acc_pass, acc_geheim, acc_mail, gebDatum->getText(), appS->zIni() ) )
                            klient->sendeEncrypted( "\0", 1 );
                        else
                            klient->sendeEncrypted( "\1", 1 );
                        gebDatum->release();
                    }
                    else
                        klient->sendeEncrypted( "\0", 1 );
                    delete[]acc_name;
                    delete[]acc_pass;
                    delete[]acc_geheim;
                    delete[]acc_mail;
                }
                break;
            case 22: // Trennen
                klient->sendeEncrypted( "\1", 1 );
                br = 1;
                break;
            case 23: // Mark Balls finish
                if( 1 )
                {
                    klient->sendeEncrypted( "\1", 1 );
                    int level = 0;
                    klient->getNachrichtEncrypted( (char *)& level, 4 );
                    int sek = 0;
                    klient->getNachrichtEncrypted( (char *)& sek, 4 );
                    if( accountId )
                        appS->zDB()->markballsFinish( level, sek, accountId, 0, 0, 0, 0 );
                    else
                    {
                        unsigned char l = 0;
                        klient->getNachrichtEncrypted( (char *)& l, 1 );
                        char *device = new char[ l + 1 ];
                        device[ (int)l ] = 0;
                        klient->getNachrichtEncrypted( device, l );
                        appS->zDB()->markballsFinish( level, sek, accountId, device, 0, 0, 0 );
                        delete[] device;
                    }
                    klient->sendeEncrypted( "\1", 1 );
                    break;
                }
            case 24: // Get Mark Balls Score
                if( 1 )
                {
                    klient->sendeEncrypted( "\1", 1 );
                    Array< int > *level = new Array< int >();
                    Array< int > *score = new Array< int >();
                    RCArray< Text > *name = new RCArray< Text >();
                    int anz = appS->zDB()->getMarkballsScore( level, score, name, 0 );
                    klient->sendeEncrypted( (char *)& anz, 4 );
                    for( int i = 0; i < anz; i++ )
                    {
                        int l = level->get( i );
                        klient->sendeEncrypted( (char *)& l, 4 );
                        int s = score->get( i );
                        klient->sendeEncrypted( (char *)& s, 4 );
                        char nl = (char)name->z( i )->getLength();
                        klient->sendeEncrypted( &nl, 1 );
                        if( nl )
                            klient->sendeEncrypted( name->z( i )->getText(), nl );
                    }
                    level->release();
                    score->release();
                    name->release();
                    break;
                }
            case 25: // Login Mark Balls
                if( 1 )
                {
                    klient->sendeEncrypted( "\1", 1 );
                    unsigned char l = 0;
                    klient->getNachrichtEncrypted( (char *)& l, 1 );
                    char *name = new char[ l + 1 ];
                    name[ (int)l ] = 0;
                    if( l )
                        klient->getNachrichtEncrypted( name, l );
                    klient->getNachrichtEncrypted( (char *)& l, 1 );
                    char *passwort = new char[ l + 1 ];
                    passwort[ (int)l ] = 0;
                    if( l )
                        klient->getNachrichtEncrypted( passwort, l );
                    klient->getNachrichtEncrypted( (char *)& l, 1 );
                    char *device = new char[ l + 1 ];
                    device[ (int)l ] = 0;
                    if( l )
                        klient->getNachrichtEncrypted( device, l );
                    accountId = appS->zDB()->login( name, passwort );
                    delete[] name;
                    delete[] passwort;
                    if( accountId > 0 )
                    {
                        appS->zDB()->deviceAccount( device, accountId );
                        klient->sendeEncrypted( "\1", 1 );
                    }
                    else
                        klient->sende( "\0", 1 );
                    delete[] device;
                    break;
                }
            case 26: // Mark Balls finish NEW
                if( 1 )
                {
                    klient->sendeEncrypted( "\1", 1 );
                    int level = 0;
                    klient->getNachrichtEncrypted( (char *)& level, 4 );
                    int sek = 0;
                    klient->getNachrichtEncrypted( (char *)& sek, 4 );
                    int diff = 0;
                    klient->getNachrichtEncrypted( (char *)& diff, 4 );
                    int gId = 0;
                    klient->getNachrichtEncrypted( (char *)& gId, 4 );
                    if( accountId )
                    {
                        int kupfer = 0;
                        klient->getNachrichtEncrypted( (char *)& kupfer, 4 );
                        appS->zDB()->markballsFinish( level, sek, accountId, 0, diff, kupfer, gId );
                    }
                    else
                    {
                        unsigned char l = 0;
                        klient->getNachrichtEncrypted( (char *)& l, 1 );
                        char *device = new char[ l + 1 ];
                        device[ (int)l ] = 0;
                        klient->getNachrichtEncrypted( device, l );
                        appS->zDB()->markballsFinish( level, sek, accountId, device, diff, 0, gId );
                        delete[] device;
                    }
                    klient->sendeEncrypted( "\1", 1 );
                    break;
                }
            case 27: // Get Mark Balls Score NEW
                if( 1 )
                {
                    klient->sendeEncrypted( "\1", 1 );
                    int diff = 0;
                    klient->getNachrichtEncrypted( (char *)& diff, 4 );
                    Array< int > *level = new Array< int >();
                    Array< int > *score = new Array< int >();
                    int anz = appS->zDB()->getMarkballsScore( level, score, diff );
                    klient->sendeEncrypted( (char *)& anz, 4 );
                    for( int i = 0; i < anz; i++ )
                    {
                        int l = level->get( i );
                        klient->sendeEncrypted( (char *)& l, 4 );
                        int s = score->get( i );
                        klient->sendeEncrypted( (char *)& s, 4 );
                    }
                    level->release();
                    score->release();
                    break;
                }
            case 28: // Get gegenstand Liste
                if( 1 )
                {
                    klient->sendeEncrypted( "\1", 1 );
                    Array< int > *gId = new Array< int >();
                    Array< int > *diff = new Array< int >();
                    int anz = 0;
                    if( accountId )
                        anz = appS->zDB()->getGegenstaende( accountId, 0, gId, diff );
                    else
                    {
                        unsigned char l = 0;
                        klient->getNachrichtEncrypted( (char *)& l, 1 );
                        char *device = new char[ l + 1 ];
                        device[ (int)l ] = 0;
                        klient->getNachrichtEncrypted( device, l );
                        anz = appS->zDB()->getGegenstaende( 0, device, gId, diff );
                        delete[] device;
                    }
                    klient->sendeEncrypted( (char *)& anz, 4 );
                    for( int i = 0; i < anz; i++ )
                    {
                        int g = gId->get( i );
                        klient->sendeEncrypted( (char *)& g, 4 );
                        int d = diff->get( i );
                        klient->sendeEncrypted( (char *)& d, 4 );
                    }
                    gId->release();
                    diff->release();
                    break;
                }
            case 29: // Get Kupfer
                if( 1 )
                {
                    if( !accountId )
                        klient->sendeEncrypted( "\0", 1 );
                    else
                    {
                        klient->sendeEncrypted( "\1", 1 );
                        int ret = appS->zDB()->getKupfer( accountId );
                        klient->sendeEncrypted( (char *)& ret, 4 );
                    }
                    break;
                }
            case 30: // Get Markballs Fortschritt
                if( 1 )
                {
                    klient->sendeEncrypted( "\1", 1 );
                    Array< int > *fortschritt = new Array< int >();
                    int anz = 0;
                    if( accountId )
                        anz = appS->zDB()->getMarkballsFortschritt( accountId, 0, fortschritt );
                    else
                    {
                        unsigned char l = 0;
                        klient->getNachrichtEncrypted( (char *)& l, 1 );
                        char *device = new char[ l + 1 ];
                        device[ (int)l ] = 0;
                        klient->getNachrichtEncrypted( device, l );
                        anz = appS->zDB()->getMarkballsFortschritt( 0, device, fortschritt );
                        delete[] device;
                    }
                    klient->sendeEncrypted( (char *)& anz, 4 );
                    for( int i = 0; i < anz; i++ )
                    {
                        int f = fortschritt->get( i );
                        klient->sendeEncrypted( (char *)& f, 4 );
                    }
                    fortschritt->release();
                    break;
                }
            case 31: // Global Login
            {
                klient->sendeEncrypted( "\1", 1 );
                unsigned char l = 0;
                klient->getNachrichtEncrypted( (char *)& l, 1 );
                char *name = new char[ l + 1 ];
                name[ (int)l ] = 0;
                if( l )
                    klient->getNachrichtEncrypted( name, l );
                klient->getNachrichtEncrypted( (char *)& l, 1 );
                char *passwort = new char[ l + 1 ];
                passwort[ (int)l ] = 0;
                if( l )
                    klient->getNachrichtEncrypted( passwort, l );
                klient->getNachrichtEncrypted( (char *)& l, 1 );
                char *device = new char[ l + 1 ];
                device[ (int)l ] = 0;
                if( l )
                    klient->getNachrichtEncrypted( device, l );
                accountId = appS->zDB()->login( name, passwort );
                delete[] name;
                delete[] passwort;
                if( accountId > 0 )
                    klient->sendeEncrypted( "\1", 1 );
                else
                    klient->sende( "\0", 1 );
                delete[] device;
                break;
            }
            case 35: // Add Kupfer
            {
                if( accountId )
                {
                    klient->sendeEncrypted( "\1", 1 );
                    int kupfer = 0;
                    klient->getNachrichtEncrypted( (char *)& kupfer, 4 );
                    appS->zDB()->addKupfer( accountId, kupfer );
                }
                else
                    klient->sendeEncrypted( "\0", 1 );
                break;
            }
            case 36: // getFreeAds
            {
                if( accountId )
                {
                    if( appS->zDB()->getFreeAds( accountId ) )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                        klient->sendeEncrypted( "\0", 1 );
                }
                else
                    klient->sendeEncrypted( "\0", 1 );
                break;
            }
            case 37: // keppAlive
            {
                klient->sendeEncrypted( "\1", 1 );
                break;
            }
            default:
                klient->sendeEncrypted( "\0", 1 );
                br = true;
                break;
            }
            if( br )
                break;
            appS->addEmpfangen( klient->getDownloadBytes( 1 ) );
            appS->addGesendet( klient->getUploadBytes( 1 ) );
        }
    }
    appS->addEmpfangen( klient->getDownloadBytes( 1 ) );
    appS->addGesendet( klient->getUploadBytes( 1 ) );
    delete this;
}

void AppSKlient::timeout()
{
    klient->trenne();
}

void AppSKlient::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 AppSKTimeOut Klasse aus AppServer.h
// Konstruktor
AppSKTimeOut::AppSKTimeOut( AppSKlient * zK )
{
    zKlient = zK;
    zm = new ZeitMesser();
    zm->messungStart();
    st = 0;
    start();
}

// Destruktor
AppSKTimeOut::~AppSKTimeOut()
{
    zm->release();
}

// nicht constant
void AppSKTimeOut::thread()
{
    while( !st )
    {
        zm->messungEnde();
        if( zm->getSekunden() > 10 )
            zKlient->timeout();
        for( int i = 0; i < 300 && !st; i++ )
            Sleep( 100 );
    }
}

void AppSKTimeOut::stop()
{
    st = 1;
}

void AppSKTimeOut::addConnect()
{
    zm->messungStart();
}