///////////////////////////////////////////////////////////////////////////////
/// @file deThread.hpp
///
/// @brief base header for threads
///
/// @author Washu
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date Jul 2004
/// @author Washu
/// @remarks Initial Creation
///////////////////////////////////////////////////////////////////////////////

#ifndef DETHREAD_HPP
#define DETHREAD_HPP

#include "deGlobalTypes.hpp"

#if defined(DEUTIL_DLL_EXPORTS) || defined(DESTINY3D_EXPORT_ALL)
#	define DETHREAD_API extern "C" DEDLL_EXPORT
#elif defined(DESTINY3D_STATIC_LINK)
#	define DETHREAD_API extern "C" 
#else
#	define DETHREAD_API extern "C" DEDLL_IMPORT
#endif

#ifdef USING_DESTINY3D
#ifdef _DEBUG
#	ifdef DESTINY3D_STATIC_LINK
#		pragma comment(lib, "deUtil_sd")
#	else
#		pragma comment(lib, "deUtild")
#	endif //DESTINY3D_STATIC_LINK
#else
#	ifdef DESTINY3D_STATIC_LINK
#		pragma comment(lib, "deUtil_s")
#	else
#		pragma comment(lib, "deUtil")
#	endif //DESTINY3D_STATIC_LINK
#endif //_DEBUG
#endif //USING_DESTINY3D

class IdeThread;
class IdeThreadLock;

/// Thread encapsulation structure.
DE3D_INTERFACE_(IdeThread)
{
public:
	/// ThreadProc is the function signature for thread execution routines.
	typedef u32 (*ThreadProc)(void*);
	typedef void (*MessageHandler)(void);

	/// Begin execution of the associated routine, passing in the specified parameter.
	/// This method can fail if a thread is already running or if the operating system cannot start the routine.
	/// @param parameter Value to pass into the thread execution routine.
	/// @return deTRUE if thread was started successfully, deFALSE on failure.
	virtual deBoolean Start(void* parameter) = 0;
	/// Test whether the thread is executing. 
	virtual deBoolean IsRunning() = 0;
	/// Retrieves the value returned by the thread execution routine.
	/// Note: if the thread has not been started or has not completed, the return value
	///   is undefined.
	/// @param waitForExit Causes the querying thread to block until the queried thread terminates.
	/// @return The value returned by the associated ThreadProc.
	virtual u32 GetReturnValue(deBoolean waitForExit = deTRUE) = 0;
	/// Releases & destroys a thread. This will block until the thread completes execution.
	/// Note that the block would cause a deadlock if called from the thread being contained,
	///   so such a call will fail - the thread must be released from within another thread.
	virtual s32 Release() = 0;
	/// Wait for the target thread to finish executing, with an optional message-handler callback.
	/// If the system receives any signals for this thread while waiting for the target thread
	///   to terminate, the message handler will be executed.
	/// @param handler a callback to be called when any system events arrive for the calling thread.
	virtual void Join(MessageHandler handler) = 0;
protected:
	virtual ~IdeThread() {}
};

/// Thread synchronization handler.
DE3D_INTERFACE_(IdeThreadLock)
{
public:
	/// Acquires an exclusive lock in the currently executing thread.
	/// This method will block until other threads relinquish the lock.
	/// Each Lock or successful TryLock call must be paired with an Unlock call.
	virtual void Lock() = 0;
	/// Relinquishes an exclusive lock, signaling any threads that are waiting for
	///   this lock object to be relinquished.
	virtual void Unlock() = 0;
	/// Attempts to acquire an exclusive lock in the currently executing thread.
	/// Each Lock or successful TryLock call must be paired with an Unlock call.
	/// @return deTRUE if the lock was acquired, deFALSE if another thread holds the lock.
	virtual deBoolean TryLock(u32 waitTimeInMs) = 0;
	/// Releases & destroys a lock object.
	/// This will block until the current thread can acquire this lock, and will then proceed.
	virtual s32 Release() = 0;
protected:
	virtual ~IdeThreadLock() {}
};

/// Manager class for avoiding threading overhead when many short-lived threads are needed.
DE3D_INTERFACE_(IdeThreadPool)
{
public:
	/// Adds a work item to the queue. It will be executed immediately if a thread is
	///   available to process it, otherwise it will wait for a thread to become available.
	/// This function will return immediately, whether the work item was executed or not.
	virtual void QueueUserWorkItem(IdeThread::ThreadProc function, void* parameter) = 0;
	/// 
	virtual u32 GetAvailableThreadCount() = 0;
	virtual u32 GetCurrentThreadCount() = 0;
	virtual void RemoveUnusedThreads() = 0;
protected:
	virtual ~IdeThreadPool() {}
};

class deThreadScopeLock
{
private:
	IdeThreadLock* mLockObj;
public:
	inline deThreadScopeLock(IdeThreadLock* lockObj) : mLockObj(lockObj) { mLockObj->Lock(); }
	inline ~deThreadScopeLock() { mLockObj->Unlock(); }
};

/// Create an IdeThread object
DETHREAD_API IdeThread* IdeThread_CreateThread(IdeThread::ThreadProc threadProc);
/// Create an IdeThreadLock synchronization object
DETHREAD_API IdeThreadLock* IdeThreadLock_CreateThreadLock(u32 spinCount = 1024);
DETHREAD_API IdeThreadPool* IdeThreadPool_GetPtr(u32 minThreadCount);
DETHREAD_API void IdeThreadPool_Destroy();

#endif //DETHREAD_HPP