#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include "kernel.h"
#include "swis.h"
#include "toolbox.h"

#define Buggy "<Obey$Dir>.Buggy"
#include "Buggy.h" // my debugging code
#include "Wimpy.h" // some Wimp definitions

// Some global variables so I need not pass them on over and over again
// ... or create them over and over again for subroutine calls
_kernel_swi_regs SWIRegs;
int WimpPollMask = PollMask_Standard;
//int WimpPollMask = PollMask_Null;
int WimpPollWait = 200;
t_WimpPollBlock MyPollBlockStorage;
t_WimpPollBlock *MyPollBlock;
t_Toolbox_ID ToolboxID;
t_TaskHandle MyTaskHandle = 0;
char ObeyDir[] = "ToolBox2Res:";
t_MessageTrans_FileDescriptor MyMessagesFile;
t_SpriteArea *MySpriteArea;

int AllMessages = 0;
int ToolboxMessages[] = {512,0};

// Function for SWI Wimp_CloseDown
void WimpCloseDown(void) {
	// Call Wimp_CloseDown if I have a TaskHandle
	if (MyTaskHandle != 0) {
		SWIRegs.r[0] = TASK;
		SWIRegs.r[1] = (int)MyTaskHandle;
		_kernel_swi(Wimp_CloseDown,&SWIRegs,&SWIRegs);
	}
	// Exit
	_kernel_swi(OS_Exit,&SWIRegs,&SWIRegs);
	exit(0);
}

#define SWI(swi)  SWIcall(swi,True,#swi,__FILE__,__LINE__)
#define SWIX(swi) SWIcall(swi,False,#swi,__FILE__,__LINE__)
#define SWIE(swi) SWIcall(-1,True,#swi,__FILE__,__LINE__)

// Call an SWI and abort in case of error...
// Call with SWI NULL to just abort
_kernel_oserror *SWIcall(int SWIName, int AbortOnError, char *AbortMessage, char *File, int Line) {
	_kernel_oserror *OSError;

	//BuggyRegs(AbortMessage,4);

	// Call the SWI (if I have one)
	if (SWIName != -1) {
		OSError = _kernel_swi(SWIName,&SWIRegs,&SWIRegs);
		if (OSError == NULL) { return(OSError); }
	}

	// In case of error write debug log and optionally abort
	BuggyError(AbortMessage,File,Line);
	if (AbortOnError) {
		SWIRegs.r[0] = (int)OSError;
		SWIRegs.r[1] = 1;
		SWIRegs.r[2] = (int)AbortMessage;
		_kernel_swi(Wimp_ReportError,&SWIRegs,&SWIRegs);
		WimpCloseDown();
	}

	return(OSError);
}

// Function for SWI Toolbox_Initalise
/*
On entry
R0 = flags
R1 = last Wimp version number known to task * 100 (must be ?310)
R2 = pointer to list of Wimp message numbers which the client wishes to receive, terminated by a 0 word
     If R2 points to just a 0 word, then all messages are delivered
     If R2 = 0, then no messages are delivered (apart from the Quit message)
R3 = pointer to list of Toolbox event codes which the client wishes to receive, terminated by a 0 word
     If R3 points to just a 0 word, then all Toolbox events are delivered
     If R3 = 0, then no Toolbox events are delivered
R4 = pointer to Directory name in which to find resources (may end with : character to specify a path from Toolbox version 1.50 onwards)
R5 = pointer to 4-word buffer to receive messages file descriptor
R6 = pointer to buffer to hold object ids on return from Wimp_Poll (the id block)

On exit
R0 = current Wimp version number * 100
R1 = Wimp task handle for this client
R2 = Pointer to Sprite area used
Buffer pointed to by R5 is filled in with a MessageTrans file descriptor for the messages file to be used
*/
void ToolBoxInitialise(void) {
	SWIRegs.r[0] = 0;
	SWIRegs.r[1] = 310;
	SWIRegs.r[2] = 0;
	SWIRegs.r[3] = (int)&AllMessages;
	SWIRegs.r[4] = (int)&ObeyDir;
	SWIRegs.r[5] = (int)&MyMessagesFile;
	SWIRegs.r[6] = (int)&ToolboxID;
	SWI(Toolbox_Initialise);
	MyTaskHandle = SWIRegs.r[1];
	MySpriteArea = (t_SpriteArea*)SWIRegs.r[2];
}

// I like more or less messages
void WimpAddRemoveMessages(int MessageCode) {
	t_WimpAddRemoveMessages Block;
	SWIRegs.r[0] = (int)(&Block);
	Block.Delimiter = 0;
	if (MessageCode < 0) {
		Block.MessageCode = -MessageCode;
		SWI(Wimp_RemoveMessages);
	}
	else {
		Block.MessageCode = MessageCode;
		SWI(Wimp_AddMessages);
	}
}

// Function for SWI Wimp_Poll
int WimpPoll(void) {
	SWIRegs.r[0] = WimpPollMask;
	SWIRegs.r[1] = (int)&MyPollBlockStorage;
	SWIRegs.r[3] = 0;
	SWI(Wimp_Poll);
	MyPollBlock = (t_WimpPollBlock *)SWIRegs.r[1];
	return(SWIRegs.r[0]);
}

int ToolboxCreate(char *Template, int Show) {
	SWIRegs.r[0] = 0;
	SWIRegs.r[1] = (int)Template;
	SWI(Toolbox_CreateObject);
	if (Show) {
		SWIRegs.r[0] = 0;
		SWIRegs.r[2] = 0;
		SWIRegs.r[3] = 0;
		SWIRegs.r[4] = 0;
		SWIRegs.r[5] = 0;
		SWI(Toolbox_ShowObject);
	}
	return(SWIRegs.r[1]);
}

int main (int argc, char *argv[]) {

	int ReasonCode;

	BuggyClear;

	BuggyMessage("Gogo");
	ToolBoxInitialise();
	BuggyMessage("Look");

	while (True) {
		ReasonCode = WimpPoll();
		BuggyInt("ReasonCode",ReasonCode);
		//BuggyBuffI("Poll",MyPollBlock,12);

		// Handle the request
		switch(ReasonCode) {

		case ReasonCode_Toolbox:
			BuggyInt("TolboxEvent",MyPollBlock->ToolboxEvent.Event);
			BuggyText("TolboxEvent",MyPollBlock->ToolboxEvent.Data);
			switch(MyPollBlock->ToolboxEvent.Event) {
			case ToolboxEvent_Quit:
				 WimpCloseDown();
				 break;
			}
			break;

		// User message
		case ReasonCode_UserMessage:
		case ReasonCode_UserMessageRecorded:
		case ReasonCode_UserMessageAcknowledge:
			BuggyInt("MessageCode",MyPollBlock->UserMessage.MessageCode);
			//BuggyBuffI("Message",MyPollBlock,12);
			switch(MyPollBlock->UserMessage.MessageCode) {
			case MessageCode_Quit:
				 WimpCloseDown();
				 break;
			}
			break;
		}
	}

}

