#ifndef Thread_H
#define Thread_H

#include "Array.h"
#include "ReferenceCounter.h"
#include <condition_variable>

namespace Framework
{
    class Thread;
    class Critical;

    //! Ein neuer Thread wie die Thread Klasse aus Java
    class Thread : public virtual ReferenceCounter
    {
    private:
        pthread_t* threadHandleSys;
        int lockCount;
        const char* name;

    protected:
        unsigned long threadId;
        pthread_t threadHandle;
        bool run;

    public:
        //! Konstruktor 
        DLLEXPORT Thread();
        //! Destruktor 
        DLLEXPORT virtual ~Thread();
        //! Startet den neuen Thread 
        DLLEXPORT void start();
#ifdef WIN32
        //! Pausiert den Thread (Nur für Windows)
        DLLEXPORT void pause();
        //! Setzt den Thread Fort (Nur für Windows)
        DLLEXPORT void fortsetzen();
#endif
        //! Beendet den Thread
        DLLEXPORT void ende();
        //! Diese Funktion wird von dem neuen Thread ausgeführt.
        DLLEXPORT virtual void thread();
        //! Diese Funktion wird eufgerufen, nachdem die thread Funktion zuende ist
        DLLEXPORT virtual void threadEnd();
        //! prüft, ob der Thrad aktiv ist
        //! return: true, falls der Thread läuft. 
        //!         false, wenn der Thread beendet, pausiert oder noch nicht gestartet wurde.
        DLLEXPORT bool isRunning() const;
        //! wartet zeit lang auf den Thread
        //! \param zeit Die Zeit, die auf den Thread gewartet werden soll. 1000 = 1 Sekunde
        DLLEXPORT int warteAufThread( int zeit );
        //! Legt einen Frameworkpointer auf ein Threadhandle fest, der auf 0 gesetzt wird, falls die Ressourcen des Threads bereits follstänfig aufgeräumt wurden
        //! \param ths Ein Zeiger auf ein Threadhandle, das verändert werden soll
        void setSystemHandlePointer( pthread_t* ths );
        //! Gibt ein Handle auf den Thread zurück
        DLLEXPORT pthread_t getThreadHandle() const;
        // set the name of the thread
        void setName( const char* name );
        // get the name of the thread
        const char* getName() const;

    private:
        void addCriticalLock();
        void removeCriticalLock();

        friend Critical;
    };

#ifdef WIN32
    //! Diese Funktion wird fon der Thread Klasse benutzt um einen thread zu starten
    DLLEXPORT unsigned long __stdcall threadStart( void* param );
#else
    //! Diese Funktion wird fon der Thread Klasse benutzt um einen thread zu starten
    void* threadStart( void* param ); //! startet thread
#endif

    //! Eine Klasse, die alle aktuell laufenden Thread Objekte speichert
    class ThreadRegister
    {
    private:
        Array< Framework::Thread* > threads;
        CRITICAL_SECTION cs;
        Array< pthread_t > closedThreads;

    public:
        //! Konstruktor
        ThreadRegister();
        //! Destruktor
        ~ThreadRegister();
        //! Fügt einen neuen Thread hinzu
        //! \param t Der Thread, der hinzugefügt werden soll
        void add( Thread* t );
        //! Entfernt einen neuen Thread
        //! \param t Der Thread, der entfernt werden soll
        void remove( Thread* t );
        //! Überprüft, ob ein Zeiger auf ein gültiges Thread Objekt zeigt, oder ob es schon gelöscht wurde
        //! \param t Der Zeiger, der geprüft werden soll
        bool isThread( Thread* t );
        //! Sucht nach einem bestimmten Thread und gibt das zugehörige Objekt zurück
        //! handle: Ein handle zu dem gesuchten Thread
        Thread* zThread( pthread_t handle );
        //! Setzt Wird automatisch aufgerufen, wenn ein Thread beendet wird. Die Reccourcen werden daraufhin in cleanUpClosedThreads freigegeben.
        //! \param handle Das Handle des Threads
        void addClosedThread( pthread_t handle );
        //! sperrt das register
        void lock();
        //! entsperrt das register
        void unlock();
        //! Löscht die bereits beendetetn Threads und gibt ihre Reccourcen wieder frei
        DLLEXPORT void cleanUpClosedThreads();
    };
}

#endif