#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[]    = "sqlitecall";
const char MyVersion[]     = "Version 1.00";

t_IconHandle MyBarIcon = 0;
t_Menu *MyBarMenu;
t_Window *MyInfoWindow;
t_Window *MyMainWindow;
t_WindowHandle MyMainWindowHandle = -1;

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

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

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

// Send a reply - the original message being in the WimpPollBlock!
void WimpMessageReply(int ReasonCode, int MessageCode) {
	WimpPollBlock->UserMessage.MessageCode = MessageCode;
	WimpPollBlock->UserMessage.YourRef = WimpPollBlock->UserMessage.MyRef;
	SWIRegs.r[0] = ReasonCode;
	SWIRegs.r[1] = (int)(WimpPollBlock);
	SWIRegs.r[2] = WimpPollBlock->UserMessage.SenderHandle;
	BuggyBuffI("WimpMessageReply",WimpPollBlock,20);
	SWI(Wimp_SendMessage);
}

// 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 remove Icon  from icon bar with SWI Wimp_DeleteIcon
void WimpDeleteIconBarIcon(t_IconHandle IconHandle) {
	t_WimpDeleteIconBlock WimpDeleteIconBlock;
	WimpDeleteIconBlock.WindowHandle = WindowIconbar;
	WimpDeleteIconBlock.IconHandle = IconHandle;
	SWIRegs.r[0] = 0;
	SWIRegs.r[1] = (int)&WimpDeleteIconBlock;
	SWI(Wimp_DeleteIcon);
}

// 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(Title) > sizeof(MenuHeader->Title)) {
		MenuHeader->Title.IconTextIndirect.Text = Title;
		MenuHeader->Title.IconTextIndirect.Validation = NULL;
		MenuHeader->Title.IconTextIndirect.Length = strlen(Title);
	}
	else {
		strncpy(MenuHeader->Title.IconText,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(Entry) > sizeof(MenuItem->IconData.IconText)) {
			MenuItem->IconData.IconTextIndirect.Text = Entry;
			MenuItem->IconData.IconTextIndirect.Validation = NULL;
			MenuItem->IconData.IconTextIndirect.Length = strlen(Entry);
			MenuItem->IconFlags = IconFlags_MenuItem | IconFlags_Mask_Indirect;
		}
		else {
			strncpy(MenuItem->IconData.IconText,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(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 = Title;
	WindowHeader->TitleIconData.IconTextIndirect.Validation = NULL;
	WindowHeader->TitleIconData.IconTextIndirect.Length = strlen(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 = Text;
	Icon->IconData.IconTextIndirect.Validation = Validation;
	if (Length == 0) { Icon->IconData.IconTextIndirect.Length = strlen(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,X,Y,Width) FillIcon(&Window->WindowIcon[Icon],IconFlags_Edit | IconFlags_Mask_Border,Text,Length,Validation,0,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,Xs,Xi,Ys,Yi,Width) FillIcon(&Window->WindowIcon[Icon],IconFlags_Edit | IconFlags_Mask_Border,Text,Length,Validation,0,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 = 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 = 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);
}


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

// Create a big window
t_Window *CreateBigWindow(char *Title, unsigned Flags, int Icons, int MaxX, int MaxY, int VisX, int VisY) {
	t_WindowHeader *WindowHeader;
	WindowHeader = (t_WindowHeader*)CreateBasicWindow(Title, Flags, Icons, MaxX, MaxY);
	// Just set visible size - we move to center later...
	WindowHeader->Visible.MaxX = VisX;
	WindowHeader->Visible.MaxY = VisY;
	return((t_Window*)WindowHeader);
}

// 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 WimpRedrawAllIcons(t_Window *Window,t_WindowHandle WindowHandle) {
	t_IconSetState Buf;
	Buf.WindowHandle = WindowHandle;
	Buf.EORword = 0;
	Buf.CLRword = 0;
	for (Buf.IconHandle=0;Buf.IconHandle<Window->WindowHeader.IconCount;Buf.IconHandle++) {
		SWIRegs.r[1] = (int)(&Buf);
		SWI(Wimp_SetIconState);
	}
}

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

int IsWimpScrap(char *p) {
	char s[256];
	BuggyText("Path",p);
	if (StringCompare((char*)(&WimpScrap),p) == 0) return (True);
	SWIRegs.r[0] = (int)(&WimpScrapVar);
	SWIRegs.r[1] = (int)(&s);
	SWIRegs.r[2] = 255;
	SWIRegs.r[3] = 0;
	SWIRegs.r[4] = 3;
	SWI(OS_ReadVarVal);
	BuggyText("Path",(char*)(&s));
	if (StringCompare((char*)(&s),p) == 0) return (True);
	return (False);
}

//----------------------

// My variables
char FileName[256] = "<Obey$Dir>.DB";
char SQL1[] = "SELECT * from tabby;";
char SQL2[] = "INSERT INTO tabby VALUES(99,'Arsch');";
#define LineMax 20 // Icons 0-2 are other stuff, as of 3 are the lines...
#define IconName 0
#define IconSQL 1
#define IconLine 2
char Lines[LineMax][256];

// Close the file passed to this function...
void CloseFile(char *File) {
	char Buffer1[1024];
	char Buffer2[1024];
	int i;

	BuggyText("FileName",File);

	// Normalize file name
	SWIRegs.r[0] = 37;
	SWIRegs.r[1] = (int)(File);
	SWIRegs.r[2] = (int)(&Buffer1);
	SWIRegs.r[3] = 0;
	SWIRegs.r[4] = 0;
	SWIRegs.r[5] = sizeof(Buffer1);
	SWIX(OS_FSControl);
	BuggyText("FSControlled",Buffer1);

	// Loop through all file handles that we can have
	for (i=255;i>0;i--) {
		// Get detail on open file
		SWIRegs.r[0] = 7;
		SWIRegs.r[1] = i;
		SWIRegs.r[2] = (int)(&Buffer2);
		SWIRegs.r[3] = 0;
		SWIRegs.r[4] = 0;
		SWIRegs.r[5] = sizeof(Buffer2);
		if (SWIX(OS_Args) == NULL) {
			BuggyInt("Args",i);
			BuggyText("...",Buffer2);
			if (StringCompare(Buffer1,Buffer2) == 0) {
				// Close the bastard
				SWIRegs.r[0] = 255;
				SWIRegs.r[1] = i;
				SWIX(OS_Args);
				SWIRegs.r[0] = 0;
				SWIRegs.r[1] = i;
				SWIX(OS_Find);
				BuggyInt("Closed",i);
			}
		}
	}
}

// let's see if sqlite3 will to what I want it to
char *sqlite3(char *DB, char *SQL, char *Buffer) {
	char *c = Buffer;
	int *b;
	int BufNeed;
	char cmd[1024];
	FILE *f;
	char scrap[] = "<Obey$Dir>.sqlresult";
	//char scrap[] = "Pipe:$.sqlite3";

	// put command together to be
	// sqlite3 DB SQL-Command { > Pipe:$.sqlite3 }
	strcpy(cmd,"sqlite3 ");
	strcat(cmd,DB);
	strcat(cmd," \"");
	strcat(cmd,SQL);
	strcat(cmd,"\" { > ");
	strcat(cmd,scrap);
	strcat(cmd," }");
	BuggyText("cmd",cmd);

	// call sqlite3
	SWIRegs.r[0] = (int)&cmd;
	BuggyMessage("A");
	SWIX(Wimp_StartTask);
	BuggyMessage("B");
	BuggyInt(".",SWIRegs.r[0]);

	// Inspect output to set up the buffer...
	f = fopen(scrap,"r");
	fseek(f,0L,SEEK_END);
	BufNeed = (int)ftell(f);
	rewind(f);
	BuggyInt("Size",BufNeed);
	if (c != NULL) {
		b = (int*)c; b--;
		if (*b < BufNeed) { free(b); c = NULL; }
	}
	if (c == NULL) {
		b = malloc(BufNeed+1+sizeof(int));
		if(b == NULL) { SWIE("sqlite3 malloc"); }
		*b = BufNeed; b++;
		c = (char*)b;
	}
	// Get the output
	fread(c,BufNeed,1,f);
	fclose(f);
	c[BufNeed] = 0;
	BuggyText("Result",c);
	return(c);
}

void DisplayResult(char *Buffer) {
	// Note that the output is CR LF delimited ....
	int i = 0;
	int l;
	char *c = Buffer;
	char *n;
	while ((*c != 0) & (i < LineMax)) {
		BuggyText("Buf",c);
		l = StringLength(c);
		if (l == 0) {
			c++;
		}
		else {
			BuggyInt("..",l);
			n = c+l;
			*n = 0;
			strncpy(Lines[i],c,sizeof(Lines[i]));
			Lines[i][sizeof(Lines[i])-1] = 0;
			c = ++n;
			i++;
		}
	}
}


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

	int ReasonCode;
	int i;
	char *SQLBuffer = NULL;

	BuggyClear;

	WimpInitialise();
	WimpAddRemoveMessages(MessageCode_DataLoad);
	WimpAddRemoveMessages(MessageCode_DataLoadAck);

	MyBarIcon = WimpCreateIconBarIcon("Switcher",IconBar_IconRight);

	// 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((char*)MyTaskName,"Ego","Tsch",NULL);
	MyBarMenu->MenuItem[0].MenuLink.Window  = WimpCreateWindow(MyInfoWindow);
	int MenuEntry_Quit = 1;

	// Window from bottom: Space - LineMax Text - Space - Filename - Space:
	MyMainWindow = CreateBigWindow((char*)MyTaskName,WindowFlags_AllTools,LineMax+2,1200,20+44+20+44+20+LineMax*44+20,600,200);
	FillEditIconXY(MyMainWindow,IconName,(char*)(&FileName),sizeof(FileName),IconValidation_Text,"S",0,"S",0,1200-20-20);
	FillTextIconXY(MyMainWindow,IconSQL,IconFlags_TextL,(char*)&SQL1,IconValidation_Text,"S",0,"STS",0,1200-20-20);
	for (i=0;i<LineMax;i++) {
		Lines[i][0] = 0;
		FillTextIconXY(MyMainWindow,IconLine+i,IconFlags_TextL,(char*)&Lines[i],IconValidation_Text,"S",0,"STSTS",44*i,1200-20-20);
		}

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

		// 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 MouseButtonRight:
					SQLBuffer = sqlite3(FileName,SQL1,SQLBuffer);
					DisplayResult(SQLBuffer);
					WimpRedrawAllIcons(MyMainWindow,MyMainWindowHandle);
					//CloseFile(FileName);
					break;
				case MouseButtonMiddle: // Menu click
					OpenMenu(MyBarMenu);
					break;
				case MouseButtonLeft:
					MyMainWindowHandle = WimpOpenNewWindow(MyMainWindow,MyMainWindowHandle,True);
				}
			}
			break;

		// Key press
		// Menu selection
		case ReasonCode_MenuSelection:
			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:
			//BuggyInt("MessageCode",WimpPollBlock->UserMessage.MessageCode);
			//BuggyBuffI("Message",WimpPollBlock,12);
			switch(WimpPollBlock->UserMessage.MessageCode) {
			case MessageCode_Quit:
				 WimpCloseDown();
				 break;
			case MessageCode_DataLoad:
				strncpy(FileName,WimpPollBlock->UserMessage.MessageData.DataLoad.FileName,255);
				WimpMessageReply(ReasonCode,MessageCode_DataLoadAck);
				WimpRedrawAllIcons(MyMainWindow,MyMainWindowHandle);
				break;
			}
			break;
		}
	}

}

