#ifndef Thread_H
#define Thread_H

#include <condition_variable>

#include "Array.h"
#include "ReferenceCounter.h"

namespace Framework
{
    class Thread;
    class Critical;

    //! A new thread similar to the Thread class from 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:
        //! Constructor
        DLLEXPORT Thread();
        //! Destructor
        DLLEXPORT virtual ~Thread();
        //! Starts the new thread
        DLLEXPORT void start();
#ifdef WIN32
        //! Pauses the thread (Windows only)
        DLLEXPORT void pause();
        //! Resumes the thread (Windows only)
        DLLEXPORT void fortsetzen();
#endif
        //! Terminates the thread
        DLLEXPORT void ende();
        //! This function is executed by the new thread
        DLLEXPORT virtual void thread();
        //! This function is called after the thread function has finished
        DLLEXPORT virtual void threadEnd();
        //! Checks whether the thread is active
        //! return: true if the thread is running.
        //!         false if the thread is terminated, paused or not yet
        //!         started.
        DLLEXPORT bool isRunning() const;
        //! Waits for the thread for the specified time
        //! \param zeit The time to wait for the thread. 1000 = 1 second
        DLLEXPORT int warteAufThread(int zeit);
        //! Sets a framework pointer to a thread handle that will be set to 0
        //! if the thread resources have already been fully cleaned up
        //! \param ths A pointer to a thread handle to be modified
        DLLEXPORT void setSystemHandlePointer(pthread_t* ths);
        //! Returns a handle to the thread
        DLLEXPORT pthread_t getThreadHandle() const;
        //! set the name of the thread
        DLLEXPORT void setName(const char* name);
        //! get the name of the thread
        DLLEXPORT const char* getName() const;

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

        friend Critical;
    };

#ifdef WIN32
    //! This function is used by the Thread class to start a thread
    DLLEXPORT unsigned long __stdcall threadStart(void* param);
#else
    //! This function is used by the Thread class to start a thread
    void* threadStart(void* param); //! starts thread
#endif

    //! A class that stores all currently running Thread objects
    class ThreadRegister
    {
    private:
        Array<Framework::Thread*> threads;
        CRITICAL_SECTION cs;
        Array<pthread_t> closedThreads;

    public:
        //! Constructor
        ThreadRegister();
        //! Destructor
        ~ThreadRegister();
        //! Adds a new thread
        //! \param t The thread to be added
        void add(Thread* t);
        //! Removes a thread
        //! \param t The thread to be removed
        void remove(Thread* t);
        //! Checks whether a pointer points to a valid Thread object, or
        //! whether it has already been deleted \param t The pointer to be checked
        bool isThread(Thread* t);
        //! Searches for a specific thread and returns the corresponding object
        //! handle: A handle to the sought thread
        Thread* zThread(pthread_t handle);
        //! Called automatically when a thread is terminated. The
        //! resources are then released in cleanUpClosedThreads.
        //! \param handle The handle of the thread
        void addClosedThread(pthread_t handle);
        //! Locks the register
        void lock();
        //! Unlocks the register
        void unlock();
        //! Deletes the already terminated threads and releases their resources
        DLLEXPORT void cleanUpClosedThreads();
    };
} // namespace Framework

#endif