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

// Inhalt der LSDatenbank Klasse aus Datenbank.h
// Konstruktor
EdSDatenbank::EdSDatenbank( 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 << "EdS: 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();
    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
EdSDatenbank::~EdSDatenbank()
{
    datenbank->release();
    DeleteCriticalSection( &cs );
}

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

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

int EdSDatenbank::istAdministrator( const char *name, const char *passwort )
{
    Text *befehl = new Text( "SELECT id FROM benutzer WHERE name = '" );
    befehl->append( name );
    befehl->append( "' AND passwort = md5('" );
    befehl->append( passwort );
    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 EdSDatenbank::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 EdSDatenbank::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 *EdSDatenbank::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 EdSDatenbank::unregisterKlient( int num, int sNum )
{
    Text *befehl = new Text( "DELETE FROM server_client WHERE client_id = " );
    befehl->append( num );
    befehl->append( " AND server_editor_id = " );
    befehl->append( sNum );
    lock();
    datenbank->befehl( befehl->getText() );
    unlock();
    befehl->release();
}

bool EdSDatenbank::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 EdSDatenbank::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 EdSDatenbank::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;
}

Text *EdSDatenbank::getKarteName( int id )
{
    Text befehl = "SELECT name FROM karte WHERE id = ";
    befehl += id;
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    Result res = datenbank->getResult();
    unlock();
    if( !res.zeilenAnzahl )
    {
        res.destroy();
        return 0;
    }
    Text *ret = new Text( res.values[ 0 ] );
    res.destroy();
    return ret;
}

bool EdSDatenbank::proveKarte( int id, int cId, int sNum )
{
    Text befehl = "SELECT a.id FROM karte a, account_client b WHERE a.id = ";
    befehl += id;
    befehl += " AND a.account_id = b.account_id AND b.client_id = ";
    befehl += cId;
    befehl += " AND a.server_editor_id = ";
    befehl += sNum;
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    bool ret = datenbank->getZeilenAnzahl() != 0;
    unlock();
    return ret;
}

bool EdSDatenbank::istKarteInUpdate( int id )
{
    Text befehl = "SELECT erlaubt FROM karte WHERE id = ";
    befehl += id;
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    Result res = datenbank->getResult();
    unlock();
    if( !res.zeilenAnzahl )
    {
        res.destroy();
        return 0;
    }
    bool ret = res.values[ 0 ].istGleich( "f" );
    res.destroy();
    return ret;
}

bool EdSDatenbank::startKarteUpdate( int id )
{
    Text befehl = "SELECT karte_update_begin( ";
    befehl += id;
    befehl += " )";
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    Result res = datenbank->getResult();
    unlock();
    if( !res.zeilenAnzahl )
    {
        res.destroy();
        return 0;
    }
    bool ret = res.values[ 0 ].istGleich( "t" );
    res.destroy();
    return ret;
}

bool EdSDatenbank::startShopUpdate( int id )
{
    Text befehl = "SELECT karte_shop_update_begin( ";
    befehl += id;
    befehl += " )";
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    Result res = datenbank->getResult();
    unlock();
    if( !res.zeilenAnzahl )
    {
        res.destroy();
        return 0;
    }
    bool ret = res.values[ 0 ].istGleich( "t" );
    res.destroy();
    return ret;
}

bool EdSDatenbank::getKarteShopDaten( int karte, int &es, int &tp, int &vp )
{
    es = 0;
    tp = 0;
    vp = 0;
    Text befehl = "SELECT karte_account_status_id, kupfer FROM karte_kauf_erlaubt WHERE karte_id = ";
    befehl += karte;
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    Result r = datenbank->getResult();
    unlock();
    for( int i = 0; i < r.zeilenAnzahl; i++ )
    {
        if( (int)r.values[ i * 2 ] == 1 )
        {
            es |= 1;
            tp = r.values[ i * 2 + 1 ];
        }
        if( (int)r.values[ i * 2 ] == 2 )
        {
            es |= 2;
            vp = r.values[ i * 2 + 1 ];
        }
    }
    r.destroy();
    return 1;
}

bool EdSDatenbank::setKarteShopDaten( int karte, int es, int tp, int vp )
{
    Text befehl = "SELECT karte_account_status_id, kupfer FROM karte_kauf_erlaubt WHERE karte_id = ";
    befehl += karte;
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    Result r = datenbank->getResult();
    unlock();
    int esAlt = 0;
    int tpAlt = 0;
    int vpAlt = 0;
    for( int i = 0; i < r.zeilenAnzahl; i++ )
    {
        if( (int)r.values[ i * 2 ] == 1 )
        {
            esAlt |= 1;
            tpAlt = r.values[ i * 2 + 1 ];
        }
        if( (int)r.values[ i * 2 ] == 2 )
        {
            esAlt |= 2;
            vpAlt = r.values[ i * 2 + 1 ];
        }
    }
    r.destroy();
    if( esAlt != es )
    {
        for( int i = 1; i < 3; i++ )
        {
            if( ( esAlt | i ) != esAlt && ( es | i ) == es )
            {
                befehl = "INSERT INTO karte_kauf_erlaubt( karte_id, karte_account_status_id, kupfer ) VALUES( ";
                befehl += karte;
                befehl += ", ";
                befehl += i;
                befehl += ", ";
                if( i == 1 )
                    befehl += tp;
                if( i == 2 )
                    befehl += vp;
                befehl += " )";
                lock();
                if( !datenbank->befehl( befehl ) )
                {
                    unlock();
                    return 0;
                }
                unlock();
            }
            else if( ( esAlt | i ) == esAlt && ( es | i ) != es )
            {
                befehl = "DELETE FROM karte_kauf_erlaubt WHERE karte_id = ";
                befehl += karte;
                befehl += " AND karte_account_status_id = ";
                befehl += i;
                lock();
                if( !datenbank->befehl( befehl ) )
                {
                    unlock();
                    return 0;
                }
                unlock();
            }
            else if( ( i == 1 && tpAlt != tp ) || ( i == 2 && vpAlt != vp ) )
            {
                befehl = "UPDATE karte_kauf_erlaubt SET kupfer = ";
                if( i == 1 )
                    befehl += tp;
                if( i == 2 )
                    befehl += vp;
                befehl += " WHERE karte_id = ";
                befehl += karte;
                befehl += " AND karte_account_status_id = ";
                befehl += i;
                lock();
                if( !datenbank->befehl( befehl ) )
                {
                    unlock();
                    return 0;
                }
                unlock();
            }
        }
    }
    return 1;
}

bool EdSDatenbank::setMaxSpieler( int karte, int spieler )
{
    Text befehl = "UPDATE karte SET max_spieler = ";
    befehl += spieler;
    befehl = " WHERE id = ";
    befehl += karte;
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    unlock();
    return 1;
}

bool EdSDatenbank::karteErstellen( const char *name, int spielArt, int klient )
{
    Text befehl = "SELECT id FROM spiel_art WHERE editor_erlaubt = TRUE AND id = ";
    befehl += spielArt;
    lock();
    if( !datenbank->befehl( befehl ) || !datenbank->getZeilenAnzahl() )
    {
        unlock();
        return 0;
    }
    unlock();
    befehl = "SELECT account_id FROM account_client WHERE client_id = ";
    befehl = klient;
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    Result r = datenbank->getResult();
    unlock();
    if( !r.zeilenAnzahl )
    {
        r.destroy();
        return 0;
    }
    int acc = r.values[ 0 ];
    r.destroy();
    befehl = "SELECT such_karten_server()";
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    r = datenbank->getResult();
    unlock();
    if( r.zeilenAnzahl != 3 )
    {
        r.destroy();
        return 0;
    }
    int ks = r.values[ 0 ];
    int es = r.values[ 1 ];
    int ss = r.values[ 2 ];
    r.destroy();
    if( !ks || !es || !ss )
        return 0;
    befehl = "INSERT INTO karte( name, spiel_art_id, account_id, server_editor_id, server_karten_id, server_shop_id ) VALUES( '";
    befehl += name;
    befehl += "', ";
    befehl += spielArt;
    befehl += ", ";
    befehl += acc;
    befehl += ", ";
    befehl += es;
    befehl += ", ";
    befehl += ks;
    befehl += ", ";
    befehl += ss;
    befehl += " )";
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    unlock();
    return 1;
}

int EdSDatenbank::getSpielArtId( int karte )
{
    Text befehl = "SELECT spiel_art_id FROM karte WHERE id = ";
    befehl += karte;
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    Result r = datenbank->getResult();
    unlock();
    int ret = r.values[ 0 ];
    r.destroy();
    return ret;
}

bool EdSDatenbank::getLast30DaysIncomeStatistik( int karte, Array< int > *einkommen, Array< int > *verkauft )
{
    Text befehl = "SELECT a._kupfer, a._verkauft FROM get_karte_einkommen_statistik_since( (now() - '30 days'::INTERVAL)::DATE, ";
    befehl += karte;
    befehl += " ) a";
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    Result r = datenbank->getResult();
    unlock();
    for( int i = 0; i < r.zeilenAnzahl; i++ )
    {
        einkommen->add( r.values[ i * 2 ] );
        verkauft->add( r.values[ i * 2 + 1 ] );
    }
    r.destroy();
    return 1;
}

bool EdSDatenbank::getLast30DaysSpielStatistik( int karte, Array< int > *spiele )
{
    Text befehl = "SELECT get_karte_spiel_statistik_since( (now() - '30 days'::INTERVAL)::DATE, ";
    befehl += karte;
    befehl += " )";
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    Result r = datenbank->getResult();
    unlock();
    for( int i = 0; i < r.zeilenAnzahl; i++ )
        spiele->add( r.values[ i ] );
    r.destroy();
    return 1;
}

int EdSDatenbank::getKaufAnz( int karte )
{
    Text befehl = "SELECT verkauft FROM karte WHERE id = ";
    befehl += karte;
    lock();
    if( !datenbank->befehl( befehl ) )
    {
        unlock();
        return 0;
    }
    Result r = datenbank->getResult();
    unlock();
    if( !r.zeilenAnzahl )
    {
        r.destroy();
        return 0;
    }
    int anz = r.values[ 0 ];
    r.destroy();
    return anz;
}

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

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

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