#include "GlobHdr.h"
#include "IWriter.h"

#include <string.h>
#include "swis.h"

typedef struct
{
	char*        filename;
	unsigned int handle;
	int          volume;
} ToData;

/*----------------
 * ToSrcFile_Init
 */

static const _kernel_oserror* ToSrcFile_Initialize(IStream* s, const _kernel_swi_regs* r)
{
	ToData* od;
	const _kernel_oserror* e;

	e = IStream_Alloc(s, (void**) &od, sizeof(*od));
	if (e) return e;

	s->writer.data = od;
	memset(od, 0, sizeof(*od));
	od->volume = s->writer.volume;
	e = IStream_AllocString(s, &od->filename, (const char*) r->r[0]);
	if (e) return e;

	// Open file in extend mode
	e = _swix(OS_Find, _INR(0,1)|_OUT(0), 0xcf, od->filename, &od->handle);
	if (e)
	{
		// Create file
		e = _swix(OS_Find, _INR(0,1)|_OUT(0), 0x8f, od->filename, &od->handle);
	}
	else
	{
		if (r->r[1])
		{
			// Move to end of file
			unsigned int pos;
			e = _swix(OS_Args, _INR(0,1)|_OUT(2), 2, od->handle, &pos);
			if (e) return e;
			e = _swix(OS_Args, _INR(0,2), 1, od->handle, pos);
			if (e) return e;
		}
		else
		{
			// Truncate file
			e = _swix(OS_Args, _INR(0,2), 3, od->handle, 0);
			if (e) return e;
		}
	}

	return e;
}

/*----------------
 * ToSrcFile_Open
 */

static const _kernel_oserror* ToSrcFile_Open(IStream* s)
{
	ToData* od = s->writer.data;

	IGNORE(od);

	return NULL;
}

/*---------------------
 * ToSrcFile_SetParams
 */

static const _kernel_oserror* ToSrcFile_SetParams(IStream* s)
{
	ToData* od = s->writer.data;

	IGNORE(od);

	return NULL;
}

/*----------------
 * ToSrcFile_Fill
 */

static const _kernel_oserror* ToSrcFile_Fill(IStream* s)
{
	ToData* od = s->writer.data;
	const _kernel_oserror* e = NULL;
	const char* p = (char*) (s->inb + 1);
	int used;

	if (s->inb->start > s->inb->free)
	{
		used = s->inb->size - s->inb->start;

		// Write to file
		e = _swix(OS_GBPB, _INR(0,3), 2, od->handle
		         , p + s->inb->start, used);
		if (e) return e;
		s->inb->start = 0;
	}

	if (s->inb->start < s->inb->free)
	{
		used = s->inb->free - s->inb->start;

		// Write to file
		e = _swix(OS_GBPB, _INR(0,3), 2, od->handle
		         , p + s->inb->start, used);
		if (e) return e;
		s->inb->start = s->inb->free;
	}

	s->status |= swrk_status_outputdone;
	if (s->inb->finishflag)
		s->status |= (swrk_status_decoded | swrk_status_played);

	return NULL;
}

/*------------------
 * ToSrcFile_Volume
 */

static const _kernel_oserror* ToSrcFile_Volume(IStream* s, int* volume)
{
	ToData* od = s->writer.data;

	if (*volume >= 0)
		od->volume = *volume;

	*volume = od->volume;

	return NULL;
}

/*-----------------
 * ToSrcFile_Close
 */

static const _kernel_oserror* ToSrcFile_Close(IStream* s)
{
	ToData* od = s->writer.data;

	IGNORE(od);

	return NULL;
}

/*--------------------
 * ToSrcFile_Finalize
 */

static const _kernel_oserror* ToSrcFile_Finalize(IStream* s)
{
	ToData* od = s->writer.data;
	const _kernel_oserror* e = NULL;

	if (!od) return NULL;

	if (od->handle)
	{
		int filetype = (s->source.os_filetype != -1)
		             ? s->source.os_filetype
		             : 0xffd;

		e = _swix(OS_Find, _INR(0,1), 0, od->handle);
		od->handle = 0;
		e = _swix(OS_File, _INR(0,2), 18, od->filename, filetype);
	}

	IStream_Free(s, (void**) &od->filename);
	IStream_Free(s, &s->writer.data);

	return e;
}

IWriter ToSrcFile =
{
	  ToSrcFile_Initialize
	, ToSrcFile_Volume
	, ToSrcFile_Open
	, ToSrcFile_SetParams
	, ToSrcFile_Fill
	, ToSrcFile_Close
	, ToSrcFile_Finalize
};
