#include "operatingsystem.h"
#include "c4d_memory.h"
#include "c4d_thread.h"

void XThreadMain(void *data)
{
	((C4DThread*)data)->Main();
}

Bool XThreadTest(void *data)
{
	return ((C4DThread*)data)->TestDBreak();
}

static const CHAR *XThreadName(void *data)
{
	return ((C4DThread*)data)->GetThreadName();
}

C4DThread::C4DThread(void)
{
	weak=FALSE;
	bt=C4DOS.Bt->Alloc(XThreadMain,XThreadTest,this,XThreadName);
}

C4DThread::~C4DThread(void)
{
	if (!weak) C4DOS.Bt->Free(bt);
}

Bool C4DThread::Start( THREADMODE mode, THREADPRIORITY priority )
{
	if (!bt) return FALSE;
	return C4DOS.Bt->Start( bt, mode, priority, NULL );
}

void C4DThread::End(Bool wait)
{
	if (bt) C4DOS.Bt->End(bt,wait);
}

void C4DThread::Wait(Bool checkevents)
{
	if (bt) C4DOS.Bt->Wait(bt,checkevents);
}

GeSignal *GeSignal::Alloc(void)
{
	return C4DOS.Bt->SIGAlloc();
}

void GeSignal::Free(GeSignal *&sm)
{
	C4DOS.Bt->SIGFree(sm);
}

Semaphore *Semaphore::Alloc(void)
{
	return C4DOS.Bt->SMAlloc();
}

void Semaphore::Free(Semaphore *&sm)
{
	C4DOS.Bt->SMFree(sm);
}

MPThreadPool::MPThreadPool(void) 
{ 
	mp=NULL; 
	mpcount=0;
}

MPThreadPool::~MPThreadPool(void)
{
	if (!mp) return;
	C4DOS.Bt->MPEnd(mp);
	C4DOS.Bt->MPFree(mp);
	mp=NULL;
}

Bool MPThreadPool::Init(const C4DThread &parent, LONG count, C4DThread **thread)
{
	return Init(parent.Get(),count,thread);
}

Bool MPThreadPool::Init(BaseThread *parent, LONG count, C4DThread **thread)
{
	if (mp) { C4DOS.Bt->MPFree(mp); mp=NULL; mpcount=0; }

	mpcount=count;
	mp=C4DOS.Bt->MPAlloc(parent,count,XThreadMain,XThreadTest,(void**)thread,XThreadName);

	LONG i;	
	for (i=0; i<count; i++)
	{
		if (!thread[i]->weak)
		{
			thread[i]->weak=TRUE;
			C4DOS.Bt->Free(thread[i]->bt);
		}
		thread[i]->bt=C4DOS.Bt->MPGetThread(mp,i);
	}

	return mp!=NULL;
}

Bool MPThreadPool::Start(THREADPRIORITY worker_priority)
{
	BaseThread *bt=NULL;
	LONG i;

	for (i=0; i<mpcount; i++)
	{
		bt=C4DOS.Bt->MPGetThread(mp,i);
		if (!bt || !C4DOS.Bt->Start(bt,THREADMODE_ASYNC,worker_priority,FALSE)) 
		{
			C4DOS.Bt->MPEnd(mp);
			return FALSE;
		}
	}

	return TRUE;
}

C4DThread *MPThreadPool::WaitForNextFree(void)
{
	return (C4DThread*)C4DOS.Bt->MPWaitForNextFree(mp);
}

void MPThreadPool::Wait(void)
{
	C4DOS.Bt->MPWait(mp);
}

void MPThreadPool::End(void)
{
	C4DOS.Bt->MPEnd(mp);
}
