#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include "kernel.h"
#include "swis.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 WimpPollBlockStorage;
t_WimpPollBlock *WimpPollBlock;
t_TaskHandle MyTaskHandle = 0;
t_MessageTrans_FileDescriptor *MyMessages;

const char MyTaskName[]    = "Sprachlich";
const char MyResPath[]     = "SprachlichRes$Path";
#define    MyAppDir          "<Obey$Dir>"
#define    MyMessagesFile    "SprachlichRes:Messages"
#define    MyTemplatesFile   "SprachlichRes:Templates"
const char MyVersion[]     = "Version 1.00";

t_IconHandle MyBarIcon = 0;
t_Menu *MyBarMenu;
t_Window *MyInfoWindow;
t_Window *MyLanguageWindow;
char MyResources[4096];

// Window positioning support
int XY(char *Where) {
	int r = 0;
	int n;
	char *c = Where;
	char w;
	for (;*c!=0;c++) {
		w = *c++;
		if ((*c >= '0') && (*c <= '9')) {
			n = 0;
			while ((*c >= '0') && (*c <= '9')) { n = n*10 + (*c++-'0'); }
		}
		else {
			n = 1;
		}
		c--;
		switch (w) {
		case 'D':
			r += 4*n;
			break;
		case 'S':
			r += 20*n;
			break;
		case 'T':
			r += 44*n;
			break;
		case '+':
			r +=n;
			break;
		case '-':
			r -=n;
			break;
		}
	}
	return(r);
}


// 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);
}

void MessagesLoad(char *FileName) {
	char *MessagesBuffer;
	char *s;
	int MessageBufferLength;
	SWIRegs.r[1] = (int)FileName;
	// Get file info; return NULL if not found
	if (SWIX(MessageTrans_FileInfo) != NULL) { return; }
	// Allocate the space we need to load the file
	int i;
	i = SWIRegs.r[2];
	MyMessages = malloc(sizeof(t_MessageTrans_FileDescriptor)+SWIRegs.r[2]);
	if(MyMessages == NULL) { SWIE("MessageLoad malloc"); }
	MessagesBuffer = (char*)(MyMessages + 1); // sizeof(t_MessageTrans_FileDescriptor);

	SWIRegs.r[0] = (int)MyMessages;
	SWIRegs.r[1] = (int)FileName;
	SWIRegs.r[2] = (int)MessagesBuffer;
	SWI(MessageTrans_OpenFile);
	//BuggyBuffC("..",(char*)(MyMessages + 1),i);
	// Make stuff C friendly so that strings are strings (but skip first 4 bytes)!
	MessagesBuffer += 4; MessageBufferLength -= 4;
	for (s = MessagesBuffer;MessageBufferLength > 0; s++, MessageBufferLength--) {
		if (*s == (char)10) { *s = (char)0; }
	}
}

void MessagesClose(void) {
	if (MyMessages != NULL) {
		SWIRegs.r[0] = (int)MyMessages;
		SWI(MessageTrans_CloseFile);
		free(MyMessages);
		MyMessages = NULL;

	}
}

char *MessagesLookup(char *Token) {

	if (MyMessages != NULL) {
		// Initial version does not support variables
		SWIRegs.r[0] = (int)MyMessages;
		SWIRegs.r[1] = (int)(Token+1);
		SWIRegs.r[2] = 0; // no buffer for result
		SWIRegs.r[3] = 0; // length not important
		SWIRegs.r[4] = 0; // %0
		SWIRegs.r[5] = 0; // %1
		SWIRegs.r[6] = 0; // %2
		SWIRegs.r[7] = 0; // %3
		if (SWIX(MessageTrans_Lookup) == NULL) { return((char*)SWIRegs.r[2]); }
		else                                   { return(Token);               }

	}
	else {
		return(Token);
	}

}

char *MessagesTrans(char *Token, char *P0, char *P1, char *P2, char *P3) {
	int l;
	char *Buffer;

	// Get space I need
	l = strlen(MessagesLookup(Token));
	if (P0 != NULL) l += strlen(P0);
	if (P1 != NULL) l += strlen(P1);
	if (P2 != NULL) l += strlen(P2);
	if (P3 != NULL) l += strlen(P3);

	Buffer = malloc(l+1); // add one for terminating zero byte
	if(Buffer == NULL) { SWIE(#"MessagesTrans malloc#"); }

	if (MyMessages != NULL) {
		SWIRegs.r[0] = (int)MyMessages;
		SWIRegs.r[1] = (int)(Token+1);
		SWIRegs.r[2] = (int)Buffer;
		SWIRegs.r[3] = l;
		SWIRegs.r[4] = (int)P0;
		SWIRegs.r[5] = (int)P1;
		SWIRegs.r[6] = (int)P2;
		SWIRegs.r[7] = (int)P3;
		if (SWIX(MessageTrans_Lookup) != NULL) { strcpy(Buffer,Token);        }
	}
	else {
		strcpy(Buffer,Token);
	}

	return(Buffer);
}

char *MessagesFill(char *Token, char *P0, char *P1, char *P2, char *P3, char *Buffer, int BufferLen) {

	if (MyMessages != NULL) {
		SWIRegs.r[0] = (int)MyMessages;
		SWIRegs.r[1] = (int)Token;
		SWIRegs.r[2] = (int)Buffer;
		SWIRegs.r[3] = BufferLen;
		SWIRegs.r[4] = (int)P0;
		SWIRegs.r[5] = (int)P1;
		SWIRegs.r[6] = (int)P2;
		SWIRegs.r[7] = (int)P3;
		if (SWIX(MessageTrans_Lookup) != NULL) { strcpy(Buffer,Token); }
	}
	else {
		strcpy(Buffer,Token);
	}
	return(Buffer);
}



char *TXT(char *Text) {
	if (*Text == '>') { return(MessagesLookup(Text)); }
	else              { return(Text);                 }
}

// StringLength with delim 00, 0a and 0d
int StringLength(char *s) {
	int l = 0;
	for (;; s++) {
		if ((*s == (char)0) || (*s == (char)10) || (*s == (char)13)) { return l; }
		l++;
	}
}

// Change end of string
void StringToC(char *s) {
	for (;; s++) {
		if ((*s == 0) || (*s == 10) || (*s == 13)) { *s = 0; break; }
	}
}

// Case insensitive string compare
int StringCompare(char *a, char *b) {
	int d;
	for (;; a++, b++) {
		d = tolower(*a) - tolower(*b);
		if ((d != 0) || (*a == (char)0) || (*b == (char)0)) { return d; }
	}
}

// Function for SWI Wimp_Initalise
void WimpInitialise(void) {
	SWIRegs.r[0] = 310;
	SWIRegs.r[1] = TASK;
	SWIRegs.r[2] = (int)&MyTaskName;
	SWIRegs.r[3] = (int)NULL;
	SWI(Wimp_Initialise);
	MyTaskHandle = SWIRegs.r[1];
}

// Function for SWI Wimp_Poll
int WimpPoll(void) {
	SWI(OS_ReadMonotonicTime);
	SWIRegs.r[2] = SWIRegs.r[0] + WimpPollWait;
	SWIRegs.r[0] = WimpPollMask;
	SWIRegs.r[1] = (int)&WimpPollBlockStorage;
	SWI(Wimp_PollIdle);
	// I would expect that the block I pass to Wimp_Poll is the one filled but the PRMs do not guarantee that!
	WimpPollBlock = (t_WimpPollBlock *)SWIRegs.r[1];
	return(SWIRegs.r[0]);
}

// Function to put Icon on icon bar with SWI Wimp_CreateIcon
t_IconHandle WimpCreateIconBarIcon(char *Sprite, t_WindowHandle LeftRight) {
	t_WimpCreateIconBlock WimpCreateIconBlock;
	WimpCreateIconBlock.WindowHandle = LeftRight;
	WimpCreateIconBlock.Icon.BoundingBox.MinX = 0;
	WimpCreateIconBlock.Icon.BoundingBox.MinY = 0;
	WimpCreateIconBlock.Icon.BoundingBox.MaxX = 69;
	WimpCreateIconBlock.Icon.BoundingBox.MaxY = 68;
	WimpCreateIconBlock.Icon.IconFlags = IconFlags_IconBar;
	WimpCreateIconBlock.Icon.IconData.IconSpriteIndirect.Sprite = Sprite;
	WimpCreateIconBlock.Icon.IconData.IconSpriteIndirect.Area = WimpSpriteArea;
	WimpCreateIconBlock.Icon.IconData.IconSpriteIndirect.Length = strlen(Sprite);
	SWIRegs.r[0] = 0;
	SWIRegs.r[1] = (int)&WimpCreateIconBlock;
	SWI(Wimp_CreateIcon);
	return(SWIRegs.r[0]);
}

// Function to check if a key is pressed
int KeyPressCheck(int Key) {
	SWIRegs.r[0] = 129;
	SWIRegs.r[1] = Key ^ 0xff;
	SWIRegs.r[2] = 0xff;
	SWI(OS_Byte);
	return((SWIRegs.r[1] == 0xff));
}

// Function to check mouse buttons
int MouseButtonCheck(int Button) {
	SWIRegs.r[0] = (int)&WimpPollBlockStorage;
	SWI(Wimp_GetPointerInfo);
	return((WimpPollBlockStorage.MouseClick.Buttons == Button));
}

// Function to create a simple menu
t_Menu *CreateMenu(char *Title, ...) {
	char *Entry;
	int Count = 0;
	t_MenuHeader *MenuHeader;
	t_MenuItem   *MenuItem;
	va_list Entries;

	// Count the number of entries needed

	va_start(Entries,Title); // Get the parameter list
	for(;;) {
		Entry = va_arg(Entries, char*); // Get next one
		if(Entry == NULL) { break; }
		Count++;
	}
	va_end(Entries); // Clean up

	// Allocate the space we need
	MenuHeader = malloc(sizeof(t_MenuHeader) + Count * sizeof(t_MenuItem));
	if(MenuHeader == NULL) { SWIE("Menu malloc"); }

	// Fill Header
	if (strlen(TXT(Title)) > sizeof(MenuHeader->Title)) {
		MenuHeader->Title.IconTextIndirect.Text = TXT(Title);
		MenuHeader->Title.IconTextIndirect.Validation = NULL;
		MenuHeader->Title.IconTextIndirect.Length = strlen(TXT(Title));
	}
	else {
		strncpy(MenuHeader->Title.IconText,TXT(Title),sizeof(MenuHeader->Title.IconText));
	}
	MenuHeader->TitleForeground = 7;
	MenuHeader->TitleBackground = 2;
	MenuHeader->BodyForeground = 7;
	MenuHeader->BodyBackground = 0;
	MenuHeader->Width = 0;
	MenuHeader->Height = 44;
	MenuHeader->Gap = 0;

	// Point to first menu entry
	// Since MenuHeader is a pointer to the menu header, adding 1 points just after it!
	MenuItem = (t_MenuItem*)(MenuHeader+1);

	va_start(Entries,Title); // Get the parameter list again
	for(;;) {
		Entry = va_arg(Entries, char*); // Get next one
		if(Entry == NULL) { break; }
		MenuItem->MenuFlags = MenuFlags_Standard;
		MenuItem->MenuLink.Warning = 0;
		if (strlen(TXT(Entry)) > sizeof(MenuItem->IconData.IconText)) {
			MenuItem->IconData.IconTextIndirect.Text = TXT(Entry);
			MenuItem->IconData.IconTextIndirect.Validation = NULL;
			MenuItem->IconData.IconTextIndirect.Length = strlen(TXT(Entry));
			MenuItem->IconFlags = IconFlags_MenuItem | IconFlags_Mask_Indirect;
		}
		else {
			strncpy(MenuItem->IconData.IconText,TXT(Entry),sizeof(MenuItem->IconData.IconText));
			MenuItem->IconFlags = IconFlags_MenuItem;
		}
		MenuItem++;
	}
	// Set flag in last menu item that it is the last one
	MenuItem--;
	MenuItem->MenuFlags = (MenuItem->MenuFlags | MenuFlags_Mask_Last);
	va_end(Entries); // Clean up

	// Set flag in first if title is indirected
	if (strlen(TXT(Title)) > sizeof(MenuHeader->Title)) {
		MenuItem = (t_MenuItem*)(MenuHeader+1);
		MenuItem->MenuFlags = MenuItem->MenuFlags | MenuFlags_Title_Indirect;
	}
	return ((t_Menu*)MenuHeader);
}


// Open Menu
void OpenMenu(t_Menu *Menu) {

	t_MenuHeader *MenuHeader;
	t_MenuItem *MenuItem;

	MenuHeader = (t_MenuHeader*)Menu;

	// X position is 64 to the left of the mouse
	// Y position depends: Iconbar or not
	SWIRegs.r[1] = (int)MenuHeader;
	SWIRegs.r[2] = WimpPollBlock->MouseClick.Mouse.X - 64;
	SWIRegs.r[3] = WimpPollBlock->MouseClick.Mouse.Y - 8;
	if (WimpPollBlock->MouseClick.WindowHandle == WindowIconbar) {
		SWIRegs.r[3] = 96 + MenuHeader->Height;
		MenuItem = (t_MenuItem*)(MenuHeader+1);
		do	{
			SWIRegs.r[3] += MenuHeader->Height;
			if ((MenuItem->MenuFlags & MenuFlags_Mask_Dashes) != 0) SWIRegs.r[3] += 24;
			MenuItem++;
		}
		while ((MenuItem->MenuFlags & MenuFlags_Mask_Last) == 0);
	}
	SWI(Wimp_CreateMenu);

}

// Create a basic window
t_Window *CreateBasicWindow(char *Title, unsigned Flags, int Icons, int MaxX, int MaxY) {

	 t_WindowHeader *WindowHeader;

	WindowHeader = malloc(sizeof(t_WindowHeader) + Icons * sizeof(t_Icon));
	if(WindowHeader == NULL) { SWIE("Window malloc"); }

	WindowHeader->Visible.MinX = 0;
	WindowHeader->Visible.MinY = 0;
	WindowHeader->Visible.MaxX = MaxX;
	WindowHeader->Visible.MaxY = MaxY;
	WindowHeader->ScrollX = 0;
	WindowHeader->ScrollY = 0;
	WindowHeader->WindowStack = Window_OpenInFront;
	WindowHeader->WindowFlags = Flags;
	WindowHeader->TitleForground = 7;
	WindowHeader->TitleBackground = 2;
	WindowHeader->WorkareaForground = 7;
	WindowHeader->WorkareaBackground = 1;
	WindowHeader->ScrollbarBackground = 3;
	WindowHeader->ScrollbarForeground = 1;
	WindowHeader->TitleFocusBackground = 12;
	WindowHeader->ExtraFlags = 0;
	WindowHeader->Workarea.MinX = 0;
	WindowHeader->Workarea.MinY = -MaxY;
	WindowHeader->Workarea.MaxX = MaxX;
	WindowHeader->Workarea.MaxY = 0;
	WindowHeader->TitleIconFlags = IconFlags_WindowTitle;
	WindowHeader->WorkareaButtonType = IconButton_MenuOnly;
	WindowHeader->ToolSpriteArea = WimpSpriteArea;
	WindowHeader->MinArea = 0;
	WindowHeader->TitleIconData.IconTextIndirect.Text = TXT(Title);
	WindowHeader->TitleIconData.IconTextIndirect.Validation = NULL;
	WindowHeader->TitleIconData.IconTextIndirect.Length = strlen(TXT(Title));
	WindowHeader->IconCount = Icons;
	return((t_Window*)WindowHeader);
}



void FillIcon(t_Icon *Icon, unsigned Flags, char* Text, int Length, char *Validation, int ESG, int X, int Y, int Width, int Height) {
	Icon->BoundingBox.MinX = X;
	Icon->BoundingBox.MinY = -Y-Height;
	Icon->BoundingBox.MaxX = X+Width;
	Icon->BoundingBox.MaxY = -Y;
	Icon->IconFlags = Flags | IconFlags_Mask_Indirect | ((ESG & 0x1f)<<IconFlags_Shift_ESG);
	if (*Validation == 'R') { Icon->IconFlags |= IconFlags_Mask_Border; }
	Icon->IconData.IconTextIndirect.Text = TXT(Text);
	Icon->IconData.IconTextIndirect.Validation = Validation;
	if (Length == 0) { Icon->IconData.IconTextIndirect.Length = strlen(TXT(Text)); }
	else             { Icon->IconData.IconTextIndirect.Length = Length;                  }
	//BuggyIconI("Icon",Icon);
}

#define FillTextIcon(Window,Icon,Flags,Text,X,Y,Validation,Width) FillIcon(&Window->WindowIcon[Icon],Flags,Text,1,Validation,0,X,Y,Width,44)
#define FillEditIcon(Window,Icon,Text,Length,Validation,ESG,X,Y,Width) FillIcon(&Window->WindowIcon[Icon],IconFlags_Edit | IconFlags_Mask_Border,Text,Length,Validation,ESG,X,Y,Width,44)
#define FillButtonIcon(Window,Icon,Text,Validation,X,Y,Width,Height) FillIcon(&Window->WindowIcon[Icon],IconFlags_Button | IconFlags_Mask_Border,Text,1,Validation,0,X,Y,Width,Height)
#define FillOnOffIcon(Window,Icon,Validation,ESG,X,Y) FillIcon(&Window->WindowIcon[Icon],IconFlags_OnOff,Icon_NoText,1,Validation,ESG,X,Y,44,44)
#define FillClickIcon(Window,Icon,Validation,X,Y) FillIcon(&Window->WindowIcon[Icon],IconFlags_Click,Icon_NoText,1,Validation,0,X,Y,44,44)

#define FillTextIconXY(Window,Icon,Flags,Text,Validation,Xs,Xi,Ys,Yi,Width) FillIcon(&Window->WindowIcon[Icon],Flags,Text,1,Validation,0,XY(Xs)+Xi,XY(Ys)+Yi,Width,XY("T"))
#define FillEditIconXY(Window,Icon,Text,Length,Validation,ESG,Xs,Xi,Ys,Yi,Width) FillIcon(&Window->WindowIcon[Icon],IconFlags_Edit | IconFlags_Mask_Border,Text,Length,Validation,ESG,XY(Xs)+Xi,XY(Ys)+Yi,Width,XY("T"))
#define FillButtonIconXY(Window,Icon,Text,Validation,Xs,Xi,Ys,Yi,Width,Height) FillIcon(&Window->WindowIcon[Icon],IconFlags_Button | IconFlags_Mask_Border,Text,1,Validation,0,XY(Xs)+Xi,XY(Ys)+Yi,Width,Height)
#define FillOnOffIconXY(Window,Icon,Validation,ESG,Xs,Xi,Ys,Yi) FillIcon(&Window->WindowIcon[Icon],IconFlags_OnOff,Icon_NoText,1,Validation,ESG,XY(Xs)+Xi,XY(Ys)+Yi,XY("T"),XY("T"))
#define FillClickIconXY(Window,Icon,Validation,Xs,Xi,Ys,Yi) FillIcon(&Window->WindowIcon[Icon],IconFlags_Click,Icon_NoText,1,Validation,0,XY(Xs)+Xi,XY(Ys)+Yi,XY("T"),XY("T"))

// Get Icon Text
char *GetIconText(unsigned IconFlags, t_IconData *IconData) {

	if ((IconFlags & IconFlags_Mask_Text) == 0) {
		IconTextBuffer[0] = 0;
		return ((char*)(&IconTextBuffer));
	}

	if ((IconFlags & IconFlags_Mask_Indirect) == 0) {
		strncpy(IconTextBuffer,IconData->IconText,sizeof(t_IconData));
		StringToC(IconTextBuffer);
		return ((char*)(&IconTextBuffer));
	}

	StringToC(IconData->IconTextIndirect.Text);
	return (IconData->IconTextIndirect.Text);
}

#define GetIconTextFD(IconFlags) GetIconText(IconFlags,(t_IconData*)(&IconFlags +1))

#define GetIconTextMenuEntry(Menu,Item) GetIconText(Menu->MenuItem[Item].IconFlags,&(Menu->MenuItem[Item].IconData))


void SetIconText(unsigned IconFlags,t_IconData *IconData, char *Text) {

	char *c;
	char x;

	if ((IconFlags & IconFlags_Mask_Text) == 0) {
		// No Text in the icon
		return;
	}

	if ((IconFlags & IconFlags_Mask_Indirect) == 0) {
		// Text directly in icon data, length limited
		strncpy(IconData->IconText,Text,sizeof(t_IconData));
		return;
	}

	if (strlen(Text)>=IconData->IconTextIndirect.Length) {
		// Text it a bit too long for the icon so we cut it off
		c = Text + IconData->IconTextIndirect.Length -1; // -1 to allow trailing zero
		x = *c;
		*c = 0;
		strcpy(IconData->IconTextIndirect.Text,Text);
		*c = x;
	}
	else {
		// Text fits nicely...
		strcpy(IconData->IconTextIndirect.Text,Text);
	}
}

#define SetIconTextFD(IconFlags,Text) SetIconText(IconFlags,(t_IconData*)(&IconFlags +1),Text)

int GetMenuEntryNumber(t_Menu *Menu, char *Token)  {
	char *Entry = TXT(Token);
	int Result = -1;
	int i;
	for (i=0;Result==-1;i++) {
		if(strcmp(Entry,GetIconText(Menu->MenuItem[i].IconFlags,&(Menu->MenuItem[i].IconData))) == 0) { Result = i; }
		if ((Menu->MenuItem[i].MenuFlags & MenuFlags_Mask_Last) != 0) { break; }
	}
	return(Result);
}


int GetWindowIconNumber(t_Window *Window, char *Token)  {
	char *Entry = TXT(Token);
	int Result = -1;
	int i;

	for (i=0;i<Window->WindowHeader.IconCount;i++) {
		if (strcmp(Entry,GetIconText(Window->WindowIcon[i].IconFlags,&(Window->WindowIcon[i].IconData))) == 0) { Result = i; }
	}
	return(Result);
}

void MessagesIcon(unsigned *IconFlags, t_IconData *IconData) {

	char *t;

	// Get text
	t = GetIconText(*IconFlags,IconData);

	if (*t == '>') { // I will translate this one...
		t = TXT(t);
		if (*t != '>') { // translate succeeded...
			if ((*IconFlags & IconFlags_Mask_Indirect) == 0) {
				// Make indirect
				*IconFlags = *IconFlags | IconFlags_Mask_Indirect;
				IconData->IconTextIndirect.Validation = NULL;
				IconData->IconTextIndirect.Length = strlen(t);
			}
			IconData->IconTextIndirect.Text = t;
			if (IconData->IconTextIndirect.Length < strlen(t)) {
				IconData->IconTextIndirect.Length = strlen(t);
			}
		}
	}
}


void TemplatesOpen(char *FileName) {

	SWIRegs.r[1] = (int)FileName;
	SWI(Wimp_OpenTemplate);

}

void TemplatesClose(void) {

	SWI(Wimp_CloseTemplate);

}

t_Window *TemplatesLoad(char *WindowName) {

	int SpaceWindow;
	int SpaceIndirect;
	int i;
	t_Window *Window;
	char *Indirect;

	// Wimp_LoadTemplate - get size
	// R1 	0 to find the required buffer size
	// R2 	Pointer to workspace for indirected data
	// R3 	Pointer to end of workspace +1 byte
	// R4 	Pointer to 256 byte array for font reference, or –1 for no fonts
	// R5 	Pointer to (wildcard) name to match (must be 12 bytes word-aligned)
	// R6 	Position to search from, or 0 for the first call
	//
	// R1 	Size of window and icons
	// R2 	Size of indirect data

	// Wimp_LoadTemplate - load
	// R1 	Pointer to buffer for template
	// R2 	Pointer to workspace for indirected data
	// R3 	Pointer to end of indirect data workspace +1 byte
	// R4 	Pointer to 256 byte array for font reference, or –1 for no fonts
	// R5 	Pointer to (wildcard) name to match (must be 12 bytes word-aligned)
	// R6 	Position to search from, or 0 for the first call
	//
	// R2 	Pointer to remaining workspace
	// R5 	Template name returned in block
	// R6 	Position of next entry, or 0 if template not found

	// Find out the space we need to allocate (r[1] = 0)
	SWIRegs.r[1] = 0; // get space info
	SWIRegs.r[2] = 0;
	SWIRegs.r[3] = 0;
	SWIRegs.r[4] = -1; // no fonts
	SWIRegs.r[5] = (int)WindowName;
	SWIRegs.r[6] = 0;
	SWI(Wimp_LoadTemplate);
	SpaceWindow   = SWIRegs.r[1];
	SpaceIndirect = SWIRegs.r[2];

	// If the window we want doesn’t exist in the template: oops
	if (SWIRegs.r[6] == 0) {
		SWIE("TemplateLoad not found");
	}

	// Allocate Space - in one buffer for both so we can free up if needed easier
	Window = malloc(SpaceWindow+SpaceIndirect);
	if(Window == NULL) { SWIE("TemplateLoad malloc"); }
	if (SpaceIndirect == 0) { Indirect = NULL; }
	else                    { Indirect = ((char*)Window) + SpaceWindow; }

	// Load the bastard
	SWIRegs.r[1] = (int)Window;
	SWIRegs.r[2] = (int)Indirect;
	SWIRegs.r[3] = (int)Indirect + SpaceIndirect;
	SWIRegs.r[4] = -1; // no fonts
	SWIRegs.r[5] = (int)WindowName;
	SWIRegs.r[6] = 0;
	SWI(Wimp_LoadTemplate);


	MessagesIcon(&(Window->WindowHeader.TitleIconFlags),&(Window->WindowHeader.TitleIconData));
	// We have it now... MsgTrans all Text if needed...

	for (i=0;i<Window->WindowHeader.IconCount;i++) {
		MessagesIcon(&(Window->WindowIcon[i].IconFlags),&(Window->WindowIcon[i].IconData));
	}

	return(Window);

}

// Wimp create window
t_WindowHandle WimpCreateWindow(t_Window *Window) {
	SWIRegs.r[1] = (int)Window;
	SWI(Wimp_CreateWindow);
	return((t_WindowHandle)SWIRegs.r[0]);
}

// Wimp close window
void WimpCloseWindow(void) {
	SWIRegs.r[1] = (int)(WimpPollBlock);
	SWI(Wimp_CloseWindow);
}

// Wimp open window
void WimpOpenWindow(void) {
	SWIRegs.r[1] = (int)(WimpPollBlock);
	SWI(Wimp_OpenWindow);
}

// Move to center
void MoveToCenter(t_BoxenLuder *Box) {
	int X,Y;
	// Current screen mode
	SWIRegs.r[0] = -1;
	// Read X and Y resolution
	SWIRegs.r[1] = 11; SWI(OS_ReadModeVariable); X = ++(SWIRegs.r[2]);
	SWIRegs.r[1] = 12; SWI(OS_ReadModeVariable); Y = ++(SWIRegs.r[2]);
	// Shift resolution by Eigfactor
	SWIRegs.r[1] = 4; SWI(OS_ReadModeVariable); X = X * (++(SWIRegs.r[2]));
	SWIRegs.r[1] = 5; SWI(OS_ReadModeVariable); Y = Y * (++(SWIRegs.r[2]));
	// Get offset to shift to middle X
	X = (X - (Box->MaxX - Box->MinX)) / 2;
	Box->MinX +=X;
	Box->MaxX +=X;
	// Get offset to shift to middle Y
	Y = (Y - (Box->MaxY - Box->MinY)) / 2;
	Box->MinY +=Y;
	Box->MaxY +=Y;
}

// Wimp open window
t_WindowHandle WimpOpenNewWindow(t_Window *Window, t_WindowHandle WindowHandle, int Center) {

	if (WindowHandle == -1) { WimpPollBlockStorage.OpenWindow.WindowHandle = WimpCreateWindow(Window); }
	else                    { WimpPollBlockStorage.OpenWindow.WindowHandle = WindowHandle; }
	WimpPollBlockStorage.OpenWindow.Visible.MinX = Window->WindowHeader.Visible.MinX;
	WimpPollBlockStorage.OpenWindow.Visible.MinY = Window->WindowHeader.Visible.MinY;
	WimpPollBlockStorage.OpenWindow.Visible.MaxX = Window->WindowHeader.Visible.MaxX;
	WimpPollBlockStorage.OpenWindow.Visible.MaxY = Window->WindowHeader.Visible.MaxY;
	WimpPollBlockStorage.OpenWindow.ScrollX      = Window->WindowHeader.ScrollX;
	WimpPollBlockStorage.OpenWindow.ScrollY      = Window->WindowHeader.ScrollY;
	WimpPollBlockStorage.OpenWindow.WindowStack  = Window->WindowHeader.WindowStack;

	if (Center) { MoveToCenter(&(WimpPollBlockStorage.OpenWindow.Visible)); }

	SWIRegs.r[1] = (int)(&WimpPollBlockStorage);
	SWI(Wimp_OpenWindow);

	return(WimpPollBlockStorage.OpenWindow.WindowHandle);
}

void WimpRedrawIcon(t_Window *Window,t_WindowHandle WindowHandle, t_IconHandle IconHandle) {
	t_IconSetState Buf;
	Buf.WindowHandle = WindowHandle;
	Buf.IconHandle   = IconHandle;
	Buf.EORword = 0;
	Buf.CLRword = 0;
	SWIRegs.r[1] = (int)(&Buf);
	SWI(Wimp_SetIconState);
}

int WimpGetIconState(t_WindowHandle WindowHandle, t_IconHandle IconHandle) {
	t_WimpGetIconStateBlock Block;
	Block.WindowHandle = WindowHandle;
	Block.IconHandle = IconHandle;
	SWIRegs.r[1] = (int)(&Block);
	SWI(Wimp_GetIconState);
	return((Block.Icon.IconFlags & IconFlags_Mask_Selected) == 0 ? False : True);
}


int GetTerritoryNumber(void) {
	if (SWIX(Territory_Number) != NULL) { return(-1); }
	else                                { return(SWIRegs.r[0]); }
}	

void GetTerritoryName(char *Buffer, int Length) {
	if (SWIX(Territory_Number) != NULL) { 
		*Buffer = 0; 
		return;
	}
	
	SWIRegs.r[1] = (int)Buffer;
	SWIRegs.r[2] = Length;
	if (SWIX(Territory_NumberToName) != NULL) { *Buffer = 0; }
}	

int GetCountryNumber(void) {
	SWIRegs.r[0] = 70;  // Read/Write Country (0x46)
	SWIRegs.r[1] = 127; // Read
	if (SWIX(OS_Byte) != NULL) { return(-1); }
	else                       { return(SWIRegs.r[1]); }
}


void GetCountryName(char *Buffer, int Length) {
	SWIRegs.r[0] = 70;  // Read/Write Country (0x46)
	SWIRegs.r[1] = 127; // Read
	if (SWIX(OS_Byte) != NULL) { 
		*Buffer = 0;
		return;
	}
	
	SWIRegs.r[3] = SWIRegs.r[1];
	SWIRegs.r[1] = 67;  // Service International (0x43)
	SWIRegs.r[2] = 2;   // Number to Name
	SWIRegs.r[4] = (int)Buffer;
	SWIRegs.r[5] = Length;
	if (SWIX(OS_ServiceCall) != NULL) { *Buffer = 0; }
}	

void SetResourcesPathByCountry(int NameOrNumber) {

	// Get the country name or number as base...
	char Language[64];
	if (NameOrNumber) {
		GetCountryName(&Language[0],sizeof(Language));
	}
	else {
		sprintf(Language,"%d",GetCountryNumber());
	}

	// Put together language resources Path
	strcpy(MyResources,MyAppDir);		// <App$Dir>
	strcat(MyResources,".Resources.");	// <App$Dir>.Resources.
	strcat(MyResources,Language);		// <App$Dir>.Resources.language
	
	BuggyText("L:",MyResources);

	// Check if it is there as folder
	SWIRegs.r[0] = 13;
	SWIRegs.r[1] = (int)(&MyResources[0]);
	if (SWIX(OS_File) != NULL) { // Default since not found
		if (NameOrNumber) { strcpy(Language,"UK"); } 
		else              { strcpy(Language,"1"); } 
	}
	else {
		if ((SWIRegs.r[0] != 2) & (SWIRegs.r[0] !=3)) {
			// Default since not a folder
			if (NameOrNumber) { strcpy(Language,"UK2"); } 
			else              { strcpy(Language,"1"); } 
		}
	}

	// Put together full resources Path
	strcpy(MyResources,MyAppDir);		// <App$Dir>
	strcat(MyResources,".Resources.");	// <App$Dir>.Resources.
	strcat(MyResources,Language);		// <App$Dir>.Resources.language
	strcat(MyResources,".,");			// <App$Dir>.Resources.language.,
	strcat(MyResources,MyAppDir);		// <App$Dir>.Resources.language.,<App$Dir>
	strcat(MyResources,".Resources.,");	// <App$Dir>.Resources.language.,<App$Dir>.Resources.,
	strcat(MyResources,MyAppDir);		// <App$Dir>.Resources.language.,<App$Dir>.Resources.,<App$Dir>
	strcat(MyResources,".");			// <App$Dir>.Resources.language.,<App$Dir>.Resources.,<App$Dir>.

	BuggyText("P:",MyResources);
	
	// Set up system varialbe AppRes$Path
	SWIRegs.r[0] = (int)(&MyResPath[0]);
	SWIRegs.r[1] = (int)(&MyResources[0]);
	SWIRegs.r[2] = strlen(MyResources);
	SWIRegs.r[3] = 0;
	SWIRegs.r[4] = 0;
	SWI(OS_SetVarVal);
}

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

	int ReasonCode;

	BuggyClear;
	
	// This call is not needed if you use ResFind since ResFind will do the trick...
	// and it is more versatile allowing you to set personal language preferences
	// and ResFind supports old OS with the 10 character limit for filenames too
	SetResourcesPathByCountry(True);

	WimpInitialise();

	MyBarIcon = WimpCreateIconBarIcon("Switcher",IconBar_IconRight);

	// Load Messages
	MessagesLoad(MyMessagesFile);
	// Load Templates
	TemplatesOpen(MyTemplatesFile);
	MyLanguageWindow = TemplatesLoad("Language");
	TemplatesClose();
	int TNU_Icon = GetWindowIconNumber(MyLanguageWindow,"TNU");
	int TNA_Icon = GetWindowIconNumber(MyLanguageWindow,"TNA");
	int CNU_Icon = GetWindowIconNumber(MyLanguageWindow,"CNU");
	int CNA_Icon = GetWindowIconNumber(MyLanguageWindow,"CNA");

	char SomeString[64];
	
	sprintf(SomeString,"%d",GetTerritoryNumber());
	SetIconTextFD(MyLanguageWindow->WindowIcon[TNU_Icon].IconFlags,SomeString);
	GetTerritoryName(&SomeString[0],sizeof(SomeString));
	SetIconTextFD(MyLanguageWindow->WindowIcon[TNA_Icon].IconFlags,SomeString);
	
	sprintf(SomeString,"%d",GetCountryNumber());
	SetIconTextFD(MyLanguageWindow->WindowIcon[CNU_Icon].IconFlags,SomeString);
	GetCountryName(&SomeString[0],sizeof(SomeString));
	SetIconTextFD(MyLanguageWindow->WindowIcon[CNA_Icon].IconFlags,SomeString);


	// The classic infobox
	MyInfoWindow = CreateBasicWindow(">I_TIT",WindowFlags_Info,6,20+120+20+300+20,20+44+20+44+20+44+20);
	FillTextIconXY(MyInfoWindow,0,IconFlags_TextR,">I_NAME",           IconValidation_Flat,"S",     0,"S",   0,120);
	FillTextIconXY(MyInfoWindow,1,IconFlags_TextC,(char*)MyTaskName,   IconValidation_Text,"S2+120",0,"S",   0,300);
	FillTextIconXY(MyInfoWindow,2,IconFlags_TextR,">I_AUTHOR",         IconValidation_Flat,"S",     0,"S2T", 0,120);
	FillTextIconXY(MyInfoWindow,3,IconFlags_TextC,"Herbert zur Nedden",IconValidation_Text,"S2+120",0,"S2T", 0,300);
	FillTextIconXY(MyInfoWindow,4,IconFlags_TextR,">I_VERSION",        IconValidation_Flat,"S",     0,"S3T2",0,120);
	FillTextIconXY(MyInfoWindow,5,IconFlags_TextC,(char*)MyVersion,    IconValidation_Text,"S2+120",0,"S3T2",0,300);

	// A simple menu with just Info and Quit
	MyBarMenu = CreateMenu(">M_TITLE",">M_INFO",">M_LANGUAGE",">M_QUIT",NULL);
	MyBarMenu->MenuItem[GetMenuEntryNumber(MyBarMenu,">M_INFO")].MenuLink.Window  = WimpCreateWindow(MyInfoWindow);
	MyBarMenu->MenuItem[GetMenuEntryNumber(MyBarMenu,">M_LANGUAGE")].MenuLink.Window  = WimpCreateWindow(MyLanguageWindow);
	int MenuEntry_Quit = GetMenuEntryNumber(MyBarMenu,">M_QUIT");

	while (True) {
		ReasonCode = WimpPoll();
		BuggyInt("ReasonCode",ReasonCode);

		// Handle the request
		switch(ReasonCode) {

		// Mouse click
		case ReasonCode_MouseClick:
			//BuggyBuffI("Mouse",WimpPollBlock,12);
			// Iconbar icon
			if ((WimpPollBlock->MouseClick.WindowHandle == WindowIconbar) && (WimpPollBlock->MouseClick.IconHandle == MyBarIcon)) {
				switch(WimpPollBlock->MouseClick.Buttons) {
				case MouseButtonMiddle: // Menu click
					OpenMenu(MyBarMenu);
					break;
				}
			}
			break;

		// Menu selection
		case ReasonCode_MenuSelection:
			//BuggyBuffI("Menu",WimpPollBlock,12);
			BuggyInt("i",WimpPollBlock->MenuSelection.MenuItem[0]);
			BuggyInt("q",MenuEntry_Quit);
			if (WimpPollBlock->MenuSelection.MenuItem[0] == MenuEntry_Quit) {
				WimpCloseDown();
				break;
			}

			if (MouseButtonCheck(MouseButtonRight)) { OpenMenu(MyBarMenu); }
			break;

		// Window stuff
		case ReasonCode_OpenWindow:
			//BuggyMessage("ReasonCode_OpenWindow");
			WimpOpenWindow();
			break;
		case ReasonCode_CloseWindow:
			//BuggyMessage("ReasonCode_CloseWindow");
			WimpCloseWindow();
			break;

		// User message
		case ReasonCode_UserMessage:
		case ReasonCode_UserMessageRecorded:
		case ReasonCode_UserMessageAcknowledge:
			switch(WimpPollBlock->UserMessage.MessageCode) {
			case MessageCode_Quit:
				 WimpCloseDown();
				 break;
			}
			break;
		}
	}


}

