#include "tn_ra.h"

int32 TNPlug_TestPlayer (struct TNPlugIFace *Self, uint8 *testme, uint8 *testbuffer,
	uint32 totalsize, uint32 testsize)
{
	int32 ret = 0;
	char *ext;
	ext = strrchr((char *)testme, '.');
	if (ext) {
		ext++;
		if (!IUtility->Stricmp(ext, "ra") || !IUtility->Stricmp(ext, "ram") ||
			!IUtility->Stricmp(ext, "rm")) {
			ret = PLM_File;
		}
	}
	return ret;
}

static LONG DOSRead (APTR handle, APTR buf, LONG len) {
	return IDOS->Read((BPTR)handle, buf, len);
}

static LONG AsyncRead (APTR handle, APTR buf, LONG len) {
	return IAsyncIO->ReadAsync(handle, buf, len);
}

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

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

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

		if (!IAsyncIO) {
			handle->inHandle = (APTR)IDOS->Open(openme, MODE_OLDFILE);
			if (!handle->inHandle) goto out;
			handle->ReadFunc = DOSRead;
		} else {
			handle->inHandle = IAsyncIO->OpenAsync(openme, MODE_READ, 16 << 10);
			if (!handle->inHandle) goto out;
			handle->ReadFunc = AsyncRead;
		}

		handle->in = IExec->AllocVec(DATACHUNK2, MEMF_SHARED);
		if (!handle->in) goto out;

		handle->codec = ReadHeader(handle->inHandle, handle->ReadFunc, handle->in,
			&handle->freq, &handle->chans, &handle->blockSize, &handle->packets,
			&handle->streamid, &handle->rmf);

		switch (handle->codec) {
			case 1:
				handle->chunkSize = handle->blockSize*72;
				handle->Real = init_144();
				break;
			case 2:
				handle->chunkSize = handle->blockSize*72;
				handle->Real = init_288();
				break;
			case 3:
				handle->chunkSize = handle->blockSize*((handle->chans == 1) ? 8 : 4);
				handle->Real = init_dnet();
				break;
			default:
				handle->Real = NULL;
				break;
		}
		if (!handle->Real) goto out;

		if (handle->chunkSize > DATACHUNK2) {
			IExec->FreeVec(handle->in);
			handle->in = IExec->AllocVec(handle->chunkSize, MEMF_SHARED);
			if (!handle->in) goto out;
		}

		if (handle->codec > 1) {
			handle->deint = IExec->AllocVec(handle->chunkSize+8, MEMF_SHARED|MEMF_CLEAR);
			if (!handle->deint) goto out;
		}

		inTuneNet->pcm[0] = IExec->AllocVec(AUDIOBUFFER << 1, MEMF_SHARED);
		if (!inTuneNet->pcm[0]) goto out;
		inTuneNet->pcm[1] = inTuneNet->pcm[0] + 1;

		res = TRUE;
out:
		if (res) {
			inTuneNet->DirectRender = ARender_InternalBuffer;
			inTuneNet->max_subsongs =
			inTuneNet->current_subsong = 0;

			dbug(("codec: %ld\n", handle->codec));
			dbug(("freq: %ld\n", handle->freq));
			dbug(("channels: %ld", handle->chans));

			inTuneNet->dec_frequency = handle->freq;
			inTuneNet->dec_channels = handle->chans;
			inTuneNet->bitrate = 0;
			inTuneNet->mix_lr = TN_STEREO_50PER;

			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 {
			TNPlug_ClosePlayer(Self, inTuneNet);
		}
	}

	return res;
}

void TNPlug_ClosePlayer (struct TNPlugIFace *Self, struct TuneNet *inTuneNet) {
	struct TNDecHandle *handle = inTuneNet->handle;
	if (handle) {
		if (handle->Real) {
			switch (handle->codec) {
				case 1:
					free_144(handle->Real);
					break;
				case 2:
					free_288(handle->Real);
					break;
				case 3:
					free_dnet(handle->Real);
					break;
			}
		}

		IExec->FreeVec(handle->deint);
		IExec->FreeVec(handle->in);

		if (handle->inHandle) {
			if (!IAsyncIO)
				IDOS->Close((BPTR)handle->inHandle);
			else
				IAsyncIO->CloseAsync(handle->inHandle);
		}

		IExec->FreeVec(handle);
		inTuneNet->handle = NULL;
	}
	IExec->FreeVec(inTuneNet->pcm[0]);
	inTuneNet->pcm[0] = inTuneNet->pcm[1] = NULL;
}
