#include "WimpLib:Message.h"

#include <string.h>

#include "WimpLib:Exception.h"
#include "WimpLib:File.h"
#include "WimpLib:mem.h"

#define msg_bufs 8

static struct
{
	void* Handle;
	int   BufNr;
} Msg_Globals = {NULL, 0};

static char Msg_Buf[msg_bufs][1024];

void throw_Msg_Msg(void)
{
	_kernel_swi_regs regs;
	_kernel_oserror* err;
	const char* filename = throw_File_FromRes("Messages");

	if (Msg_Globals.Handle) return;

	// MessageTrans_FileInfo
	regs.r[1] = (int) filename;
	throw_os(_kernel_swi(0x61500, &regs, &regs));

	Msg_Globals.Handle = throw_mem_alloc(regs.r[2] + 16);

	// MessageTrans_OpenFile
	regs.r[0] = (int) Msg_Globals.Handle;
	regs.r[1] = (int) filename;
	regs.r[2] = regs.r[0] + 16;
	if ((err = _kernel_swi(0x61501, &regs, &regs)) != NULL)
	{
		mem_free(Msg_Globals.Handle);
		Msg_Globals.Handle = NULL;
		throw_os(err);
	}
}

void Msg_NotMsg(void)
{
	_kernel_swi_regs regs;

	if (Msg_Globals.Handle == NULL) return;

	// MessageTrans_CloseFile
	regs.r[0] = (int) Msg_Globals.Handle;
	_kernel_swi(0x61504, &regs, &regs);

	mem_free(Msg_Globals.Handle);
	Msg_Globals.Handle = NULL;
}

const char* Msg_Lookup(const char* tag)
{
	_kernel_swi_regs regs;
	_kernel_oserror* err;
	char* msg;

	Msg_Globals.BufNr = (Msg_Globals.BufNr + 1) % msg_bufs;

	// MessageTrans_Lookup
	regs.r[0] = (int) Msg_Globals.Handle;
	regs.r[1] = (int) tag;
	regs.r[2] = (int) &Msg_Buf[Msg_Globals.BufNr][0];
	regs.r[3] = 1024;
	regs.r[4] = 0;
	regs.r[5] = 0;
	regs.r[6] = 0;
	regs.r[7] = 0;
	err = _kernel_swi(0x61502, &regs, &regs);
	if ((err != NULL) || (regs.r[3] <= 0))
		return tag;

	msg = (char*) regs.r[2];
	msg[regs.r[3]] = 0;

	return msg;
}

const char* Msg_CLookup(const char* tag, ...)
{
	const char* msg = Msg_Lookup(tag);
	char* cmsg;

	Msg_Globals.BufNr = (Msg_Globals.BufNr + 1) % msg_bufs;

	cmsg = &Msg_Buf[Msg_Globals.BufNr][0];

	va_list arg;
	va_start(arg, tag);
	vsnprintf(cmsg, 1024, msg, arg);
	va_end(arg);

	return cmsg;
}

const char* Msg_Lookup1(const char* tag, const char* par1)
{
	_kernel_swi_regs regs;
	_kernel_oserror* err;
	char* msg;

	Msg_Globals.BufNr = (Msg_Globals.BufNr + 1) % msg_bufs;

	// MessageTrans_Lookup
	regs.r[0] = (int) Msg_Globals.Handle;
	regs.r[1] = (int) tag;
	regs.r[2] = (int) &Msg_Buf[Msg_Globals.BufNr];
	regs.r[3] = 1024;
	regs.r[4] = (int) par1;
	regs.r[5] = 0;
	regs.r[6] = 0;
	regs.r[7] = 0;
	err = _kernel_swi(0x61502, &regs, &regs);
	if (err != NULL)
		return tag;

	msg = (char*) regs.r[2];
	msg[regs.r[3]] = 0;

	return msg;
}

const _kernel_oserror* Msg_ErrorLookup(const _kernel_oserror* err)
{
	_kernel_swi_regs regs;

	if (!(err->errnum & 0x40000000)) return err;

	Msg_Globals.BufNr = (Msg_Globals.BufNr + 1) % msg_bufs;

	// MessageTrans_ErrorLookup, returns with V flags set !!!
	regs.r[0] = (int) err;
	regs.r[1] = (int) Msg_Globals.Handle;
	regs.r[2] = (int) &Msg_Buf[Msg_Globals.BufNr];
	regs.r[3] = 1024;
	regs.r[4] = 0;
	regs.r[5] = 0;
	regs.r[6] = 0;
	regs.r[7] = 0;
	return _kernel_swi(0x61506, &regs, &regs);
}
