#pragma once
#include "il2cpp-config.h"
#include "il2cpp-object-internals.h"

namespace il2cpp
{
namespace vm
{
    class LIBIL2CPP_CODEGEN_API Monitor
    {
    public:
        static void AllocateStaticData();
        static void FreeStaticData();

        static void Enter(Il2CppObject* object);
        static bool TryEnter(Il2CppObject* object, uint32_t timeout);
        static void Exit(Il2CppObject* object);
        static void Pulse(Il2CppObject* object);
        static void PulseAll(Il2CppObject* object);
        static void Wait(Il2CppObject* object);
        static bool TryWait(Il2CppObject* object, uint32_t timeout);
        static bool IsAcquired(Il2CppObject* object);
        static bool IsOwnedByCurrentThread(Il2CppObject* object);
    };

#if !IL2CPP_SUPPORT_THREADS

    inline void Monitor::AllocateStaticData()
    {
    }

    inline void Monitor::FreeStaticData()
    {
    }

    inline bool Monitor::TryEnter(Il2CppObject* object, uint32_t timeout)
    {
        Monitor::Enter(object);
        return true;
    }

    inline void Monitor::Pulse(Il2CppObject* object)
    {
    }

    inline void Monitor::PulseAll(Il2CppObject* object)
    {
    }

    inline void Monitor::Wait(Il2CppObject* object)
    {
    }

    inline bool Monitor::TryWait(Il2CppObject* object, uint32_t timeout)
    {
        return true;
    }

    inline bool Monitor::IsAcquired(Il2CppObject* object)
    {
        return object->monitor != 0;
    }

    inline bool Monitor::IsOwnedByCurrentThread(Il2CppObject* object)
    {
        return Monitor::IsAcquired(object);
    }

#endif

    struct MonitorHolder
    {
        MonitorHolder(Il2CppObject* obj) :
            m_Object(obj)
        {
            Monitor::Enter(obj);
        }

        ~MonitorHolder()
        {
            Monitor::Exit(m_Object);
        }

    private:
        Il2CppObject* m_Object;
    };
} /* namespace vm */
} /* namespace il2cpp */
