// ------------------------------------------------------------------
//	File: gtbase.h
//
//
// ==================================================================
// IF YOU DO NOT AGREE WITH THE FOLLOWING STATEMENT, YOU MUST 
// PROMPTLY RETURN THE SOFTWARE AND ANY ACCOMPANYING DOCUMENTATION 
// ("PRODUCT") TO PCBest Networks(www.pcbest.net).
//
// PCBest Networks owns all title and 
// ownership rights to Software.  "Software" means any data processing
// programs (hereinafter "programs") consisting of a series of 
// instructions or statements in object code form, including any 
// systemized collection of data in the form of a data base, and any
// related proprietary materials such as flow charts, logic diagrams, 
// manuals media and listings provided for use with the programs.
// User has no right, express or implied, to transfer, sell, provide
// access to or dispose of Software to any third party without PCBest Networks'
// prior written consent.  User will not copy, reverse assemble,
// reverse engineer, decompile, modify, alter, translate or display
// the Software other than as expressly permitted by PCBest Networks in writing.
// ------------------------------------------------------------------

#if !defined(__GTAPI_BASE_HEADER_FILE_H)
#define __GTAPI_BASE_HEADER_FILE_H

#include "GTTypes.h"
#include <time.h>

#if (defined(WIN32) || defined(_WIN32_WCE))

	typedef DWORD			timeout_t;

#ifndef MAX_SEM_VALUE
	#define	MAX_SEM_VALUE	0x7fffffff
#endif

#else // WIN32

	#include <pthread.h>
	#include <semaphore.h>
	
	typedef	unsigned long	timeout_t;

	#define INFINITE		~((timeout_t) 0)
	#define TIMEOUT_INF		~((timeout_t) 0)

#endif //WIN32


#ifdef USE_GTAPI_NAMESPACE
namespace GTAPI
{
#endif

	#if (defined(WIN32) || defined(_WIN32_WCE))

	class GT_DLL_API CCriticalSection
	{
	public:
		CCriticalSection()          { InitializeCriticalSection(&m_CS); }
		virtual ~CCriticalSection() { DeleteCriticalSection(&m_CS); }

		bool Lock()					{ EnterCriticalSection(&m_CS); return true; }
		bool Unlock()				{ LeaveCriticalSection(&m_CS); return false;}
//		bool TryLock()				{ return (TryEnterCriticalSection(&m_CS) != FALSE); }

	private:
		CRITICAL_SECTION m_CS;
	}; // class CCriticalSection

	#else /* POSIX */

	#include <pthread.h>

	class GT_DLL_API CCriticalSection
	{
	public:
		CCriticalSection(int recursive = 1)
		{
			// We really heavily on recursive critical sections
			// Note that the recursive mutex is non-portable
			pthread_mutex_init(&m_Mutex, NULL);
			if (recursive) 
			{
				#ifdef __linux__
					m_Mutex.__m_kind = PTHREAD_MUTEX_RECURSIVE_NP;
				#else
					#error We need a recursive mutex
				#endif
			}
		}
		
		virtual ~CCriticalSection() { pthread_mutex_destroy(&m_Mutex); }

		bool Lock()              { pthread_mutex_lock(&m_Mutex); return true;}
		bool Unlock()            { pthread_mutex_unlock(&m_Mutex); return true;}
		bool TryLock(unsigned int timeout = 0)           { return (pthread_mutex_trylock(&m_Mutex) == 0); }

		// This is for CConditionVar
		//pthread_mutex_t *getMutex() { return &m_Mutex; }

	private:
		pthread_mutex_t m_Mutex;
	}; // class CCriticalSection

	#endif /* _WIN32 */	


	#if (defined(WIN32) || defined(_WIN32_WCE))

	class GT_DLL_API CMutex
	{
	public:
		CMutex()					{ m_hSyncObj = ::CreateMutex(NULL,FALSE, NULL);if(!m_hSyncObj)throw(this); }
		virtual ~CMutex()			{ if(m_hSyncObj){::CloseHandle(m_hSyncObj);m_hSyncObj = 0;} }

		bool Lock()					{ if(m_hSyncObj){return WaitForSingleObject(m_hSyncObj, INFINITE) == WAIT_OBJECT_0;} return false;}
		bool Unlock()				{ if(m_hSyncObj){if(ReleaseMutex(m_hSyncObj)) return true; return false;} return false;}
		bool TryLock(unsigned int timeout = 0)				{ if(m_hSyncObj){return WaitForSingleObject(m_hSyncObj, timeout) == WAIT_OBJECT_0;} return false;}

		//HANDLE getHandle()          {return m_hSyncObj;}

	private:
		HANDLE m_hSyncObj;
	};

	#else /* POSIX */

	class GT_DLL_API CMutex : public CCriticalSection
	{
	public:
		CMutex():CCriticalSection(){}
		virtual ~CMutex(){}
	};

	#endif


	class GT_DLL_API CMutexLock
	{
	public:
		/**
		* Acquire the mutex
		*
		* @param _mutex reference to mutex to aquire.
		*/
		CMutexLock( CMutex& _mutex ) : mutex( _mutex ) 
			{ mutex.Lock(); }

		/**
		* Release the mutex automatically
		*/
		virtual ~CMutexLock()
			{ mutex.Unlock(); }

	protected:
		CMutex& mutex;
		
	};


	#if (defined(WIN32) || defined(_WIN32_WCE))

	class GT_DLL_API CSemaphore
	{
	public:
		CSemaphore()          { m_Semaphore = CreateSemaphore(NULL, 0, MAX_SEM_VALUE, NULL); }
		virtual ~CSemaphore() { CloseHandle(m_Semaphore); }

		bool    Wait()        { return WaitForSingleObject(m_Semaphore, INFINITE) == WAIT_OBJECT_0; }
		bool    TryWait(unsigned int timeout = 0)     { return WaitForSingleObject(m_Semaphore, timeout) == WAIT_OBJECT_0; }
		void	Post()		  { ReleaseSemaphore(m_Semaphore, 1, NULL); }

	private:
		HANDLE m_Semaphore;
	}; // class CSemaphore

	#else /* POSIX */

	#include <semaphore.h>

	class GT_DLL_API CSemaphore
	{
	public:
		CSemaphore()          { sem_init(&m_Semaphore, 0, 0); }
		virtual ~CSemaphore() { sem_destroy(&m_Semaphore);}
		
		bool	Wait()        { return sem_wait(&m_Semaphore) == 0; }
		bool    TryWait(unsigned int timeout = 0)     { return sem_trywait(&m_Semaphore) == 0; }
		void	Post()		  { sem_post(&m_Semaphore); }

	private:
		sem_t m_Semaphore;
	}; // class CSemaphore

	#endif /* _WIN32 */


	class GT_DLL_API CSemaphoreLock
	{
	private:
		CSemaphore& sem;

	public:
		/**
		* Wait for the semaphore
		*/
		CSemaphoreLock( CSemaphore& _sem ) : sem( _sem ) { sem.Wait(); }
		/**
		* Post the semaphore automatically
		*/
		// this should be not-virtual
		~CSemaphoreLock(){ sem.Post(); }
	};



#if (defined(WIN32) || defined(_WIN32_WCE))
	class GT_DLL_API CEvent
	{
	public:
		CEvent()          { m_Event = CreateEvent(NULL, FALSE,  FALSE, NULL); }
		virtual ~CEvent() { CloseHandle(m_Event);}
		
		bool    Wait()        { return WaitForSingleObject(m_Event, INFINITE) == WAIT_OBJECT_0; }
		bool    TryWait(unsigned int timeout = 0)     { return WaitForSingleObject(m_Event, timeout) == WAIT_OBJECT_0; }
		void	Post()		  { SetEvent(m_Event); }

	private:
		HANDLE m_Event;
	};

#else

	#define CEvent CSemaphore

#endif

#if (defined(WIN32) || defined(_WIN32_WCE))
	typedef	DWORD			gt_tid_t;
	typedef HANDLE			gt_thrd_t;
#else
	typedef	pthread_t		gt_tid_t;
	typedef pthread_t		gt_thrd_t;
	typedef	void	*(*gt_exec_t)(void *);
#endif

	class GT_DLL_API CBaseThread
	{
	public:
		//////////////contructor and destrcutor//////////////
		CBaseThread();
		virtual ~CBaseThread();

#if defined(_DEBUG) || defined(GT_CHECK_CPU_TIME) || defined(GTAPI_DETECT_THREAD_ACTIVE)
		time_t m_tLastCheck;

		char m_sThreadName[81];
		virtual const char* GetThreadClassName(){strcpy(m_sThreadName, "CBaseThread"); return m_sThreadName;}
#endif

	///////////interfaces for thread initialization
	public:
		virtual				bool TCreate(bool bRunNow=true);
		virtual				bool TDestroy(timeout_t timeout=INFINITE);

		//for long sleep over 200 milli-seconds
		virtual				void TSleep(timeout_t timeout);
		
		virtual				gt_thrd_t	CreateThread(bool bRunNow=true);

		bool				ResumeThread(void);
		bool				SuspendThread(void);
		bool				TerminateThread(unsigned long dwExitCode);

		/////////////////////////////////////////////////////////////////////////////
		/// Thread stopping function
		/////////////////////////////////////////////////////////////////////////////
		virtual				void SignalStop();
		bool				Join(timeout_t timeout);
		bool				Quit(timeout_t timeout){SignalStop();return Join(timeout);}


		static void			Sleep(timeout_t timeout);
		static gt_tid_t		GetThreadID();
		
		virtual				GT_BOOL	SetPriority(GT_INT p);

	protected:

		virtual				void OnQuit();
		virtual				void OnCreate();

		virtual				bool DoUnblockedLoop();

		virtual				void BeforeRun();
		virtual				unsigned long Run();
		virtual				void AfterRun();

		bool				WaitUntillStop(timeout_t timeout=INFINITE);


		unsigned long	GetExitCodeThread(){return m_ExitCode;}
		bool				IsActive();


	public:
		enum				THREAD_STATUS
		{
			THREAD_STATUS_INIT				=0,
			THREAD_STATUS_CREATED			,
			THREAD_STATUS_RUNNING			,
			THREAD_STATUS_SUSPENDED			,
			THREAD_STATUS_SIGNAL_STOPPED	,
			THREAD_STATUS_STOPPED
		};

		THREAD_STATUS		GetThreadStatus();

	protected:
		void				SetThreadStatus(THREAD_STATUS sts);

	protected:

		gt_thrd_t			m_hThread;
		gt_tid_t			m_ThreadID;

		THREAD_STATUS		m_ThreadStatus;
		CMutex				m_mtxThreadStatus;

		unsigned long		m_ExitCode;

		bool				m_bExit;

	public:

		#if (defined(WIN32) || defined(_WIN32_WCE))
			friend DWORD WINAPI BaseThreadProc(LPVOID pParam);
		#else
			friend static void* BaseThreadProc(void *pParam);
		#endif

	};





#ifdef USE_GTAPI_NAMESPACE
}
#endif


#endif