#include "deThread_priv.hpp"

#ifdef DESTINY3D_PLATFORM_WIN32

deThread::deThread(ThreadProc threadProc)
:	mThreadProc(threadProc),
	mThreadHandle(0),
	mThreadId(0)
{
}

deThread::~deThread()
{
	if (mThreadHandle)
	{
		// wait for the thread to terminate (immediate return if it's done already)
		Join(0);
	}
}

deBoolean deThread::Start(void* parameter)
{
	if (IsRunning())
		DEBUGRETURN(deFALSE, "deThread::Start - already running a thread");
	mThreadHandle =CreateThread(0,
								0, 
								reinterpret_cast<LPTHREAD_START_ROUTINE>(mThreadProc), 
								parameter, 
								0, 
								&mThreadId);
	if (!mThreadHandle)
		DEBUGRETURN(deFALSE, "deThread::Start - invalid thread handle");
	return deTRUE;
}

deBoolean deThread::IsRunning()
{
	if (!mThreadHandle)
		return deFALSE; // not started yet
	DWORD retVal = WaitForSingleObject(mThreadHandle, 0);
	if(retVal == WAIT_TIMEOUT)
		return deTRUE;
	return deFALSE;
}

u32 deThread::GetReturnValue(deBoolean WaitForExit)
{
	if (!mThreadHandle)
		DEBUGRETURN(0, "deThread::GetReturnValue - invalid thread handle");
	DWORD exitCode = 0;
	BOOL isValid = GetExitCodeThread(mThreadHandle, &exitCode);
	if (isValid && exitCode == STILL_ACTIVE)
	{
		if (WaitForExit)
		{
			Join(0);
			isValid = GetExitCodeThread(mThreadHandle, &exitCode);
		}
		else
			return 0;
	}
	if (!isValid)
		DEBUGRETURN(0, "deThread::GetReturnValue - GetExitCodeThread() failed");
	return exitCode;
}

s32 deThread::Release()
{
	if (mThreadHandle && mThreadId == GetCurrentThreadId())
		DEBUGRETURN(1, "deThread::Release - aborted to avoid deadlock (thread terminating self)");
	delete this;
	return 0;
}

void deThread::Join(MessageHandler mh)
{
	if(mh) {
		DoMessageJoin(mh);
	} else {
		DoWaitJoin();
	}
}

void deThread::DoMessageJoin(MessageHandler mh)
{
	DWORD retVal;
	while(true) {
		(mh)();
		retVal = MsgWaitForMultipleObjects(1, &mThreadHandle, FALSE, INFINITE, QS_ALLINPUT);
		if(retVal == WAIT_OBJECT_0 + 1) { //Message
			continue;
		} else if(retVal == WAIT_OBJECT_0) { //thread done.
			break;
		}
	}
	CloseHandle(mThreadHandle);
	mThreadHandle = 0;
	mThreadId = 0;
}

void deThread::DoWaitJoin()
{
	WaitForSingleObject(mThreadHandle, INFINITE);
	CloseHandle(mThreadHandle);
	mThreadHandle = 0;
}

DETHREAD_API IdeThread* IdeThread_CreateThread(IdeThread::ThreadProc threadProc)
{
	if (!threadProc)
		DEBUGRETURN(NULL, "IdeThread_CreateThread - invalid threadProc argument (NULL)");
	return new deThread(threadProc);
}

#elif defined(DESTINY3D_PLATFORM_LINUX)
#error linux threading system not yet implemented
#else
#error unsupported platform configuration
#endif
