/* My timer device! */

#include <string.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/intuition_protos.h>
#include <exec/exec.h>
#include <dos/dostags.h>
#include <proto/locale.h>

extern struct Catalog *catalog;

extern struct Library *DOSBase;
extern void msg(char *text);

char tname[100];

void BTimer(void);
struct TimerDev *GoTimer(long timeunit);
void CloseTimer(struct TimerDev *td);

struct TimerDev {
	struct MsgPort *tport;
	BOOL close;
	long delay;
	long sig;
};

struct TimerDev *timer_global;

struct TimerDev *GoTimer(long timeunit) {

	int i=1;

	if(!(timer_global=AllocVec(sizeof(struct TimerDev),MEMF_ANY))) {
		msg(GetCatalogStr(catalog,30,"Memory error!"));
		return(0);
	}

	timer_global->delay=timeunit;
	timer_global->close=0;
	timer_global->tport=CreateMsgPort();
	
	if(!timer_global->tport) {
		msg(GetCatalogStr(catalog,30,"No port available!"));
		FreeVec(timer_global);
		return(0);
	}
	
	timer_global->sig=1<<timer_global->tport->mp_SigBit;

	sprintf(tname,"EngTimer_%d",i);

	while((FindTask(tname)) || i==10) {
		i++;
		sprintf(tname,"EngTimer_%d",i);
	}

	if(!(CreateNewProcTags(NP_Entry,BTimer,NP_StackSize,16384,NP_Name,tname,TAG_END))) {
		msg(GetCatalogStr(catalog,41,"Couldn't do new process!\n Panic!"));
		CloseTimer(timer_global);
		return(0);
	}
	
	return(timer_global);
}

void CloseTimer(struct TimerDev *td) {

	td->close=1;					// Signal the thread to close

	while(FindTask(tname))		// Wait until the task is no longer visible
		Delay(20);					// ...but don't busy loop!

	if(td) {
		if(td->tport) DeleteMsgPort(td->tport);
		FreeVec(td);
	}
}

void BTimer(void) {
	struct Message timer_msg;
	struct MsgPort *reply;
	
	memset(&timer_msg,0,sizeof(timer_msg));

	reply=CreateMsgPort();
	
	if(!reply) {
		DisplayBeep(NULL);
		CloseTimer(timer_global);
		return;
	}
	
	timer_msg.mn_ReplyPort=reply;
	timer_msg.mn_Length=sizeof(struct Message);
	
	while(!timer_global->close) {

		// Send a message back through the port
		PutMsg(timer_global->tport,&timer_msg);
		// Don't worry about acknowledging the reply
		Delay(timer_global->delay);
		
	}
	
	DeleteMsgPort(reply);
}

/* For testing only...:- */

/* void main(void) {
	struct TimerDev *local;
	BOOL exit_flag=0;
	long d;

	printf("Choose a delay value (in ticks!): ");
	scanf("%ld",&d);

	local=GoTimer(d);
	if(!local) {
		printf("Timer didn't say ok!\n");
		return;
	}
	
	while(!exit_flag) {
		if(Wait(local->sig|SIGBREAKF_CTRL_C)==SIGBREAKF_CTRL_C) {
			printf("You pressed Ctrl-C!\n");
			exit_flag=TRUE;
		} else {
			struct Message *msg;
			while(msg=GetMsg(local->tport)) {
				ReplyMsg(msg);
				printf("Got a timer msg!\n");
			}
			
		}
	}

	CloseTimer(local);
} */