//
//thread.c
//
//Thread control code.
//
//
//-UserX 2002/02/16

#include "base/thread.h"
#include "base/array.h"
#include "base/str.h"
#include <stdlib.h>

int threadstyle = THREADSTYLE_COOPERATIVE;

Thread threadblank = THREADBLANK;
ThreadFamily threadfamilyblank = THREADFAMILYBLANK;

ThreadFamilyArrayHandle *threadfamilyarray = NULL;


Mutex threadcontrollock = MUTEXBLANK;

void threadInit(void) {
	threadfamilyarray = (ThreadFamilyArrayHandle *) arrayMake(sizeof(ThreadFamily), 0, &threadfamilyblank, NULL, NULL);
}

//Add a thread family.
//Returns the index of it.
int threadAddFamily(char *family) {
	int i = threadfamilyarray->size;
	arrayInsert((ArrayHandle *) threadfamilyarray, i, 1);
	threadfamilyarray->data[i].familyID = stringCopy(family);
	//todo:spawn OS thread if needed
	return i;
}

//returns a pointer to a threadfamily as determine by the family id
ThreadFamily *threadGetFamily(char *family) {
	int i;
	//todo: search family list
	for(i = 0; i < threadfamilyarray->size; i++) {
		if(stringCaseCompare(threadfamilyarray->data[i].familyID, family) == 0) {
			return &threadfamilyarray->data[i];
		}
	}
	return &threadfamilyarray->data[threadAddFamily(family)];
}

void threadAdd(threadEntry thread, void *data, char *family) {
	ThreadFamily *tf;
	int i;
	if(thread == NULL) {
		return;
	}

	mutexLockWait(&threadcontrollock);

	tf = threadGetFamily(family);
	//todo: assetions
	
	i = tf->threads->size;
	arrayInsert((ArrayHandle *) tf->threads, i, 1);

	tf->threads->data[i].data = data;
	tf->threads->data[i].entrypoint = thread;
	tf->threads->data[i].itag = itagGet();
	
	//todo: spawn OS thread if needed

	mutexUnlock(&threadcontrollock);
}

void threadSleep(int duration) {
	//todo: actual call to OS relevant function
}

void threadYield(void) {
	//todo: actual call to OS relevant function
	threadSleep(0);
}

void threadRunner(Thread t, int family) {
	//todo: repeatedly call this thread until done
}

void threadFamilyRunner(int family) {
	//todo: loop through all threads in this family
}

void threadAllRunner(void) {
	//todo: loop through all thread families
}

void mutexUnlock(Mutex *m) {
	//todo: assertion.
	*m--;
}

//attempt to lock a mutex
//returns non-zero if failed
int mutexLock(Mutex *m) {
	if(*m != 0) {
		return 1;
	}
	*m++;
	if(*m != 1) {
		*m--;
		return 1;
	}
	return 0;
}

void mutexLockWait(Mutex *m) {
	while(mutexLock(m)){
		threadYield();
	}
}

