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

// Inhalt der LSDatenbank Klasse aus Datenbank.h
// Konstruktor
ShSDatenbank::ShSDatenbank( InitDatei *zIni )
{
    datenbank = new Datenbank( zIni->zWert( "DBBenutzer" )->getText(), zIni->zWert( "DBPasswort" )->getText(),
        zIni->zWert( "DBName" )->getText(), zIni->zWert( "DBIP" )->getText(),
        (unsigned short)TextZuInt( zIni->zWert( "DBPort" )->getText(), 10 ) );
    if( !datenbank->istOk() )
    {
        std::cout << "ShS: Die Verbindung zur Datenbank konnte nicht hergestellt werden.\nDas Programm wird beendet.";
        exit( 1 );
    }
    InitializeCriticalSection( &cs );
    ref = 1;
    Text befehl = "SELECT port, admin_port  FROM server WHERE id = ";
    befehl += zIni->zWert( "ServerId" )->getText();
    sid = (int)*zIni->zWert( "ServerId" );
    lock();
    datenbank->befehl( befehl );
    Result res = datenbank->getResult();
    unlock();
    if( res.zeilenAnzahl == 1 )
    {
        zIni->addWert( "ServerPort", res.values[ 0 ] );
        zIni->addWert( "AdminServerPort", res.values[ 1 ] );
    }
    res.destroy();
}

// Destruktor
ShSDatenbank::~ShSDatenbank()
{
    datenbank->release();
    DeleteCriticalSection( &cs );
}

// nicht constant
void ShSDatenbank::lock()
{
    EnterCriticalSection( &cs );
}

void ShSDatenbank::unlock()
{
    LeaveCriticalSection( &cs );
}

int ShSDatenbank::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 ShSDatenbank::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;
}

bool ShSDatenbank::proveKlient( int num, int sNum )
{
    Text *befehl = new Text( "SELECT * FROM server_client WHERE server_id = " );
    befehl->append( sNum );
    befehl->append( " AND client_id = " );
    befehl->append( num );
    lock();
    datenbank->befehl( befehl->getText() );
    Result res = datenbank->getResult();
    unlock();
    befehl->release();
    bool ret = 0;
    if( res.zeilenAnzahl == 1 )
        ret = 1;
    res.destroy();
    return ret;
}

Text *ShSDatenbank::getKlientKey( int cId )
{
    lock();
    if( !datenbank->befehl( Text( "SELECT schluessel FROM client WHERE id = " ) += cId ) )
    {
        unlock();
        return 0;
    }
    Result res = datenbank->getResult();
    unlock();
    if( !res.zeilenAnzahl )
    {
        res.destroy();
        return 0;
    }
    Text *ret = new Text( res.values[ 0 ].getText() );
    res.destroy();
    return ret;
}

void ShSDatenbank::unregisterKlient( int num, int sNum )
{
    Text *befehl = new Text( "DELETE FROM server_client WHERE client_id = " );
    befehl->append( num );
    befehl->append( " AND server_id = " );
    befehl->append( sNum );
    lock();
    datenbank->befehl( befehl->getText() );
    unlock();
    befehl->release();
}

bool ShSDatenbank::setServerStatus( int id, int status )
{
    Text *befehl = new Text( "UPDATE server SET server_status_id = " );
    *befehl += status;
    *befehl += "WHERE id = ";
    *befehl += id;
    lock();
    if( !datenbank->befehl( befehl->getText() ) )
    {
        unlock();
        befehl->release();
        return 0;
    }
    bool ret = datenbank->getZeilenAnzahl() != 0;
    unlock();
    befehl->release();
    return ret;
}

bool ShSDatenbank::setMaxKarten( int id, int maxK )
{
    Text *befehl = new Text( "UPDATE server SET max_tasks = " );
    befehl->append( maxK );
    befehl->append( " WHERE id = " );
    befehl->append( id );
    lock();
    if( !datenbank->befehl( befehl->getText() ) )
    {
        unlock();
        befehl->release();
        return 0;
    }
    bool ret = datenbank->getZeilenAnzahl() > 0;
    unlock();
    befehl->release();
    return ret;
}

bool ShSDatenbank::serverIstNichtPausiert( int id )
{
    Text *befehl = new Text( "SELECT server_status_id FROM server WHERE id = " );
    befehl->append( id );
    lock();
    if( !datenbank->befehl( befehl->getText() ) )
    {
        unlock();
        befehl->release();
        return 0;
    }
    Result res = datenbank->getResult();
    unlock();
    befehl->release();
    if( !res.zeilenAnzahl )
    {
        res.destroy();
        return 0;
    }
    bool ret = (int)res.values[ 0 ] == 3;
    res.destroy();
    return ret;
}

bool ShSDatenbank::getSpielArtListe( int cId, char *suche, Array< int > *ret )
{
    Text *befehl = new Text( "SELECT distinct( a.id ) FROM spiel_art a LEFT JOIN account_client b ON b.client_id = " );
    befehl->append( cId );
    befehl->append( " LEFT JOIN spiel_art_account c ON a.id = c.spiel_art_id AND b.account_id = c.account_id AND "
        "c.status_id = 2 AND c.end_dat IS NULL INNER JOIN spiel_art_kauf_erlaubt d ON d.spiel_art_id = a.id WHERE a.name LIKE '%" );
    befehl->append( suche );
    befehl->append( "%' AND c.spiel_art_id IS NULL" );
    lock();
    if( !datenbank->befehl( befehl->getText() ) )
    {
        unlock();
        befehl->release();
        return 0;
    }
    Result res = datenbank->getResult();
    unlock();
    befehl->release();
    ret->leeren();
    for( int i = 0; i < res.zeilenAnzahl; i++ )
        ret->add( TextZuInt( res.values[ i ].getText(), 10 ) );
    res.destroy();
    return 1;
}

int ShSDatenbank::getSpielBesitzStatus( int cId, int sId )
{
    Text *befehl = new Text( "SELECT b.status_id FROM account_client a, spiel_art_account b "
        "WHERE a.account_id = b.account_id AND b.end_dat IS NULL AND a.client_id = " );
    befehl->append( cId );
    befehl->append( " AND b.spiel_art_id = " );
    befehl->append( sId );
    lock();
    if( !datenbank->befehl( befehl->getText() ) )
    {
        unlock();
        befehl->release();
        return 0;
    }
    Result res = datenbank->getResult();
    unlock();
    befehl->release();
    if( !res.zeilenAnzahl )
    {
        res.destroy();
        return 0;
    }
    int ret = TextZuInt( res.values[ 0 ].getText(), 10 );
    res.destroy();
    return ret;
}

int ShSDatenbank::getSpielTestversionStatus( int cId, int sId )
{
    Text *befehl = new Text( "SELECT b.verbleibend FROM account_client a, spiel_art_account b "
        "WHERE a.account_id = b.account_id AND b.end_dat IS NULL AND b.status_id = 1 AND a.client_id = " );
    befehl->append( cId );
    befehl->append( " AND b.spiel_art_id = " );
    befehl->append( sId );
    lock();
    if( !datenbank->befehl( befehl->getText() ) )
    {
        unlock();
        befehl->release();
        return 0;
    }
    Result res = datenbank->getResult();
    unlock();
    befehl->release();
    if( !res.zeilenAnzahl )
    {
        res.destroy();
        return 0;
    }
    int ret = TextZuInt( res.values[ 0 ].getText(), 10 );
    res.destroy();
    return ret;
}

int ShSDatenbank::getSpielErwerbbarStatus( int cId, int sId )
{
    Text *befehl = new Text( "SELECT a.spiel_art_account_status_id FROM spiel_art_kauf_erlaubt a LEFT JOIN account_client b ON b.client_id = " );
    befehl->append( cId );
    befehl->append( " LEFT JOIN spiel_art_account c ON a.spiel_art_id = c.spiel_art_id AND b.account_id = c.account_id AND c.end_dat IS NULL "
        "AND a.spiel_art_account_status_id = c.status_id WHERE c.spiel_art_id IS NULL AND a.spiel_art_id = " );
    befehl->append( sId );
    lock();
    if( !datenbank->befehl( befehl->getText() ) )
    {
        unlock();
        befehl->release();
        return 0;
    }
    Result res = datenbank->getResult();
    unlock();
    befehl->release();
    int ret = 0;
    for( int i = 0; i < res.zeilenAnzahl; i++ )
    {
        if( TextZuInt( res.values[ i ].getText(), 10 ) == 1 )
            ret |= 1;
        else if( TextZuInt( res.values[ i ].getText(), 10 ) == 2 )
            ret |= 2;
    }
    res.destroy();
    return ret;
}

int ShSDatenbank::getSpielPreis( int sId, bool testVersion )
{
    int status = testVersion ? 1 : 2;
    Text *befehl = new Text( "SELECT kupfer FROM spiel_art_kauf_erlaubt WHERE spiel_art_id = " );
    befehl->append( sId );
    befehl->append( " AND spiel_art_account_status_id = " );
    befehl->append( status );
    lock();
    if( !datenbank->befehl( befehl->getText() ) )
    {
        unlock();
        befehl->release();
        return 0;
    }
    Result res = datenbank->getResult();
    unlock();
    befehl->release();
    if( !res.zeilenAnzahl )
    {
        res.destroy();
        return 0;
    }
    int ret = TextZuInt( res.values[ 0 ].getText(), 10 );
    res.destroy();
    return ret;
}

bool ShSDatenbank::spielKaufen( int cId, int sId, bool testVersion )
{
    Text *befehl = new Text( "SELECT spiel_erwerben( " );
    befehl->append( cId );
    befehl->append( ", " );
    befehl->append( sId );
    if( testVersion )
        befehl->append( ", TRUE )" );
    else
        befehl->append( ", FALSE )" );
    lock();
    if( !datenbank->befehl( befehl->getText() ) )
    {
        unlock();
        befehl->release();
        return 0;
    }
    Result res = datenbank->getResult();
    unlock();
    befehl->release();
    if( !res.zeilenAnzahl )
    {
        res.destroy();
        return 0;
    }
    bool ret = res.values[ 0 ].istGleich( "t" );
    res.destroy();
    return ret;
}

bool ShSDatenbank::getKarteListe( int cId, int sId, char *suche, Array< int > *ret )
{
    Text *befehl = new Text( "SELECT distinct( a.id ) FROM karte a LEFT JOIN account_client b ON b.client_id = " );
    befehl->append( cId );
    befehl->append( " LEFT JOIN karte_account c ON a.id = c.karte_id AND b.account_id = c.account_id AND "
        "c.status_id = 2 AND c.end_dat IS NULL INNER JOIN karte_kauf_erlaubt d ON d.karte_id = a.id WHERE a.name LIKE '%" );
    Text s( suche );
    s.ersetzen( "'", "''" );
    befehl->append( (char*)s );
    befehl->append( "%' AND c.karte_id IS NULL" );
    if( sId )
    {
        befehl->append( " AND a.spiel_art_id = " );
        befehl->append( sId );
    }
    lock();
    if( !datenbank->befehl( befehl->getText() ) )
    {
        unlock();
        befehl->release();
        return 0;
    }
    Result res = datenbank->getResult();
    unlock();
    befehl->release();
    ret->leeren();
    for( int i = 0; i < res.zeilenAnzahl; i++ )
        ret->add( TextZuInt( res.values[ i ].getText(), 10 ) );
    res.destroy();
    return 1;
}

int ShSDatenbank::getKarteBesitzStatus( int cId, int kId )
{
    Text *befehl = new Text( "SELECT b.status_id FROM account_client a, karte_account b "
        "WHERE a.account_id = b.account_id AND b.end_dat IS NULL AND a.client_id = " );
    befehl->append( cId );
    befehl->append( " AND b.karte_id = " );
    befehl->append( kId );
    lock();
    if( !datenbank->befehl( befehl->getText() ) )
    {
        unlock();
        befehl->release();
        return 0;
    }
    Result res = datenbank->getResult();
    unlock();
    befehl->release();
    if( !res.zeilenAnzahl )
    {
        res.destroy();
        return 0;
    }
    int ret = TextZuInt( res.values[ 0 ].getText(), 10 );
    res.destroy();
    return ret;
}

int ShSDatenbank::getKarteTestversionStatus( int cId, int kId )
{
    Text *befehl = new Text( "SELECT b.verbleibend FROM account_client a, karte_account b "
        "WHERE a.account_id = b.account_id AND b.end_dat IS NULL AND b.status_id = 1 AND a.client_id = " );
    befehl->append( cId );
    befehl->append( " AND b.karte_id = " );
    befehl->append( kId );
    lock();
    if( !datenbank->befehl( befehl->getText() ) )
    {
        unlock();
        befehl->release();
        return 0;
    }
    Result res = datenbank->getResult();
    unlock();
    befehl->release();
    if( !res.zeilenAnzahl )
    {
        res.destroy();
        return 0;
    }
    int ret = TextZuInt( res.values[ 0 ].getText(), 10 );
    res.destroy();
    return ret;
}

int ShSDatenbank::getKarteErwerbbarStatus( int cId, int kId )
{
    Text *befehl = new Text( "SELECT a.karte_account_status_id FROM karte_kauf_erlaubt a LEFT JOIN account_client b ON b.client_id = " );
    befehl->append( cId );
    befehl->append( " LEFT JOIN karte_account c ON a.karte_id = c.karte_id AND b.account_id = c.account_id AND c.end_dat IS NULL "
        "AND a.karte_account_status_id = c.status_id WHERE c.karte_id IS NULL AND a.karte_id = " );
    befehl->append( kId );
    lock();
    if( !datenbank->befehl( befehl->getText() ) )
    {
        unlock();
        befehl->release();
        return 0;
    }
    Result res = datenbank->getResult();
    unlock();
    befehl->release();
    int ret = 0;
    for( int i = 0; i < res.zeilenAnzahl; i++ )
    {
        if( TextZuInt( res.values[ i ].getText(), 10 ) == 1 )
            ret |= 1;
        else if( TextZuInt( res.values[ i ].getText(), 10 ) == 2 )
            ret |= 2;
    }
    res.destroy();
    return ret;
}

int ShSDatenbank::getKartePreis( int kId, bool testVersion )
{
    int status = testVersion ? 1 : 2;
    Text *befehl = new Text( "SELECT kupfer FROM karte_kauf_erlaubt WHERE karte_id = " );
    befehl->append( kId );
    befehl->append( " AND karte_account_status_id = " );
    befehl->append( status );
    lock();
    if( !datenbank->befehl( befehl->getText() ) )
    {
        unlock();
        befehl->release();
        return 0;
    }
    Result res = datenbank->getResult();
    unlock();
    befehl->release();
    if( !res.zeilenAnzahl )
    {
        res.destroy();
        return 0;
    }
    int ret = TextZuInt( res.values[ 0 ].getText(), 10 );
    res.destroy();
    return ret;
}

bool ShSDatenbank::karteKaufen( int cId, int kId, bool testVersion )
{
    Text *befehl = new Text( "SELECT karte_erwerben( " );
    befehl->append( cId );
    befehl->append( ", " );
    befehl->append( kId );
    if( testVersion )
        befehl->append( ", TRUE )" );
    else
        befehl->append( ", FALSE )" );
    lock();
    if( !datenbank->befehl( befehl->getText() ) )
    {
        unlock();
        befehl->release();
        return 0;
    }
    Result res = datenbank->getResult();
    unlock();
    befehl->release();
    if( !res.zeilenAnzahl )
    {
        res.destroy();
        return 0;
    }
    bool ret = res.values[ 0 ].istGleich( "t" );
    res.destroy();
    return ret;
}

int ShSDatenbank::getUpdateKarte( int serverId )
{
    Text befehl = "SELECT id FROM karte WHERE shop_update = true AND server_shop_id = ";
    befehl += serverId;
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    Result r = datenbank->getResult();
    unlock();
    if( r.zeilenAnzahl )
    {
        int karte = r.values[ 0 ];
        r.destroy();
        return karte;
    }
    r.destroy();
    return 0;
}

bool ShSDatenbank::endUpdateKarte( int karteId )
{
    Text befehl = "SELECT karte_shop_update_ende( ";
    befehl += karteId;
    befehl += " )";
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    Result r = datenbank->getResult();
    unlock();
    if( !r.zeilenAnzahl )
    {
        r.destroy();
        return 0;
    }
    bool ret = r.values[ 0 ].istGleich( "t" );
    r.destroy();
    return ret;
}

bool ShSDatenbank::getEditorServerPortIp( int karteId, int *port, Text *ip )
{
    if( !port || !ip )
        return 0;
    Text befehl = "SELECT a.port, a.ip FROM server a, karte b WHERE a.id = b.server_editor_id AND b.id = ";
    befehl += karteId;
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    Result r = datenbank->getResult();
    unlock();
    if( !r.zeilenAnzahl )
    {
        r.destroy();
        return 0;
    }
    *port = r.values[ 0 ];
    ip->setText( r.values[ 1 ] );
    r.destroy();
    return 1;
}

bool ShSDatenbank::proveKarte( int serverId, int karteId )
{
    Text befehl = "SELECT id FROM karte WHERE id = ";
    befehl += karteId;
    befehl += " AND server_shop_id = ";
    befehl += serverId;
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    int z = datenbank->getZeilenAnzahl();
    unlock();
    return z != 0;
}

bool ShSDatenbank::getKarteShopServerPortIp( int karteId, int clientId, int *port, Text *ip )
{
    if( !port || !ip )
        return 0;
    Text befehl = "SELECT a.id, a.port, a.ip FROM server a, karte b WHERE a.id = b.server_shop_id AND a.server_status_id = 3 AND b.id = ";
    befehl += karteId;
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    Result r = datenbank->getResult();
    unlock();
    if( !r.zeilenAnzahl )
    {
        r.destroy();
        return 0;
    }
    int id = r.values[ 0 ];
    *port = r.values[ 1 ];
    ip->setText( r.values[ 2 ] );
    r.destroy();
    befehl = "UPDATE server_client SET server_id = ";
    befehl += id;
    befehl += " WHERE client_id = ";
    befehl += clientId;
    befehl += " AND server_id = ";
    befehl += sid;
    lock();
    datenbank->befehl( befehl );
    unlock();
    return 1;
}

bool ShSDatenbank::proveSpiel( int serverId, int spielId )
{
    Text befehl = "SELECT id FROM spiel_art WHERE id = ";
    befehl += spielId;
    befehl += " AND server_shop_id = ";
    befehl += serverId;
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    int z = datenbank->getZeilenAnzahl();
    unlock();
    return z != 0;
}

bool ShSDatenbank::getSpielShopServerPortIp( int spielId, int clientId, int *port, Text *ip )
{
    if( !port || !ip )
        return 0;
    Text befehl = "SELECT a.id, a.port, a.ip FROM server a, spiel_art b WHERE a.id = b.server_shop_id AND a.server_status_id = 3 AND b.id = ";
    befehl += spielId;
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    Result r = datenbank->getResult();
    unlock();
    if( !r.zeilenAnzahl )
    {
        r.destroy();
        return 0;
    }
    int id = r.values[ 0 ];
    *port = r.values[ 1 ];
    ip->setText( r.values[ 2 ] );
    r.destroy();
    befehl = "UPDATE server_shop_clients SET server_id = ";
    befehl += id;
    befehl += " WHERE client_id = ";
    befehl += clientId;
    befehl += " AND server_id = ";
    befehl += sid;
    lock();
    datenbank->befehl( befehl );
    unlock();
    return 1;
}

// constant
Text *ShSDatenbank::getLetzterFehler() const
{
    return datenbank->getLetzterFehler();
}

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

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