/*
 * Copyright (c) 2005-2006 Tom N Harris.
 *
 *     This program is free software; you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation; either version 2 of the License, or
 *     (at your option) any later version.
 *
 *     A copy of the GNU General Public License can be found at
 *     http://www.gnu.org/
 *
 * Written by Tom N Harris <telliamed@whoopdedo.org>
 *
 */

 // This implementation can be broken very easily. 
 //Don't do anything stupid.

#include <process.h>

#include "Thread.h"

using namespace Setup;


unsigned __stdcall 
Thread::thread_callback(void* data)
{
	Thread* _This = reinterpret_cast<Thread*>(data);
	_This->run();
	_This->exit();
	return 0;
}

Thread::Thread()
{
	m_handle = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, 
					    thread_callback, this, 
					    CREATE_SUSPENDED, 
					    reinterpret_cast<unsigned*>(&m_threadId)));
}

Thread::~Thread()
{
	if (isAlive())
	{
		if (isCurrentThread())
			exit(0);
		else
			stop(0);
	}
	::CloseHandle(m_handle);
}

void 
Thread::start()
{
	::ResumeThread(m_handle);
}

void 
Thread::stop(DWORD exit_code)
{
	::TerminateThread(m_handle, exit_code);
}

void 
Thread::suspend()
{
	::SuspendThread(m_handle);
}

void 
Thread::resume()
{
	::ResumeThread(m_handle);
}

void 
Thread::exit(DWORD exit_code)
{
	_endthreadex(exit_code);
}

bool 
Thread::isCurrentThread() const
{
	return m_threadId == ::GetCurrentThreadId();
}

bool 
Thread::isAlive() const
{
	DWORD exit_code;
	if (::GetExitCodeThread(m_handle, &exit_code))
		return exit_code == STILL_ACTIVE;
	return false;
}

DWORD 
Thread::getExitCode() const
{
	DWORD exit_code;
	if (::GetExitCodeThread(m_handle, &exit_code))
		return exit_code;
	return ::GetLastError();
}

int 
Thread::getPriority() const
{
	return ::GetThreadPriority(m_handle);
}

void
Thread::setPriority(int priority)
{
	::SetThreadPriority(m_handle, priority);
}

bool 
Thread::waitForExit(DWORD time)
{
	return WAIT_OBJECT_0 == ::WaitForSingleObject(m_handle, time);
}

void 
Thread::sleep(DWORD time)
{
	::Sleep(time);
}

void 
Thread::wait(DWORD time)
{
	::SleepEx(time, TRUE);
}

