#pragma once

namespace FDK
{
	private struct CritSec
	{
	public:
		CritSec()
		{
			::InitializeCriticalSection( &m_criticalSection );
			this->bLocked = false;
		}
		~CritSec()
		{
			this->Unlock();
			::DeleteCriticalSection( &m_criticalSection );
		}

		void Lock()
		{
			::EnterCriticalSection( &m_criticalSection );
			this->bLocked = true;
		}
		void Unlock()
		{
			if( this->b自スレッドがLock中() )	// 自分がロックしてないときに Leave を呼び出すと、他の Enter 待ちスレッドにエラーが発生する。（MSDNより）
			{
				this->bLocked = false;
				::LeaveCriticalSection( &m_criticalSection );
			}
		}
		bool b自スレッドがLock中()
		{
			BOOL bEntered = ::TryEnterCriticalSection( &m_criticalSection );

			if( FALSE == bEntered )			// Enter できなかったら
				return false;				// 自分以外の誰かがロック中である。
			
			::LeaveCriticalSection( &m_criticalSection );		// Enter できたので Leave する。これは TryEnter で取得された分の Leave であり、もしそれ以前に自分が Enter していたとしても、それは Leave されないままである。

			if( false == this->bLocked )	// Enter できたが bLocked が false のままなら、Lock() メソッドではなく先の TryEnter で自分がロックした、
				return false;				// すなわち（自分も含めて）誰も Lock() メソッドを呼び出してなかったことを示す。

			return true;					// Enter できて、かつ bLocked が true なら、自分が先に Lock() したままである。
		}
		bool b誰かがLock中()
		{
			BOOL bEntered = ::TryEnterCriticalSection( &m_criticalSection );

			if( FALSE == bEntered )			// Enter できなかったら
				return true;				// 自分以外の誰かがロック中である。

			::LeaveCriticalSection( &m_criticalSection );		// Enter できたので Leave する。これは TryEnter で取得された分の Leave であり、もしそれ以前に自分が Enter していたとしても、それは Leave されないままである。

			if( false == this->bLocked )	// Enter できたが bLocked が false のままなら、Lock() メソッドではなく先の TryEnter で自分がロックした、
				return false;				// すなわち（自分も含めて）誰も Lock() メソッドを呼び出してなかったことを示す。

			return true;					// Enter できて、かつ bLocked が true なら、自分が先に Lock() したままである。
		}

	private:
		CRITICAL_SECTION m_criticalSection;
		bool bLocked;
	};
}
