#include "Datenbank.h"
#include <iostream>
#include <Datei.h>

#ifndef WIN32
#include <spawn.h>
#endif

// Inhalt der AppSDatenbank Klasse aus Datenbank.h
// Konstruktor
AppSDatenbank::AppSDatenbank( InitDatei *zDat )
{
    datenbank = new Datenbank( zDat->zWert( "DBBenutzer" )->getText(), zDat->zWert( "DBPasswort" )->getText(),
                               zDat->zWert( "DBName" )->getText(), zDat->zWert( "DBIP" )->getText(),
                               (unsigned short)TextZuInt( zDat->zWert( "DBPort" )->getText(), 10 ) );
    if( !datenbank->istOk() )
    {
        std::cout << "AppS: Es konnte keine Verbindung zur Datenbank hergestellt werden:\n";
        Text *txt = datenbank->getLetzterFehler();
        std::cout << txt->getText() << "\nDas Programm wird beendet.";
        txt->release();
        exit( 1 );
    }
    InitializeCriticalSection( &ths );
    ref = 1;
    Text befehl = "SELECT port, admin_port FROM server WHERE id = ";
    befehl += zDat->zWert( "ServerId" )->getText();
    lock();
    datenbank->befehl( befehl );
    Result res = datenbank->getResult();
    unlock();
    if( res.zeilenAnzahl == 1 )
    {
        zDat->addWert( "AppSPort", res.values[ 0 ] );
        zDat->addWert( "AppSAPort", res.values[ 1 ] );
    }
    res.destroy();
}

// Detruktor
AppSDatenbank::~AppSDatenbank()
{
    datenbank->release();
    DeleteCriticalSection( &ths );
}

// nicht constant
void AppSDatenbank::lock()
{
    EnterCriticalSection( &ths );
}

void AppSDatenbank::unlock()
{
    LeaveCriticalSection( &ths );
}

int AppSDatenbank::istAdministrator( const char *name, const char *passwort )
{
    Text *befehl = new Text( "SELECT id FROM benutzer WHERE name = '" );
    Text n( name );
    n.ersetzen( "'", "''" );
    befehl->append( (char*)n );
    befehl->append( "' AND passwort = md5('" );
    Text p( passwort );
    p.ersetzen( "'", "''" );
    befehl->append( (char*)p );
    befehl->append( "')" );
    lock();
    datenbank->befehl( befehl->getText() );
    Result res = datenbank->getResult();
    unlock();
    befehl->release();
    int ret = 0;
    if( res.zeilenAnzahl > 0 )
        ret = TextZuInt( res.values[ 0 ].getText(), 10 );
    res.destroy();
    return ret;
}

bool AppSDatenbank::adminHatRecht( int id, int recht )
{
    Text *befehl = new Text( "SELECT * FROM benutzer_rechte WHERE benutzer_id = " );
    befehl->append( id );
    befehl->append( " AND rechte_id = " );
    befehl->append( recht );
    lock();
    datenbank->befehl( befehl->getText() );
    int ret = datenbank->getZeilenAnzahl();
    unlock();
    befehl->release();
    return ret != 0;
}

Text *AppSDatenbank::getKey()
{
    lock();
    datenbank->befehl( "SELECT get_next_schluessel()" );
    Result res = datenbank->getResult();
    unlock();
    if( !res.zeilenAnzahl )
        return 0;
    Text *ret = new Text( res.values[ 0 ].getText() );
    res.destroy();
    return ret;
}

int AppSDatenbank::login( char *name, char *passwort )
{
    Text befehl = "SELECT id FROM account WHERE name = '";
    befehl += name;
    befehl += "' AND passwort = md5('";
    befehl += passwort;
    befehl += "')";
    lock();
    datenbank->befehl( befehl );
    Result res = datenbank->getResult();
    unlock();
    if( !res.zeilenAnzahl )
        return 0;
    int ret = res.values[ 0 ];
    res.destroy();
    return ret;
}

bool AppSDatenbank::istNeu( int account )
{
    Text befehl = "SELECT * from app_5_minigames_score WHERE account_id = ";
    befehl += account;
    lock();
    datenbank->befehl( befehl );
    int zeilen = datenbank->getZeilenAnzahl();
    unlock();
    return zeilen == 0;
}

int AppSDatenbank::getWeltBloeckeScore( int anz, Array< int > *score, RCArray< Text > *namen )
{
    Text befehl = "SELECT a.bloecke, b.ruf_name FROM app_5_minigames_score a, account b WHERE b.id = a.account_id ORDER BY a.bloecke DESC LIMIT ";
    befehl += anz;
    lock();
    datenbank->befehl( befehl );
    Result res = datenbank->getResult();
    unlock();
    int ret = res.zeilenAnzahl;
    for( int i = 0; i < ret; i++ )
    {
        score->set( res.values[ i * 2 ], i );
        namen->set( new Text( res.values[ i * 2 + 1 ].getText() ), i );
    }
    res.destroy();
    return ret;
}

int AppSDatenbank::getWeltMauerScore( int anz, Array< int > *score, RCArray< Text > *namen )
{
    Text befehl = "SELECT a.mauer, b.ruf_name FROM app_5_minigames_score a, account b WHERE b.id = a.account_id ORDER BY a.mauer DESC LIMIT ";
    befehl += anz;
    lock();
    datenbank->befehl( befehl );
    Result res = datenbank->getResult();
    unlock();
    int ret = res.zeilenAnzahl;
    for( int i = 0; i < ret; i++ )
    {
        score->set( res.values[ i * 2 ], i );
        namen->set( new Text( res.values[ i * 2 + 1 ].getText() ), i );
    }
    res.destroy();
    return ret;
}

int AppSDatenbank::getWeltFarbenScore( int anz, Array< int > *score, RCArray< Text > *namen )
{
    Text befehl = "SELECT a.farben, b.ruf_name FROM app_5_minigames_score a, account b WHERE b.id = a.account_id ORDER BY a.farben DESC LIMIT ";
    befehl += anz;
    lock();
    datenbank->befehl( befehl );
    Result res = datenbank->getResult();
    unlock();
    int ret = res.zeilenAnzahl;
    for( int i = 0; i < ret; i++ )
    {
        score->set( res.values[ i * 2 ], i );
        namen->set( new Text( res.values[ i * 2 + 1 ].getText() ), i );
    }
    res.destroy();
    return ret;
}

int AppSDatenbank::getWeltFangenScore( int anz, Array< int > *score, RCArray< Text > *namen )
{
    Text befehl = "SELECT a.fangen, b.ruf_name FROM app_5_minigames_score a, account b WHERE b.id = a.account_id ORDER BY a.fangen DESC LIMIT ";
    befehl += anz;
    lock();
    datenbank->befehl( befehl );
    Result res = datenbank->getResult();
    unlock();
    int ret = res.zeilenAnzahl;
    for( int i = 0; i < ret; i++ )
    {
        score->set( res.values[ i * 2 ], i );
        namen->set( new Text( res.values[ i * 2 + 1 ].getText() ), i );
    }
    res.destroy();
    return ret;
}

int AppSDatenbank::getWeltRennenScore( int anz, Array< int > *score, RCArray< Text > *namen )
{
    Text befehl = "SELECT a.rennen, b.ruf_name FROM app_5_minigames_score a, account b WHERE b.id = a.account_id ORDER BY a.rennen DESC LIMIT ";
    befehl += anz;
    lock();
    datenbank->befehl( befehl );
    Result res = datenbank->getResult();
    unlock();
    int ret = res.zeilenAnzahl;
    for( int i = 0; i < ret; i++ )
    {
        score->set( res.values[ i * 2 ], i );
        namen->set( new Text( res.values[ i * 2 + 1 ].getText() ), i );
    }
    res.destroy();
    return ret;
}

int AppSDatenbank::getWeltGesamtScore( int anz, Array< int > *score, RCArray< Text > *namen )
{
    Text befehl = "SELECT a.gesamt, b.ruf_name FROM app_5_minigames_score a, account b WHERE b.id = a.account_id ORDER BY a.gesamt DESC LIMIT ";
    befehl += anz;
    lock();
    datenbank->befehl( befehl );
    Result res = datenbank->getResult();
    unlock();
    int ret = res.zeilenAnzahl;
    for( int i = 0; i < ret; i++ )
    {
        score->set( res.values[ i * 2 ], i );
        namen->set( new Text( res.values[ i * 2 + 1 ].getText() ), i );
    }
    res.destroy();
    return ret;
}

int AppSDatenbank::getBloeckeScore( int account )
{
    Text befehl = "SELECT bloecke FROM app_5_minigames_score WHERE account_id = ";
    befehl += account;
    lock();
    datenbank->befehl( befehl );
    Result res = datenbank->getResult();
    unlock();
    if( !res.zeilenAnzahl )
        return 0;
    int ret = res.values[ 0 ];
    res.destroy();
    return ret;
}

int AppSDatenbank::getMauerScore( int account )
{
    Text befehl = "SELECT mauer FROM app_5_minigames_score WHERE account_id = ";
    befehl += account;
    lock();
    datenbank->befehl( befehl );
    Result res = datenbank->getResult();
    unlock();
    if( !res.zeilenAnzahl )
        return 0;
    int ret = res.values[ 0 ];
    res.destroy();
    return ret;
}

int AppSDatenbank::getMauerZeit( int account, int level )
{
    Text befehl = "SELECT sekunden FROM app_5_minigames_mauer_score WHERE account_id = ";
    befehl += account;
    befehl += " AND level = ";
    befehl += level;
    lock();
    datenbank->befehl( befehl );
    Result res = datenbank->getResult();
    unlock();
    if( !res.zeilenAnzahl )
        return 0;
    int ret = res.values[ 0 ];
    res.destroy();
    return ret;
}

int AppSDatenbank::getFarbenScore( int account )
{
    Text befehl = "SELECT farben FROM app_5_minigames_score WHERE account_id = ";
    befehl += account;
    lock();
    datenbank->befehl( befehl );
    Result res = datenbank->getResult();
    unlock();
    if( !res.zeilenAnzahl )
        return 0;
    int ret = res.values[ 0 ];
    res.destroy();
    return ret;
}

int AppSDatenbank::getFangenScore( int account )
{
    Text befehl = "SELECT fangen FROM app_5_minigames_score WHERE account_id = ";
    befehl += account;
    lock();
    datenbank->befehl( befehl );
    Result res = datenbank->getResult();
    unlock();
    if( !res.zeilenAnzahl )
        return 0;
    int ret = res.values[ 0 ];
    res.destroy();
    return ret;
}

int AppSDatenbank::getRennenScore( int account )
{
    Text befehl = "SELECT rennen FROM app_5_minigames_score WHERE account_id = ";
    befehl += account;
    lock();
    datenbank->befehl( befehl );
    Result res = datenbank->getResult();
    unlock();
    if( !res.zeilenAnzahl )
        return 0;
    int ret = res.values[ 0 ];
    res.destroy();
    return ret;
}

int AppSDatenbank::getGesamtScore( int account )
{
    Text befehl = "SELECT gesamt FROM app_5_minigames_score WHERE account_id = ";
    befehl += account;
    lock();
    datenbank->befehl( befehl );
    Result res = datenbank->getResult();
    unlock();
    if( !res.zeilenAnzahl )
        return 0;
    int ret = res.values[ 0 ];
    res.destroy();
    return ret;
}

void AppSDatenbank::setBloeckeScore( int account, int score )
{
    if( score < getBloeckeScore( account ) )
        return;
    Text befehl = "UPDATE app_5_minigames_score SET bloecke = ";
    befehl += score;
    befehl += " WHERE account_id = ";
    befehl += account;
    lock();
    datenbank->befehl( befehl );
    int z = datenbank->getZeilenAnzahl();
    unlock();
    if( !z )
    {
        befehl = "INSERT INTO app_5_minigames_score( bloecke, account_id ) VALUES( ";
        befehl += score;
        befehl += ", ";
        befehl += account;
        befehl += " )";
        lock();
        datenbank->befehl( befehl );
        unlock();
    }
    calkGesamtScore( account );
}

void AppSDatenbank::setFarbenScore( int account, int score )
{
    if( score < getFarbenScore( account ) )
        return;
    Text befehl = "UPDATE app_5_minigames_score SET farben = ";
    befehl += score;
    befehl += " WHERE account_id = ";
    befehl += account;
    lock();
    datenbank->befehl( befehl );
    int z = datenbank->getZeilenAnzahl();
    unlock();
    if( !z )
    {
        befehl = "INSERT INTO app_5_minigames_score( farben, account_id ) VALUES( ";
        befehl += score;
        befehl += ", ";
        befehl += account;
        befehl += " )";
        lock();
        datenbank->befehl( befehl );
        unlock();
    }
    calkGesamtScore( account );
}

void AppSDatenbank::setFangenScore( int account, int score )
{
    if( score < getFangenScore( account ) )
        return;
    Text befehl = "UPDATE app_5_minigames_score SET fangen = ";
    befehl += score;
    befehl += " WHERE account_id = ";
    befehl += account;
    lock();
    datenbank->befehl( befehl );
    int z = datenbank->getZeilenAnzahl();
    unlock();
    if( !z )
    {
        befehl = "INSERT INTO app_5_minigames_score( fangen, account_id ) VALUES( ";
        befehl += score;
        befehl += ", ";
        befehl += account;
        befehl += " )";
        lock();
        datenbank->befehl( befehl );
        unlock();
    }
    calkGesamtScore( account );
}

void AppSDatenbank::setRennenScore( int account, int score )
{
    if( score < getRennenScore( account ) )
        return;
    Text befehl = "UPDATE app_5_minigames_score SET rennen = ";
    befehl += score;
    befehl += " WHERE account_id = ";
    befehl += account;
    lock();
    datenbank->befehl( befehl );
    int z = datenbank->getZeilenAnzahl();
    unlock();
    if( !z )
    {
        befehl = "INSERT INTO app_5_minigames_score( rennen, account_id ) VALUES( ";
        befehl += score;
        befehl += ", ";
        befehl += account;
        befehl += " )";
        lock();
        datenbank->befehl( befehl );
        unlock();
    }
    calkGesamtScore( account );
}

void AppSDatenbank::setMauerZeit( int account, int level, int zeit )
{
    if( zeit > getMauerZeit( account, level ) && getMauerZeit( account, level ) != 0 )
        return;
    if( zeit > 600 )
        zeit = 600;
    Text befehl = "UPDATE app_5_minigames_mauer_score SET sekunden = ";
    befehl += zeit;
    befehl += " WHERE account_id = ";
    befehl += account;
    befehl += " AND level = ";
    befehl += level;
    lock();
    datenbank->befehl( befehl );
    int z = datenbank->getZeilenAnzahl();
    unlock();
    if( !z )
    {
        befehl = "INSERT INTO app_5_minigames_mauer_score( account_id, level, sekunden ) VALUES( ";
        befehl += account;
        befehl += ", ";
        befehl += level;
        befehl += ", ";
        befehl += zeit;
        befehl += " )";
        lock();
        datenbank->befehl( befehl );
        unlock();
    }
    calkMauerScore( account );
}

void AppSDatenbank::calkMauerScore( int account )
{
    Text befehl = "SELECT count( sekunden ), sum( sekunden ) FROM app_5_minigames_mauer_score WHERE account_id = ";
    befehl += account;
    lock();
    datenbank->befehl( befehl );
    Result res = datenbank->getResult();
    unlock();
    if( (int)res.values[ 0 ] == 0 )
        return;
    int score = (int)res.values[ 0 ] * 600 - (int)res.values[ 1 ];
    res.destroy();
    befehl = "UPDATE app_5_minigames_score SET mauer = ";
    befehl += score;
    befehl += " WHERE account_id = ";
    befehl += account;
    lock();
    datenbank->befehl( befehl );
    int z = datenbank->getZeilenAnzahl();
    unlock();
    if( !z )
    {
        befehl = "INSERT INTO app_5_minigames_score( mauer, account_id ) VALUES( ";
        befehl += score;
        befehl += ", ";
        befehl += account;
        befehl += " )";
        lock();
        datenbank->befehl( befehl );
        unlock();
    }
    calkGesamtScore( account );
}

void AppSDatenbank::calkGesamtScore( int account )
{
    Text befehl = "SELECT bloecke, mauer, farben, fangen, rennen FROM app_5_minigames_score WHERE account_id = ";
    befehl += account;
    lock();
    datenbank->befehl( befehl );
    Result res = datenbank->getResult();
    unlock();
    if( !res.zeilenAnzahl )
        return;
    int gesamt = ( (int)res.values[ 0 ] + (int)res.values[ 1 ] + (int)res.values[ 2 ] + (int)res.values[ 3 ] + (int)res.values[ 4 ] ) / 5;
    res.destroy();
    befehl = "UPDATE app_5_minigames_score SET gesamt = ";
    befehl += gesamt;
    befehl += " WHERE account_id = ";
    befehl += account;
    lock();
    datenbank->befehl( befehl );
    unlock();
}

int AppSDatenbank::pruefNeuAccount( const char *name, const char *eMail )
{
    Text *befehl = new Text( "SELECT account_neu_alt_check( '" );
    Text n( name );
    n.ersetzen( "'", "''" );
    befehl->append( (char*)n );
    befehl->append( "', '" );
    Text m( eMail );
    m.ersetzen( "'", "''" );
    befehl->append( (char*)m );
    befehl->append( "' )" );
    lock();
    datenbank->befehl( befehl->getText() );
    Result res = datenbank->getResult();
    unlock();
    if( res.values[ 0 ].istGleich( "t" ) )
    {
        befehl->release();
        res.destroy();
        return 0;
    }
    else
    {
        res.destroy();
        befehl->setText( "SELECT account.id FROM account, account_neu WHERE account.name = '" );
        befehl->append( (char*)n );
        befehl->append( "' OR account_neu.name = '" );
        befehl->append( (char*)n );
        befehl->append( "'" );
        lock();
        datenbank->befehl( befehl->getText() );
        res = datenbank->getResult();
        unlock();
        if( res.zeilenAnzahl > 0 )
        {
            befehl->release();
            res.destroy();
            return 1;
        }
        else
        {
            res.destroy();
            befehl->release();
            return 2;
        }
    }
}

bool AppSDatenbank::neuAccount( const char *name, const char *pass, const char *geheim, const char *eMail, const char *gebDatum, InitDatei *zIni )
{
    Text *befehl = new Text( "INSERT INTO account_neu( name, passwort, geheimnis, e_mail, geb_datum ) VALUES ( '" );
    Text n( name );
    n.ersetzen( "'", "''" );
    befehl->append( (char*)n );
    befehl->append( "', md5('" );
    Text p( pass );
    p.ersetzen( "'", "''" );
    befehl->append( (char*)p );
    befehl->append( "'), '" );
    Text g( geheim );
    g.ersetzen( "'", "''" );
    befehl->append( (char*)g );
    befehl->append( "', '" );
    Text m( eMail );
    m.ersetzen( "'", "''" );
    befehl->append( (char*)m );
    befehl->append( "', '" );
    Text d( gebDatum );
    d.ersetzen( "'", "''" );
    befehl->append( (char*)d );
    befehl->append( "' )" );
    lock();
    if( datenbank->befehl( befehl->getText() ) )
    {
        unlock();
        befehl->setText( "SELECT schluessel, id FROM account_neu WHERE name = '" );
        befehl->append( (char*)n );
        befehl->append( "'" );
        lock();
        datenbank->befehl( befehl->getText() );
        Result res = datenbank->getResult();
        unlock();
        if( res.zeilenAnzahl )
        {
            // e_mail senden
            pid_t pid;
            char *pargs[] = { zIni->zWert( "PHP" )->getText(), zIni->zWert( "AccountActivationMail" )->getText(), (char*)name, (char*)geheim, (char*)gebDatum, res.values[ 0 ].getText(), (char*)eMail, res.values[ 1 ].getText(), (char*)0 };
            posix_spawn( &pid, zIni->zWert( "PHP" )->getText(), 0, 0, pargs, 0 );
        }
        res.destroy();
        befehl->release();
        return 1;
    }
    unlock();
    befehl->release();
    return 0;
}

void AppSDatenbank::markballsFinish( int level, int sek, int account, char *device, int diff, int kupfer, int gId )
{
    if( !device && kupfer > 0 )
    {
        Text befehl = "UPDATE account SET kupfer = kupfer + ";
        befehl += kupfer;
        befehl += " WHERE id = ";
        befehl += account;
        lock();
        datenbank->befehl( befehl );
        unlock();
    }
    if( gId > 0 )
    {
        Text befehl = "SELECT markballs_gegenstand_id FROM markballs_gegenstand_account WHERE markballs_gegenstand_id = ";
        befehl += gId;
        befehl += " AND diff = ";
        befehl += diff;
        if( !device )
        {
            befehl += " AND account_id = ";
            befehl += account;
        }
        else
        {
            befehl += " AND device = '";
            befehl += device;
            befehl += "'";
        }
        lock();
        datenbank->befehl( befehl );
        int rows = datenbank->getZeilenAnzahl();
        unlock();
        if( !rows )
        {
            befehl = "INSERT INTO markballs_gegenstand_account( account_id, device, markballs_gegenstand_id, diff ) VALUES( ";
            if( !device )
            {
                befehl += account;
                befehl += ", NULL, ";
            }
            else
            {
                befehl += "NULL, '";
                befehl += device;
                befehl += "', ";
            }
            befehl += gId;
            befehl += ", ";
            befehl += diff;
            befehl += " )";
            lock();
            datenbank->befehl( befehl );
            unlock();
        }
    }
    Text befehl = "SELECT * FROM markballs WHERE level = ";
    befehl += level;
    befehl += " AND diff = ";
    befehl += diff;
    lock();
    datenbank->befehl( befehl );
    int rows = datenbank->getZeilenAnzahl();
    unlock();
    if( !rows )
    {
        befehl = "INSERT INTO markballs( level, diff ) VALUES( ";
        befehl += level;
        befehl += ", ";
        befehl += diff;
        befehl += " )";
        lock();
        datenbank->befehl( befehl );
        unlock();
    }
    Text spalte = "verloren";
    if( sek > 0 && sek <= 10 )
        spalte = "s_1_10";
    else if( sek > 10 && sek <= 20 )
        spalte = "s_11_20";
    else if( sek > 20 && sek <= 30 )
        spalte = "s_21_30";
    else if( sek > 30 && sek <= 40 )
        spalte = "s_31_40";
    else if( sek > 40 && sek <= 50 )
        spalte = "s_41_50";
    else if( sek > 50 && sek <= 60 )
        spalte = "s_51_60";
    else if( sek > 60 )
        spalte = "more";
    befehl = "UPDATE markballs SET ";
    befehl += spalte.getText();
    befehl += " = ";
    befehl += spalte.getText();
    befehl += " + 1, account_id = ";
    if( account )
        befehl += account;
    else
        befehl += "null";
    befehl += ", device = ";
    if( !device )
        befehl += "null";
    else
    {
        befehl += "'";
        befehl += device;
        befehl += "'";
    }
    befehl += ", best = ";
    befehl += sek;
    befehl += " WHERE level = ";
    befehl += level;
    befehl += " AND diff = ";
    befehl += diff;
    lock();
    datenbank->befehl( befehl );
    unlock();
}

int AppSDatenbank::getMarkballsScore( Array< int > *level, Array< int > *score, RCArray< Text > *name, int diff )
{
    Text befehl = "SELECT a.level, a.best, b.ruf_name from markballs a left join account b ON a.account_id = b.id WHERE a.diff = ";
    befehl += diff;
    lock();
    datenbank->befehl( befehl );
    Result res = datenbank->getResult();
    unlock();
    int ret = res.zeilenAnzahl;
    for( int i = 0; i < ret; i++ )
    {
        level->set( res.values[ i * 3 ], i );
        score->set( res.values[ i * 3 + 1 ], i );
        name->set( new Text( res.values[ i * 3 + 2 ].getText() ), i );
    }
    res.destroy();
    return ret;
}

int AppSDatenbank::getMarkballsScore( Array< int > *level, Array< int > *score, int diff )
{
    Text befehl = "SELECT level, best from markballs WHERE diff = ";
    befehl += diff;
    lock();
    datenbank->befehl( befehl );
    Result res = datenbank->getResult();
    unlock();
    int ret = res.zeilenAnzahl;
    for( int i = 0; i < ret; i++ )
    {
        level->set( res.values[ i * 2 ], i );
        score->set( res.values[ i * 2 + 1 ], i );
    }
    res.destroy();
    return ret;
}

void AppSDatenbank::deviceAccount( char *device, int account )
{
    Text befehl = "UPDATE markballs SET account_id = ";
    befehl += account;
    befehl += ", device = null WHERE account_id IS NULL AND device = '";
    befehl += device;
    befehl += "'";
    lock();
    datenbank->befehl( befehl );
    unlock();
    befehl = "SELECT app_device_to_account( '";
    befehl += device;
    befehl += "', ";
    befehl += account;
    befehl += " )";
    lock();
    datenbank->befehl( befehl );
    unlock();
    befehl = "UPDATE markballs_fortschritt SET account_id = ";
    befehl += account;
    befehl += ", device = null WHERE account_id IS NULL AND device = '";
    befehl += device;
    befehl += "'";
    lock();
    datenbank->befehl( befehl );
    unlock();
    befehl = "UPDATE markballs_gegenstand_account SET account_id = ";
    befehl += account;
    befehl += ", device = null WHERE account_id IS NULL AND device = '";
    befehl += device;
    befehl += "'";
    lock();
    datenbank->befehl( befehl );
    unlock();
}

int AppSDatenbank::getGegenstaende( int accountId, char *device, Array< int > *gId, Array< int > *diff )
{
    Text befehl = "SELECT markballs_gegenstand_id, diff FROM markballs_gegenstand_account WHERE ";
    if( !device )
    {
        befehl += " account_id = ";
        befehl += accountId;
    }
    else
    {
        befehl += " device = '";
        befehl += device;
        befehl += "'";
    }
    lock();
    datenbank->befehl( befehl );
    Result r = datenbank->getResult();
    unlock();
    if( !r.zeilenAnzahl )
    {
        r.destroy();
        return 0;
    }
    for( int i = 0; i < r.zeilenAnzahl; i++ )
    {
        gId->add( (int)r.values[ i * 2 ] );
        diff->add( (int)r.values[ i * 2 + 1 ] );
    }
    int ret = r.zeilenAnzahl;
    r.destroy();
    return ret;
}

int AppSDatenbank::getKupfer( int accountId )
{
    Text befehl = "SELECT kupfer FROM account WHERE id = ";
    befehl += accountId;
    lock();
    datenbank->befehl( befehl );
    Result r = datenbank->getResult();
    unlock();
    int ret = r.zeilenAnzahl ? (int)r.values[ 0 ] : 0;
    r.destroy();
    return ret;
}

int AppSDatenbank::getMarkballsFortschritt( int accountId, char *device, Array< int > *f )
{
    Text befehl = "SELECT level, diff FROM markballs_fortschritt WHERE ";
    if( !device )
    {
        befehl += " account_id = ";
        befehl += accountId;
    }
    else
    {
        befehl += " device = '";
        befehl += device;
        befehl += "'";
    }
    befehl += " ORDER BY diff";
    lock();
    datenbank->befehl( befehl );
    Result r = datenbank->getResult();
    unlock();
    int anz = 0;
    int lastDiff = 0;
    for( int i = 0; i < r.zeilenAnzahl; i++, anz++ )
    {
        int l = (int)r.values[ i * 2 ];
        int d = (int)r.values[ i * 2 + 1 ];
        for( int j = lastDiff + 1; j < d; j++, anz++ )
            f->add( 0 );
        f->add( l );
        lastDiff = d;
    }
    r.destroy();
    return anz;
}

void AppSDatenbank::addKupfer( int account, int kupfer )
{
    Text befehl = "UPDATE account SET kupfer = kupfer + ";
    befehl += kupfer;
    befehl += " WHERE id = ";
    befehl += account;
    lock();
    datenbank->befehl( befehl );
    unlock();
}

bool AppSDatenbank::getFreeAds( int account )
{
    Text befehl = "SELECT get_account_free_ad( ";
    befehl += account;
    befehl += " )";
    lock();
    datenbank->befehl( befehl );
    Result r = datenbank->getResult();
    unlock();
    if( r.zeilenAnzahl < 1 )
    {
        r.destroy();
        return 0;
    }
    bool ret = r.values[ 0 ].istGleich( "t" );
    r.destroy();
    return ret;
}

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

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