#pragma once

#include <condition_variable>

#include "Betriebssystem.h"

namespace Framework
{
    class Thread;

    class Critical
    {
    private:
        CRITICAL_SECTION cs;
        Thread* owner;
        int lockCount;
        int id;

    public:
        //! Constructor
        DLLEXPORT Critical();
        //! Destructor
        DLLEXPORT ~Critical();
        //! Locks the object
        DLLEXPORT void lock();
        //! Tries to lock the object
        DLLEXPORT bool tryLock();
        //! Unlocks the object
        DLLEXPORT void unlock();

        //! Returns true if the object is locked
        DLLEXPORT bool isLocked() const;
        //! Returns a pointer to the thread that locked the object
        DLLEXPORT const Thread* zOwner() const;
    };

    class CriticalLock
    {
    private:
        Critical* critical;

    public:
        DLLEXPORT CriticalLock(Critical* critical);
        DLLEXPORT ~CriticalLock();
    };

#define LOCK(x)     CriticalLock _lock(x)
#define LOCKN(x, i) CriticalLock _lock_##i(x)

    class Synchronizer
    {
    private:
        std::condition_variable block;
        std::mutex mutex;
        int numWaiting;
        bool skip;

    public:
        DLLEXPORT Synchronizer();
        DLLEXPORT ~Synchronizer();

        DLLEXPORT bool wait();
        DLLEXPORT bool wait(int milisec);
        DLLEXPORT void notify();
        DLLEXPORT void notify(int amount);
        DLLEXPORT void notifyAll();

        DLLEXPORT int getNumberOfWaitingThreads() const;
    };
} // namespace Framework