#include "tn_psf.h"
#include "TNPSF.bin_rev.h"

struct ExecIFace *IExec;
struct DOSIFace *IDOS;
struct Interface *INewlib;
struct Library *DOSBase;
struct Library *NewlibBase;

struct TNDecHandle *handlePtr;
BOOL stopped;

const char verstag[] = VERSTAG;

int OpenLibs ();
void CloseLibs ();

int _start (char *argstr, int32 arglen, struct ExecBase *SysBase) {
	struct Process *proc;
	struct TNDecHandle *handle;
	uint32 signals;

	dbug(("waiting for startup msg\n"));
	IExec = (struct ExecIFace *)SysBase->MainInterface;
	proc = (struct Process *)IExec->FindTask(NULL);
	IExec->WaitPort(&proc->pr_MsgPort);
	handle = (struct TNDecHandle *)IExec->GetMsg(&proc->pr_MsgPort);
	handlePtr = handle;
	handle->info = NULL;
	
	dbug(("opening libraries\n"));
	if (!OpenLibs()) {
		dbug(("leaving\n"));
		CloseLibs();
		return 20;
	}

	dbug(("opening psf file\n"));
	handle->info = sexy_load(handle->filename);
	handle->datasig = 1 << IExec->AllocSignal(-1);
	handle->endsig = 1 << IExec->AllocSignal(-1);
	if (!handle->info) {
		dbug(("leaving\n"));
		CloseLibs();
		return 20;
	}
	dbug(("replying\n"));
	IExec->ReplyMsg(&handle->msg);

	dbug(("entering main loop\n"));
	handle->data_in_buffer = 0;
	stopped = FALSE;
	for (;;) {
		sexy_execute();
		if (stopped) break;

		sexyd_update(NULL, 0);
		if (stopped) break;

		handle->info = sexy_load(handle->filename);
	}

	dbug(("leaving\n"));
	CloseLibs();
	return 0;
}

void sexyd_update (unsigned char *sound, long bytes) {
	struct TNDecHandle *handle = handlePtr;
	uint32 signals;
	uint32 send_bytes;

	signals = IExec->Wait(handle->datasig|handle->endsig);

	if (signals & handle->endsig) {
		dbug(("end signal\n"));
		sexy_stop();
		stopped = TRUE;
		return;
	}

	if (bytes < AUDIO_BUFFER_SIZE) {
		send_bytes = bytes;
	} else {
		send_bytes = AUDIO_BUFFER_SIZE;
	}

	dbug(("sending audio (%ld bytes)\n", send_bytes));
	IExec->CopyMem(sound, handle->pcm, send_bytes);
	handle->data_in_buffer = send_bytes;
	IExec->Signal(handle->main_task, SIGF_CHILD);

	if (bytes > AUDIO_BUFFER_SIZE) {
		bytes -= AUDIO_BUFFER_SIZE;
		dbug(("more data than could fit into buffer (%ld bytes)\n", bytes));
		sexyd_update(sound + send_bytes, bytes);
	}
}

int OpenLibs () {
	DOSBase = IExec->OpenLibrary("dos.library", 52);
	IDOS = (struct DOSIFace *)IExec->GetInterface(DOSBase, "main", 1, NULL);
	if (!IDOS) return FALSE;
	NewlibBase = IExec->OpenLibrary("newlib.library", 52);
	INewlib = IExec->GetInterface(NewlibBase, "main", 1, NULL);
	if (!INewlib) return FALSE;
	return TRUE;
}

void CloseLibs () {
	IExec->DropInterface(INewlib);
	IExec->CloseLibrary(NewlibBase);
	IExec->DropInterface((struct Interface *)IDOS);
	IExec->CloseLibrary(DOSBase);
}
