#pragma once
#include <Klient.h>
#include <Thread.h>
#include <iostream>

class ESClient : public Framework::Thread
{
private:
    Network::Klient *k;
    int klientId;
    bool abmel;
    bool trenn;
    unsigned short port;
    char *ip;
    char *key;
    unsigned char keyLen;
    int ref;

public:
    // Konstruktor
    ESClient( int klientId, unsigned short port, char *ip, char *key, unsigned char keyLen )
    {
        k = 0;
        this->klientId = klientId;
        this->port = port;
        this->ip = new char[ textLength( ip ) + 1 ];
        memcpy( this->ip, ip, textLength( ip ) + 1 );
        this->keyLen = keyLen;
        this->key = new char[ keyLen ];
        memcpy( this->key, key, keyLen );
        abmel = 0;
        trenn = 0;
        ref = 1;
    }
    // Destruktor
    ~ESClient()
    {
        delete[] key;
        if( k )
            abmelden();
        delete[] ip;
        warteAufThread( 5000 );
        ende();
        if( k )
            k->release();
    }
    // nicht constant
    bool verbinden()
    {
        if( k )
            return 1;
        k = new Network::Klient();
        if( k->verbinde( port, ip ) )
        {
            k->sende( "\0", 1 ); // Verschlüsselung Aktivieren
            if( k->sendeEncrypted( "\1", 1 ) )
            {
                k->sendeEncrypted( (char*)&klientId, 4 );
                char serverReturn = 0;
                k->getNachrichtEncrypted( &serverReturn, 1 );
                if( serverReturn == 3 )
                {
                    char byte = 0;
                    k->getNachrichtEncrypted( &byte, 1 );
                    char *f = new char[ byte + 1 ];
                    f[ byte ] = 0;
                    k->getNachrichtEncrypted( f, byte );
                    std::cerr << "error while identifyin client Erhaltung Server returned: " << f << "\n";
                    delete[]f;
                    k->sendeEncrypted( "\3", 1 );
                    k->getNachrichtEncrypted( &serverReturn, 1 );
                    k->trenne();
                    return 0;
                }
                k->setSendeKey( (char*)key, keyLen );
                k->setEmpfangKey( (char*)key, keyLen );
                start();
            }
            else
            {
                std::cerr << "network error while sending to Erhaltung Server\n";
                k = k->release();
                return 0;
            }
        }
        else
        {
            std::cerr << "network error while connecting to Erhaltung Server\n";
            k = k->release();
            return 0;
        }
        return 1;
    }

    void abmelden()
    {
        abmel = 1;
        trenn = 1;
    }

    void trennen()
    {
        trenn = 1;
    }

    virtual void thread()
    {
        while( 1 )
        {
            char n = 0;
            k->getNachrichtEncrypted( &n, 1 );
            if( n != 1 )
            {
                Sleep( 250 );
                continue;
            }
            if( trenn )
            {
                if( abmel )
                {
                    k->sendeEncrypted( "\1", 1 );
                    k->getNachrichtEncrypted( &n, 1 );
                }
                k->trenne();
                run = 0;
                return;
            }
            else
                k->sendeEncrypted( "\0", 1 );
        }
    }

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

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