/////////////////////////////////////////////////////////////
// CINEMA 4D SDK                                           //
/////////////////////////////////////////////////////////////
// (c) 1989-2004 MAXON Computer GmbH, all rights reserved  //
/////////////////////////////////////////////////////////////

#ifndef __C4DTHREAD_H
#define __C4DTHREAD_H

#include "operatingsystem.h"

class BaseThread
{
	private:
		BaseThread();
		~BaseThread();
	public:
		Bool TestBreak(void) { return C4DOS.Bt->TestBreak(this); }
		void End(Bool wait=TRUE) { C4DOS.Bt->End(this,wait); }
		Bool IsRunning(void) { return C4DOS.Bt->IsRunning(this); }
};

#define THREADPRIORITY_NORMAL	0
#define THREADPRIORITY_ABOVE	1000
#define THREADPRIORITY_BELOW	1001

class Thread
{
	friend class MPThread;
	friend void XThreadMain(void *data);
	friend Bool XThreadTest(void *data);

	private:
		Bool				weak;
		BaseThread	*bt;
	public:
		Thread(void);
		virtual ~Thread(void);

		BaseThread *Get(void) const { return bt; }

		Bool Start(Bool back, LONG priority=THREADPRIORITY_NORMAL, Bool keeprunning=FALSE);
		void End(Bool wait=TRUE);
		Bool IsRunning(void) { return C4DOS.Bt->IsRunning(bt); }
		Bool TestBreak(void) { return C4DOS.Bt->TestBreak(bt); }
		void Wait(Bool checkevents);

		// routines for overriding
		virtual Bool TestDBreak(void) { return FALSE; }
		virtual void Main(void)=0;
		virtual const CHAR *GetThreadName(void)=0;
};

#define MAX_THREADS	16

class MPThread
{
	private:
		MPBaseThread *mp;
		LONG mpcount;
	public:
		MPThread(void);
		~MPThread(void);

		Bool		Init(BaseThread *parent, LONG count, Thread **thread);
		Bool		Init(const Thread &parent, LONG count, Thread **thread);
		Bool		Start(void);
		Thread	*WaitForNextFree(void);
		void		Wait(void);
		void		End(void);
};

class Semaphore
{
	private:
		Semaphore();
		~Semaphore();
	public:
		Bool Lock(void) { return C4DOS.Bt->SMLock(this); }
		Bool LockAndWait(BaseThread *bt) { return C4DOS.Bt->SMLockAndWait(this,bt); } 
		Bool LockAndWait(Thread *bt) { return C4DOS.Bt->SMLockAndWait(this,bt?bt->Get():NULL); }
		void UnLock(void) { C4DOS.Bt->SMUnLock(this); }

		static Semaphore *Alloc(void);
		static void Free(Semaphore *&sm);
};

inline LONG GeGetCPUCount(void) { return C4DOS.Bt->GetCPUCount(); }
inline void GeThreadLock(void) { C4DOS.Bt->ThreadLock(); }
inline void GeThreadUnLock(void) { C4DOS.Bt->ThreadUnLock(); }

inline void	GeSpinLock(GE_SPINLOCK *lock)						{C4DOS.Bt->SpinLock(lock);}
inline void	GeSpinUnlock(GE_SPINLOCK *lock)					{C4DOS.Bt->SpinUnlock(lock);}
inline void	GeSpinReadLock(GE_RWSPINLOCK *rwlock)		{C4DOS.Bt->SpinReadLock(rwlock);}
inline void	GeSpinReadUnlock(GE_RWSPINLOCK *rwlock)	{C4DOS.Bt->SpinReadUnlock(rwlock);}
inline void	GeSpinWriteLock(GE_RWSPINLOCK *rwlock)	{C4DOS.Bt->SpinWriteLock(rwlock);}
inline void	GeSpinWriteUnlock(GE_RWSPINLOCK *rwlock){C4DOS.Bt->SpinWriteUnlock(rwlock);}

inline LONG IdentifyThread(BaseThread *bt) { return C4DOS.Bt->Identify(bt); }

inline ULONG GeGetCurrentThreadId() { return C4DOS.Bt->GetCurrentThreadId(); }
inline BaseThread* GeGetCurrentThread() { return C4DOS.Bt->GetCurrentThread(); }

#endif
