//////////////////////////////////////////////////////////////////////////////////////
// THis header is devoted to providing (potentially cross-platform) safe and easy
// mechanism to use synchronization primitives OS presents to the programmer
//
// CONTAINS declaration of the following synchronization primitives:
//  Critical Section
//  Mutex
//  Event (in the sense of Windows)
//
// The paradigm is to create primitives (like critical section) as objects that auto-
// construct and destruct the underlying OS-specific structures, and if pair operations
// (lock/unlock) need to be performed, then use other primitives (auto-lock) that need
// only be mentioned once in the code.
// 
// No operation must be smeared in the code -
// it must be atomic. E.g. when you want to lock something for some time, you should
// create an auto-lock object that will lock this something in constructor and unlock it
// (without your intervention) in the destructor. This had an additional advantage
// of unlocking your primitive when a C++ exception is thrown
//////////////////////////////////////////////////////////////////////////////////////

#ifndef _MIGDALSKIY_SYNCHRNONIZE_HDR__
#define _MIGDALSKIY_SYNCHRNONIZE_HDR__

namespace util
{
/////////////////////////////////////////////////////////////////////////////////////
// Safe critical section robot: when constructing, it's locking the section, when
//  destructing, it's unlocking it
/////////////////////////////////////////////////////////////////////////////////////
template <class T>
class CAutoLock
{
	T& m_csThis; // the critical section that is to be locked on construction and unlocked on destruction
public:
	// on construction, we lock the critical section
	CAutoLock(T& csThis):
		m_csThis(csThis)
	{
		csThis.Lock();
	}
	// on destruction, we unlock it
	~CAutoLock()
	{
		m_csThis.Unlock();
	}
};

/////////////////////////////////////////////////////////////////////////////////////
// The opposite to CAutoLock. An instance of this class unlocks the primitive T
// until destruction (then it locks it up again). Useful for temporary release of 
// resourse in some lengthy algorithms
/////////////////////////////////////////////////////////////////////////////////////
template <class T>
class CAutoUnlock
{
	T& m_csThis; // the critical section that is to be locked on construction and unlocked on destruction
public:
	// on construction, we UNlock the critical section
	CAutoUnlock (T& csThis):
		m_csThis(csThis)
	{
		csThis.Unlock();
	}
	// on destruction, we LOCK it
	~CAutoUnlock()
	{
		m_csThis.Lock();
	}
};


/////////////////////////////////////////////////////////////////////////////////////
// Abstraction of critical section synchronization object. Auto-constructs/destructs
// the embedded critical section
/////////////////////////////////////////////////////////////////////////////////////
class CCritSection
{
	CRITICAL_SECTION // embedded critical section
		csThis;

public:
	// creates a critical section primitive
	CCritSection();
	// destructs the critical section primitive
	~CCritSection();
	// locks the critical section primitive
	void Lock ();
	// unlocks the critical section primitive
	void Unlock ();

	// the lock and unlock facilities may be disabled for explicit use,
	// the client functions should use auto-lockers and auto-unlockers instead
private:
	// copying of critical section is not what we'd like to have in some cases, so disable it
	// by declaring the constructor private
	CCritSection (const CCritSection &);

	// only the auto-lock classes may always explicitly call Lock and Unlock facilities of this primitive
	friend class CAutoLock<CCritSection>;
	friend class CAutoUnlock<CCritSection>;
};

/////////////////////////////////////////////////////////////////////////////////////////////
// Wrapper around Mutex synchronization primitive
// This is essentially the same as critical section, but is slower and has additional advantage
// of the interprocess communication/synchronization capability
/////////////////////////////////////////////////////////////////////////////////////////////
class CMutex
{
	// the native OS handle of the primitive
	HANDLE hMutex;
public:
	// flags used in creation of shared memory file
	enum {
		nFlagAllowAccessAll = 1 // set security descriptor to "Allow Access to Everyone"
	};

	// creates the mutex, optionally (with non-null szName) named and optionally with security descriptor set to "Allow Access to Everyone" (if flags specify)
	CMutex (const char* szName = NULL, DWORD dwFlags = 0);
	// destructs/closes the mutex; it doesn't get closed (naturally) if another process is using it
	~CMutex ();
	// locks the mutex
	void Lock();
	// unlocks the mutex
	void Unlock();

	// NOTE: Lock and Unlock() facitlities may be disabled for explicit use to improve robustness
	//       and theoretical deadlock-proofs
private:
	// copying of mutex is not what we'd like to have in some cases, so disable it
	// by declaring the constructor private
	CMutex (const CMutex&);

	// only the auto-lock classes may always explicitly call Lock and Unlock facilities of this primitive
	friend class CAutoLock<CMutex>;
	friend class CAutoUnlock<CMutex>;
};

///////////////////////////////////////////////////////////////////////////////////
// Wrapper around Windows Event primitive
// Provides the same functionality through object-oriented interface
///////////////////////////////////////////////////////////////////////////////////
class CEvent
{
	// embedded event handle
	HANDLE hEvent;
public:
	// enumeration that defines the flags modifying behaviour of the event object
	enum {
		nFlagManualReset = 1
	};

	// creates event optionally with modified by flags behaviour
	CEvent(DWORD dwFlags = 0);
	
	// destructs the event
	~CEvent()
	{
		CloseHandle(hEvent);
	}
	
	// copies the event
	CEvent(const CEvent& rEvent)
	{
		DuplicateHandle (GetCurrentProcess(), rEvent.hEvent, GetCurrentProcess(), &hEvent, 0, FALSE, DUPLICATE_SAME_ACCESS);
	}

	// signals the event
	void Signal() {SetEvent(hEvent);}
	// resets the event
	void Reset() {ResetEvent(hEvent);}

	// converts to the Windows handle
	operator HANDLE(){return hEvent;}

	// waits for the primitive for specified amount of time,
	// returns true if wais satisfied and false upon error or timeout
	bool Wait (DWORD dwInterval = INFINITE) {return WaitForSingleObject(hEvent, dwInterval) == WAIT_OBJECT_0;}
};

}

// set of macros defining autolocking functionality
// you can either specify one of AUTO_* macros at the beginning of the block of code
// to lock/unlock automatically, or specify AUTO_*_BEGIN and AUTO_*_END for creating
// end denoting the block of code protected by lock

#define AUTO_LOCK_MTX(mtxLock) util::CAutoLock<util::CMutex> __AL__##mtxLock(mtxLock)
#define AUTO_LOCK(csLock) util::CAutoLock<util::CCritSection> __AL__##csLock(csLock)
#define AUTO_LOCK_THIS() util::CAutoLock<util::CCritSection> __AL__this(*this)

#define AUTO_UNLOCK(csUnlock) util::CAutoUnlock<util::CCritSection> __AUl__##csUnlock(csUnlock)

#endif
