// Common, groups WinWrap, Thread
// Copyright Alexander Liss

#include <process.h>
#include "thread.h"

	// Thread

void Thread::selfdestruct()
{ 
	// this order !
	destruct=true; 
	loop_sleep=0;
	wake_up();
}

	// AsyncStep

int AsyncStep::loop(bool& continue_loop)
{
	continue_loop=true; 
	
	int g=respond(); 
	
	if(g) return g; 
	
	wait(thread_event); 
	
	return 0;
}

	// ThreadControl


// creates the thread, which begins executing using the Thread OBJECT
int ThreadControl::launch( Thread& cThread,
           unsigned uInitFlag, 
           LPSECURITY_ATTRIBUTES lpSecurity, 
           unsigned uStackSize)
{

	thread_object=&cThread;

	if(! thread_object)
	{
		status = 1;
		return 1;
	}
     

    handle = (HANDLE) _beginthreadex( lpSecurity, uStackSize, thread_procedure, thread_object, uInitFlag, &thread_id);


    if (is_valid_handle(handle)) 
	{
        status = NO_ERROR; // 0
    }
	else
	{
		status = errno;
		return 2;
	}

	return 0;

}


unsigned _stdcall ThreadControl::thread_procedure(void *pThread) 
{

	int hr1=0,hr2=0,hr3=0,hr4=0;
	bool loop=true;
    Thread *p_thread = static_cast<Thread *>(pThread);
 
	if(p_thread->destruct)
	{
		_endthreadex(0);
		return destructed;
	}

	hr1=p_thread->startup(); 
    

    if(! hr1)
		while(loop)
		{

			if(p_thread->destruct)
			{
				hr2=1;
				break;
			}

			hr3=p_thread->loop(loop);

			if(hr3) break;

			if(p_thread->destruct)
			{
				hr2=1;
				break;
			}

			if(p_thread->loop_sleep>0)
				wait(p_thread->thread_event,p_thread->loop_sleep);
				//Sleep(p_thread->loop_sleep);
		}

	hr4=p_thread->cleanup();


	unsigned hr=0;

	if(hr1) hr=failed_startup;
	else if(hr2) hr=destructed;
	else if(hr3) hr=bad_loop;
	else if(hr4) hr=failed_cleanup;

	 _endthreadex(hr);
	 
	 return hr;
}
            
// suspend the thread
DWORD ThreadControl::suspend() 
{
	if(! thread_object)
		return 0xFFFFFFFF;
 
    return ::SuspendThread( handle);
}

// resume the thread
DWORD ThreadControl::resume() 
{
	if(! thread_object)
		return 0xFFFFFFFF;

    return ::ResumeThread( handle);
}

// terminate the thread
BOOL ThreadControl::terminate( DWORD dwExitCode) 
{
	if(! thread_object)
		return FALSE;

    return ::TerminateThread( handle, dwExitCode);
}

// read a thread's exit code
BOOL ThreadControl::get_exit_code( DWORD *pdwExitCode) 
{
	if(! thread_object)
		return FALSE;

    return ::GetExitCodeThread( handle, pdwExitCode);
}

// set a thread's priority
BOOL ThreadControl::set_priority( int nPriority) 
{
	if(! thread_object)
		return FALSE;

    return ::SetThreadPriority( handle, nPriority);
}

// read a thread's priority
int ThreadControl::get_priority() 
{
	if(! thread_object)
		return 0;

    return ::GetThreadPriority( handle);
}

// return the thread's identifier
DWORD ThreadControl::get_thread_id()const
{
	if(! thread_object)
		return 0;

    return static_cast<DWORD>(thread_id);
}

#if(_WIN32_WINNT >= 0x0400)
DWORD ThreadControl::queue_APC(PAPCFUNC pfnAPC,DWORD dwData)
{
	if(! thread_object || !handle)
		return 0;

	return ::QueueUserAPC(pfnAPC,handle,dwData);

}
#endif