/***************************************************************************
*                                                                          *
*  Copyright (C) Golaem S.A.  All Rights Reserved.                         *
*                                                                          *
***************************************************************************/

#pragma once
#ifndef GLMSCOPEDLOCK_H
#define GLMSCOPEDLOCK_H

#include "glmCoreAPI.h"
#include "glmAssert.h"

namespace glm
{
	template <typename Lockable>
	class ScopedLock
	{
	public:

		ScopedLock(Lockable& lockable) : _locked(NULL)
		{
			lockable.lock();
			_locked = &lockable;
		}

		~ScopedLock()
		{
            GLM_DEBUG_ASSERT(_locked != NULL);

            _locked->unlock();
			_locked = NULL;
		}

	private:
		GLM_DISALLOW_COPY_AND_ASSIGN(ScopedLock);

		Lockable* _locked;
	};

	template <typename Lockable>
	class ScopedLockActivable
	{
	public:

		ScopedLockActivable(Lockable& lockable) : _isLocked(false), _locked(NULL)
		{
			_locked = &lockable;
		}

		void lock()
		{
            GLM_DEBUG_ASSERT(_locked != NULL);
            _locked->lock();
			_isLocked = true;
		}

        void unlock()
        {
            GLM_DEBUG_ASSERT(_locked != NULL);
            _locked->unlock();
            _isLocked = false;
        }

        ~ScopedLockActivable()
        {
            GLM_DEBUG_ASSERT(_locked != NULL);
            if (_isLocked)
			{
				_locked->unlock();
			}
			_locked = NULL;
        }

    private:
		GLM_DISALLOW_COPY_AND_ASSIGN(ScopedLockActivable);

		bool _isLocked;
		Lockable* _locked;
	};

	template<typename Lockable, bool isWriter>
	class ScopedLockRW
	{
	public:

		ScopedLockRW(Lockable& lockable) : _locked(NULL)
		{
			isWriter? lockable.lockWriter() : lockable.lockReader();
			_locked = &lockable;
		}

		~ScopedLockRW()
		{
            GLM_DEBUG_ASSERT(_locked != NULL);

            isWriter? _locked->unlockWriter() : _locked->unlockReader();
			_locked = NULL;
		}

	private:
		GLM_DISALLOW_COPY_AND_ASSIGN(ScopedLockRW);

		Lockable* _locked;
	};
}
#endif // GLMSCOPEDLOCK_H
