#include "tn_psf.h"
#include <libraries/iffparse.h>
#include <stdio.h>
#include <string.h>

#define PSF2_MAGIC MAKE_ID('P','S','F',2)

extern struct Interface *INewlib;

int32 TNPlug_TestPlayer (struct TNPlugIFace *Self, uint8 *testme, uint8 *testbuffer,
	uint32 totalsize, uint32 testsize)
{
	char *ext = NULL;
	int32 res = 0;

	if (totalsize <= 4) return 0;
	if (testme) {
		ext = strrchr((char *)testme, '.');
		if (ext) {
			ext++;
			if (!stricmp(ext, "psflib")) {
				return 0;
			}
		}
	}
	if (testsize >= 4) {
		uint32 magic = *(uint32 *)testbuffer;
		if (magic == PSF2_MAGIC || !strncmp((char *)testbuffer, "SPU", 3)) {
			res = PLM_FileLoad;
		}
	} else {
		char *ext;
		ext = strrchr((char *)testme, '.');
		if (ext) {
			ext++;
			if (!stricmp(ext, "psf") || !stricmp(ext, "spu")) {
				res = PLM_FileLoad;
			}
		}
	}

	return res;
}

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

	if (inTuneNet->playmode == PLM_FileLoad) {
		struct TNDecHandle *handle;
		psfiface_t *iface;
		int32 path_len;
		BPTR dir = ZERO, old;

		dbug(("creating handle\n"));
		handle = IExec->AllocVec(sizeof(*handle), MEMF_SHARED|MEMF_CLEAR);
		inTuneNet->handle = handle;
		if (!handle) goto out;

		if (*(uint32 *)inTuneNet->in_file == PSF2_MAGIC) {
			handle->fmt = FMT_PSF2;
			handle->pcm_size = 735;
		} else 
		if (!strncmp((char *)inTuneNet->in_file, "SPU", 3)) {
			handle->fmt = FMT_SPU;
			handle->pcm_size = 768;
		} else {
			goto out;
		}

		dbug(("allocating pcm buffer\n"));
		inTuneNet->pcm[0] = IExec->AllocVec(handle->pcm_size << 2, MEMF_SHARED);
		if (!inTuneNet->pcm[0]) goto out;
		inTuneNet->pcm[1] = inTuneNet->pcm[0] + 1;

		dbug(("loading psf code\n"));
		handle->psf_bin = IDOS->LoadSeg("PROGDIR:plugins/data/TN_PSF2.bin");
		if (!handle->psf_bin) goto out;

		dbug(("obtaining interface\n"));
		iface = (psfiface_t *)IDOS->RunCommand(handle->psf_bin, 4096, "", 0);
		if (!iface) goto out;

		path_len = (char *)IDOS->PathPart((STRPTR)openme) - (char *)openme;
		dbug(("path_len: %ld\n", path_len));
		dbug(("openme: %s\n", openme));
		if (path_len) {
			char *path;
			path = IExec->AllocVec(path_len+1, MEMF_SHARED);
			if (!path) goto out;
			memcpy(path, openme, path_len);
			path[path_len] = 0;
			dir = IDOS->Lock(path, ACCESS_READ);
			IExec->FreeVec(path);
			if (!dir) goto out;
			old = IDOS->CurrentDir(dir);
		}

		dbug(("psf_open()\n"));
		handle->newlib = INewlib;
		handle->iface = iface;
		res = iface->open(handle, inTuneNet->in_file, inTuneNet->in_file_size);

		if (dir) {
			IDOS->CurrentDir(old);
			IDOS->UnLock(dir);
		}
out:
		if (res) {
			dbug(("success\n"));
			inTuneNet->DirectRender = ARender_InternalBuffer;

			inTuneNet->current_subsong = 0;
			inTuneNet->max_subsongs = 0;
			
			inTuneNet->dec_frequency = 44100;
			inTuneNet->dec_channels = 2;
			inTuneNet->bitrate = 0;
			inTuneNet->mix_lr = TN_STEREO_50PER;

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

			inTuneNet->ms_duration = 0;

			inTuneNet->ST_Name[0] = 0;
			inTuneNet->ST_Url[0] = 0;
			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->iface) handle->iface->close(handle);
		IDOS->UnLoadSeg(handle->psf_bin);
		IExec->FreeVec(handle);
		inTuneNet->handle = NULL;
	}
	IExec->FreeVec(inTuneNet->pcm[0]);
	inTuneNet->pcm[0] =
	inTuneNet->pcm[1] = NULL;
}
