#include "../KSGKlient.h"
#include "../KSGServer.h"
#include "../../Global/Variablen.h"
#include <Datei.h>

// Inhalt der HistorieKlient Klasse KSGKlient.h
// Konstruktor
HistorieKlient::HistorieKlient()
{
    klient = 0;
    fehler = new Text( "" );
    klientId = getKlientId();
    ref = 1;
    InitializeCriticalSection( &cs );
}

// Destruktor
HistorieKlient::~HistorieKlient()
{
    LOCK( &cs );
    trenne();
    fehler = fehler->release();
    UNLOCK( &cs );
    DeleteCriticalSection( &cs );
}

// privat
bool HistorieKlient::verbinde( char *ip, int port ) // verbindet ich mit dem Historie Server
{
    if( klient && klient->getServerPort() == port && Text( ip ).istGleich( klient->getServerIp() ) )
        return 1;
    if( klient )
        trenne();
    klient = new Klient();
    unsigned char schlüssel[ 20 ] = { 207, 30, 72, 46, 30, 50, 56, 213, 82, 107, 14, 201, 149, 58, 110, 138, 228, 241, 52, 54 };
    klient->setSendeSchlüssel( (char*)schlüssel, 20 );
    klient->setEmpfangSchlüssel( (char*)schlüssel, 20 );
    if( !klient->verbinde( (unsigned short)port, ip ) )
    {
        klient = klient->release();
        fehler->setText( "Fehler beim verbinden mit dem Historie Server." );
        return 0;
    }
    klient->sendeVerschlüsselt( "\1", 1 );
    klient->sendeVerschlüsselt( (char*)&klientId, 4 );
    char ret = 0;
    klient->getNachrichtVerschlüsselt( &ret, 1 );
    if( ret == 3 )
    {
        char län = 0;
        klient->getNachrichtVerschlüsselt( &län, 1 );
        char *nachricht = new char[ län + 1 ];
        nachricht[ län ] = 0;
        klient->getNachrichtVerschlüsselt( nachricht, län );
        fehler->setText( nachricht );
        delete[]nachricht;
        trenne();
        return 0;
    }
    if( ret == 1 )
    {
        char *sl = 0;
        char slLän = getSchlüssel( &sl );
        klient->setSendeSchlüssel( sl, slLän );
        klient->setEmpfangSchlüssel( sl, slLän );
        delete[] sl;
    }
    return 1;
}

bool HistorieKlient::trenne() // trennt sich von dem Historie Server
{
    if( !klient )
        return 1;
    char serverReturn;
    klient->sendeVerschlüsselt( "\4", 1 );
    klient->getNachrichtVerschlüsselt( &serverReturn, 1 );
    if( serverReturn == 3 )
    {
        char län = 0;
        klient->getNachrichtVerschlüsselt( &län, 1 );
        char *nachricht = new char[ län + 1 ];
        nachricht[ län ] = 0;
        klient->getNachrichtVerschlüsselt( nachricht, län );
        delete[]nachricht;
    }
    klient->sendeVerschlüsselt( "\3", 1 );
    klient->getNachrichtVerschlüsselt( &serverReturn, 1 );
    klient->trenne();
    klient = klient->release();
    return 1;
}

// nicht constant
bool HistorieKlient::downloadSpielHistorie( int spielId ) // läd Spiel Historie herunter
{
    if( DateiIstVerzeichnis( Text( "data/tmp/historie/" ) += spielId ) )
        return 1;
    LOCK( &cs );
    int port = 0;
    Text *ip = new Text();
    if( !infoKlient->getHistorieServer( spielId, &port, ip ) )
    {
        UNLOCK( &cs );
        ip->release();
        fehler->setText( infoKlient->getLetzterFehler() );
        return 0;
    }
    if( !verbinde( *ip, port ) )
    {
        UNLOCK( &cs );
        ip->release();
        return 0;
    }
    ip->release();
    klient->sendeVerschlüsselt( "\6", 1 );
    char ret = 0;
    klient->getNachrichtVerschlüsselt( &ret, 1 );
    if( ret == 1 )
    {
        klient->sendeVerschlüsselt( (char*)&spielId, 4 );
        klient->getNachrichtVerschlüsselt( &ret, 1 );
        if( ret == 1 )
        {
            char län = 0;
            klient->getNachrichtVerschlüsselt( &län, 1 );
            while( län )
            {
                char *pf = new char[ län + 1 ];
                pf[ län ] = 0;
                klient->getNachrichtVerschlüsselt( pf, län );
                __int64 gr = 0;
                klient->getNachrichtVerschlüsselt( (char*)&gr, 8 );
                Text *pfad = new Text( "data/tmp/historie/" );
                pfad->anhängen( spielId );
                pfad->anhängen( pf );
                delete[] pf;
                Datei *d = new Datei();
                d->setDatei( pfad );
                d->erstellen();
                d->öffnen( Datei::Style::schreiben );
                char *bytes = new char[ 2048 ];
                while( gr )
                {
                    int dLän = gr > 2048 ? 2048 : (int)gr;
                    klient->getNachricht( bytes, dLän );
                    d->schreibe( bytes, dLän );
                    gr -= dLän;
                }
                delete[] bytes;
                d->schließen();
                d->release();
                klient->getNachrichtVerschlüsselt( &län, 1 );
            }
            trenne();
            UNLOCK( &cs );
            return 1;
        }
    }
    if( ret == 3 )
    {
        char län = 0;
        klient->getNachrichtVerschlüsselt( &län, 1 );
        char *nachricht = new char[ län + 1 ];
        nachricht[ län ] = 0;
        klient->getNachrichtVerschlüsselt( nachricht, län );
        fehler->setText( nachricht );
        delete[]nachricht;
    }
    trenne();
    UNLOCK( &cs );
    return 0;
}

// constant
bool HistorieKlient::istVerbunden() const // prüft, ob mit Historie Server verbunden
{
    return klient != 0;
}

char *HistorieKlient::getLetzterFehler() const // gibt den Letzten Fehlertext zuück
{
    return *fehler;
}

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

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