#include "tn_gsf.h"
#include <string.h>
#include <stdio.h>

int32 TNPlug_TestPlayer (struct TNPlugIFace *Self, uint8 *testme, uint8 *testbuffer,
	uint32 totalsize, uint32 testsize)
{
	char *ext = NULL;
	int32 res = 0;
	if (testme) {
		ext = strrchr((char *)testme, '.');
		if (ext) {
			ext++;
			if (!stricmp(ext, "gsflib")) {
				return 0;
			}
		}
	}
	if (totalsize >= 4) {
		if (testbuffer[0] == 'P' && testbuffer[1] == 'S' && testbuffer[2] == 'F' &&
			testbuffer[3] == 0x22)
		{
			res = PLM_File;
		}
	} else if (ext && (!stricmp(ext, "gsf") || !stricmp(ext, "minigsf"))) {
		res = PLM_File;
	}
	return res;
}

BOOL TNPlug_OpenPlayer (struct TNPlugIFace *Self, uint8 *openme, struct TuneNet *inTuneNet) {
	BOOL res = FALSE;

	if (inTuneNet->playmode == PLM_File) {
		struct TNDecHandle *handle;
		BPTR seglist;

		dbug(("creating handle\n"));
		handle = IExec->AllocSysObjectTags(ASOT_MESSAGE,
			ASOMSG_Name,		Self->Data.LibBase->lib_Node.ln_Name,
			ASOMSG_Size,		sizeof(*handle),
			TAG_END);
		inTuneNet->handle = handle;
		if (!handle) goto out;
		memset(&handle->msg + 1, 0, sizeof(*handle) - sizeof(handle->msg));
		handle->player_task = NULL;

		dbug(("creating port\n"));
		handle->player_port = IExec->AllocSysObjectTags(ASOT_PORT,
			ASOPORT_Signal,		SIGB_CHILD,
			TAG_END);
		if (!handle->player_port) goto out;
		handle->msg.mn_ReplyPort = handle->player_port;

		handle->filename = IUtility->ASPrintf("%s", openme);
		if (!handle->filename) goto out;

		dbug(("allocating memory for pcm\n"));
		handle->pcm = IExec->AllocVec(AUDIO_BUFFER_SIZE, MEMF_SHARED);
		if (!handle->pcm) goto out;
		inTuneNet->pcm[0] = handle->pcm;
		inTuneNet->pcm[1] = inTuneNet->pcm[0] + 1;

		dbug(("loading sexypsf\n"));
		seglist = IDOS->LoadSeg("PROGDIR:Plugins/data/TN_GSF.bin");
		if (!seglist) goto out;

		dbug(("creating subprocess\n"));
		handle->player_task = (struct Task *)IDOS->CreateNewProcTags(
			NP_Name,					"TN_GSF.bin",
			NP_Input,					0,
			NP_Output,					0,
			NP_Error,					0,
			NP_Seglist,					seglist,
			NP_FreeSeglist,				TRUE,
			NP_StackSize,				1 << 20,
			NP_Priority,				1,
			NP_NotifyOnDeathMessage,	handle,
			TAG_END);
		if (!handle->player_task) {
			IDOS->UnLoadSeg(seglist);
			goto out;
		}

		dbug(("sending message\n"));
		IExec->PutMsg(&((struct Process *)handle->player_task)->pr_MsgPort, &handle->msg);
		dbug(("waiting for reply\n"));
		IExec->WaitPort(handle->player_port);
		handle = (struct TNDecHandle *)IExec->GetMsg(handle->player_port);
		IExec->SetSignal(0, SIGF_CHILD);
		dbug(("reply received\n"));

		if (handle->retcode != OK) {
			handle->player_task = NULL;
			goto out;
		}

		res = TRUE;
out:
		if (res) {
			dbug(("success\n"));

			inTuneNet->DirectRender = ARender_InternalBuffer;
			inTuneNet->max_subsongs =
			inTuneNet->current_subsong = 0;

			inTuneNet->dec_frequency = handle->info.sample_rate;
			inTuneNet->dec_channels = handle->info.channels;
			inTuneNet->bitrate = 0;
			inTuneNet->mix_lr = TN_STEREO_50PER;

			if (handle->info.game && handle->info.title) {
				snprintf(inTuneNet->Tune, sizeof(inTuneNet->Tune), "%s: %s",
					handle->info.game, handle->info.title);
			} else if (handle->info.title) {
				strncpy(inTuneNet->Tune, handle->info.title, sizeof(inTuneNet->Tune));
			} else {
				inTuneNet->Tune[0] = 0;
			}

			//printf("length: %ld\n", handle->info.length);
			inTuneNet->ms_duration = handle->info.length;

			inTuneNet->ST_Name[0] = 0;
			inTuneNet->ST_Url[0] = 0;
			inTuneNet->ST_Genre[0] = 0;
			if (handle->info.comment) {
				strncpy(inTuneNet->ST_Note, handle->info.comment, sizeof(inTuneNet->ST_Note));
			} else {
				inTuneNet->ST_Note[0] = 0;
			}

			inTuneNet->songEOF = TRUE;
		} else {
			dbug(("failure!\n"));
			TNPlug_ClosePlayer(Self, inTuneNet);
		}
	}

	return res;
}

void TNPlug_ClosePlayer (struct TNPlugIFace *Self, struct TuneNet *inTuneNet) {
	struct TNDecHandle *handle = inTuneNet->handle;
	if (handle) {
		if (handle->player_task) {
			handle->player_port->mp_SigTask = IExec->FindTask(NULL);
			IExec->Signal(handle->player_task, handle->endsig);
			IExec->WaitPort(handle->player_port);
			IExec->GetMsg(handle->player_port);
			IExec->SetSignal(0, SIGF_CHILD);
			handle->player_task = NULL;
		}
		IExec->FreeVec(handle->pcm);
		IExec->FreeVec(handle->filename);
		IExec->FreeSysObject(ASOT_PORT, handle->player_port);
		IExec->FreeSysObject(ASOT_MESSAGE, handle);
		inTuneNet->handle = NULL;
	}
	inTuneNet->pcm[0] =
	inTuneNet->pcm[1] = NULL;
}
