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

t_IconHandle MyBarIcon = 0;
t_Menu *MyBarMenu;
t_Window *MyInfoWindow;
t_Window *MyMainWindow;
t_Window *MyPaneWindow;
t_Window *MyPartWindow;
t_WindowHandle MyMainWindowHandle = -1;
t_WindowHandle MyPaneWindowHandle = -1;
t_WindowHandle MyPartWindowHandle = -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':
			r += 48*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
	MessageBufferLength = SWIRegs.r[2];
	MyMessages = malloc(sizeof(t_MessageTrans_FileDescriptor)+MessageBufferLength);
	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];
}

// 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(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 = 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(t_WindowHandle WindowHandle) {
	if (WindowHandle != (t_WindowHandle)-1) {
		if (WindowHandle != Window_WimpBlock) {
			WimpPollBlockStorage.OpenWindow.WindowHandle = WindowHandle;
		}
		SWIRegs.r[1] = (int)(&WimpPollBlockStorage);
		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 WimpOpenNormalWindow(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);
}

// Wimp open a pane window
t_WindowHandle WimpOpenPaneWindow(t_Window *Pane, t_WindowHandle PaneHandle, t_WindowHandle ParentHandle, int X, int Y, int Xfree, int Yfree) {

	t_BoxenLuder ParentVisible;
	int i,j;

	if (ParentHandle == -1) { return PaneHandle; }

	// Where is the parent?
	WimpPollBlockStorage.GetWindowState.WindowHandle = ParentHandle;
	SWI(Wimp_GetWindowState);
	if (( WimpPollBlockStorage.GetWindowState.WindowFlags && WindowFlags_Mask_Open) == 0) { return PaneHandle; }

	ParentVisible.MinX = WimpPollBlockStorage.GetWindowState.Visible.MinX;
	ParentVisible.MaxX = WimpPollBlockStorage.GetWindowState.Visible.MaxX;
	ParentVisible.MinY = WimpPollBlockStorage.GetWindowState.Visible.MinY;
	ParentVisible.MaxY = WimpPollBlockStorage.GetWindowState.Visible.MaxY;

	if (PaneHandle == -1) { WimpPollBlockStorage.OpenWindow.WindowHandle = WimpCreateWindow(Pane); }
	else                  { WimpPollBlockStorage.OpenWindow.WindowHandle = PaneHandle; }
	WimpPollBlockStorage.OpenWindow.ScrollX      = Pane->WindowHeader.ScrollX;
	WimpPollBlockStorage.OpenWindow.ScrollY      = Pane->WindowHeader.ScrollY;
	WimpPollBlockStorage.OpenWindow.WindowStack  = Pane->WindowHeader.WindowStack;

	// Position the pane is relative to MinX, MaxY of the window
	// Get width of Pane
	i = Pane->WindowHeader.Workarea.MaxX - Pane->WindowHeader.Workarea.MinX;
	if (Xfree != -1) {
		// Adjust visible width ... to the one of the parent minus Xfree
		j = ParentVisible.MaxX - ParentVisible.MinX - Xfree;
		i = j < 1 ? 1 : ( j > i ? i:j );
	}
	WimpPollBlockStorage.OpenWindow.Visible.MinX = ParentVisible.MinX + X;
	WimpPollBlockStorage.OpenWindow.Visible.MaxX = WimpPollBlockStorage.OpenWindow.Visible.MinX + i;
	// Get height of Pane
	i = Pane->WindowHeader.Workarea.MinY - Pane->WindowHeader.Workarea.MaxY;
	if (Yfree != -1) {
		// Adjust visible height... to the one of the parent minus Yfree
		j = ParentVisible.MinY - ParentVisible.MaxY + Yfree;
		i = j > -1 ? -1 : ( j < i ? i:j);
	}
	WimpPollBlockStorage.OpenWindow.Visible.MaxY = ParentVisible.MaxY - Y;
	WimpPollBlockStorage.OpenWindow.Visible.MinY = WimpPollBlockStorage.OpenWindow.Visible.MaxY + i;

	SWIRegs.r[1] = (int)(&WimpPollBlockStorage);
	SWI(Wimp_OpenWindow);
	return(WimpPollBlockStorage.OpenWindow.WindowHandle);
}

// Wimp open a pane window attached to top left outside
#define WimpOpenPaneWindowTLO(Pane,PaneHandle,ParentHandle) WimpOpenPaneWindow(Pane,PaneHandle,ParentHandle,Pane->WindowHeader.Visible.MinX - Pane->WindowHeader.Visible.MaxX -2,0,-1,-1)



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];
	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);
	return((StringCompare((char*)(&s),p) == 0));
}

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

// My variables
#define MaxLines 20
#define MaxText 256
#define MaxDigit 6

char FileName[256] = "<Obey$Dir>.DB";
char Filter[MaxText] = "";
char NewNrC[MaxDigit] = "";
int  NewNrI;
char NewName[MaxText] = "";

char OldNrC[MaxDigit] = "";
int  OldNrI;
char OldName[MaxText] = "";

int  TableNrI[MaxLines];
char TableNrC[MaxLines][MaxDigit];
char TableName[MaxLines][MaxText];
char SQL[256];
#define IconDB 1
#define IconFilter 3
#define IconNr 4
#define IconName 5
#define IconLine 6 // First Icon for a line entry (each line has 2 icons...)

// 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 *BufData = Buffer;
	int *BufLen;
	int BufNeed;
	char cmd[1024];
	FILE *f;
	char x;
	char *c;
	int i;
	char scrap[] = "<Obey$Dir>.sqlresult";
	//char scrap[] = "Pipe:$.sqlite3";

	// put command together to be
	// sqlite3 -quote DB SQL-Command { > Pipe:$.sqlite3 }
	strcpy(cmd,"sqlite3 -quote ");
	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;
	SWIX(Wimp_StartTask);

	// Inspect output to set up the buffer...
	f = fopen(scrap,"r");
	fseek(f,0L,SEEK_END);
	BufNeed = (int)ftell(f);
	rewind(f);
	if (BufData != NULL) {
		BufData--; BufLen = (int*)BufData; BufData++; BufLen--;
		if (*BufLen < BufNeed) { free(BufLen); BufData = NULL; }
	}
	if (BufData == NULL) {
		// the buffer will get 3 extra bytes
		BufLen = malloc(BufNeed+3+sizeof(int));
		if(BufLen == NULL) { SWIE("sqlite3 malloc"); }
		*BufLen = BufNeed; BufLen++;
		BufData = (char*)BufLen;
		BufData++;
	}
	// Get the output
	c = BufData;
	*--c = 0; // Prefix Zerobyte for my load checks...
	for (i=0;i<BufNeed;i++) {
		x = fgetc(f);
		BuggyInt("x",(int)x);
		if ((x == (char)10) || x == (char)13) {
			if (*c != 0) { *++c = 0; }
		}
		else {
			*++c = x;
		}
		BuggyBuffA(".",BufData,BufNeed);
	}
	if (*c != 0) { *++c = 0; }
	*++c = 0;
	fclose(f);
	BuggyBuffA("Result",BufData,BufNeed);
	return(BufData);
}

// Check if I have an error message
int sqlite3Error(char *Buffer) {
	return (strncmp(Buffer,"Error: ",7) == 0 ? True : False);
}


// Count Results
int sqlite3Count(char *Buffer) {
	int i = 0;
	char *c = Buffer;
	// Return -1 if there is an error message...
	if (sqlite3Error(Buffer)) { return(-1); }

	// Note that the output lines are a list of strings up to an empty one
	for (;;) {
		// End of buffer... we're done
		if (*c == 0) { return(i); }
		// A new line is there
		i++;
		c = c + strlen(c) +1;
	}
}

// Get one line of the results
int sqlite3Result(char *Buffer, int Number, ...) {
	va_list Entries;
	int i = -1;
	char *c = Buffer;
	char *tVar;
	int  *iVar;
	int eos;

	//BuggyInt("Result Number ",Number);

	// Return False if there is an error message...
	if (sqlite3Error(Buffer)) { return(False); }
	// Seriously...
	if (Number < 0)           { return(False); }

	// Go the the entry we want
	// The code is very simliar to the sqlite3Count ...
	for (;i != Number;) {
		if (*c == 0) { return(False); }
		i++;
		if (i != Number) { c = c + strlen(c) +1; }
	}

	va_start(Entries,Number); // Get the parameter list

	// Parse the line noting that strings are in single quotes, numbers are not
	// And put into the parameters ...
	while(*c != 0) {
		switch (*c) {
		case ',': // Empty entry
			//BuggyMessage("empty value ignored");
			tVar = va_arg(Entries, char*); // Get next one
			break; // But do not touch it!
		case '\'': // String
			tVar = va_arg(Entries, char*); // Get next one
			eos = False;
			c++; // Start of string's content
			do {
				// Check if double quote and if put one into the string
				if (*c == '\'') {
					c++;
					if (*c == '\'') {
						// Yep, a quote inside my string
						*tVar++ = *c++;
					}
					else {
						// A single quote and thus end of my string...
						c--;
						eos = True;
					}
				}
				// Some other char
				else {
					*tVar++ = *c++;
				}
			} while (!eos);
			c++; // Skip the trainling quote...
			*tVar = (char)0;
			break;
		default: // Number
			iVar = va_arg(Entries, int*); // Get next one
			*iVar = atoi(c);
			while ((*c != 0) && (*c != ',')) {
				c++;
			}
			break;
		}
		if (*c == ',') { c++; }
	}

	va_end(Entries); // Clean up

	return(True);
}

// Get one line of the results
int sqlite3ResultCSV(char *Buffer, int Number, ...) {
	va_list Entries;
	int i = -1;
	char *c = Buffer;
	char *tVar;
	int eos;

	// Return False if there is an error message...
	if (sqlite3Error(Buffer)) { return(False); }
	// Seriously...
	if (Number < 0)           { return(False); }

	// Go the the entry we want
	// The code is very simliar to the sqlite3Count ...
	for (;i != Number;) {
		if (*c == 0) { return(False); }
		i++;
		if (i != Number) { c = c + strlen(c) +1; }
	}

	va_start(Entries,Number); // Get the parameter list

	// Parse the line noting that strings are in single quotes, numbers are not
	// And put into the parameters ...
	while(*c != 0) {
		tVar = va_arg(Entries, char*); // Get next one
		switch (*c) {
		case ',': // Empty value
			*tVar = 0;
			break;
		case '"': // Quoted value
			eos = False;
			c++; // Start of string's content
			do {
				// Check if double quote and if put one into the string
				if (*c == '"') {
					c++;
					if (*c == '"') {
						// Yep, a quote inside my string
						*tVar++ = *c++;
					}
					else {
						// A single quote and thus end of my string...
						c--;
						eos = True;
					}
				}
				// Some other char
				else {
					*tVar++ = *c++;
				}
			} while (!eos);
			c++; // Skip the trainling quote...
			*tVar = (char)0;
			break;
		default: // Unqoted value
			while ((*c != 0) && (*c != ',')) {
				*tVar++ = *c++;
			}
			*tVar = (char)0;
			break;
		}
		if (*c == ',') { c++; }
	}

	va_end(Entries); // Clean up

	return(True);
}



void SQLDisplay(char *SQLBuffer) {
	int i,r;

	// Clear my table
	for (i=0;i<MaxLines;i++) { TableNrC[i][0] = 0; TableName[i][0] = 0; }

	// Read all ... not quite
	strcpy(SQL,"Select nr,name FROM tabby");
	if (Filter[0] != 0) {
		strcat(SQL," WHERE name LIKE '");
		strcat(SQL,Filter);
		strcat(SQL,"%'");
	}
	strcat(SQL,";");
	//SQLBuffer = sqlite3(FileName,"Select nr,name FROM tabby;",SQLBuffer);
	SQLBuffer = sqlite3(FileName,SQL,SQLBuffer);

	// Oops
	if (sqlite3Error(SQLBuffer)) {
		strcpy(TableNrC[0],"Oops");
		strncpy(TableName[0],SQLBuffer,sizeof(TableName[0]));
	}
	else {
		r = sqlite3Count(SQLBuffer);
		for (i=0;(i<r) && (i<MaxLines);i++) {
			sqlite3Result(SQLBuffer,i,&TableNrI[i],(char*)&TableName[i]);
			sprintf((char*)&TableNrC[i],"%d",TableNrI[i]);
		}
		if (r > MaxLines) {
			strcpy(TableNrC[MaxLines-1],"Oops");
			strcpy(TableName[MaxLines-1],"... da is noch mehr");
		}
	}
	WimpRedrawAllIcons(MyMainWindow,MyMainWindowHandle);
}


void SQLUpdate(char *SQLBuffer) {

	NewNrI = atoi(NewNrC);

	// SELECT name FROM tabby WHERE nr = <Eingabewert>
	strcpy(SQL,"SELECT name FROM tabby WHERE nr = ");
	strcat(SQL,NewNrC);
	strcat(SQL,";");
	SQLBuffer = sqlite3(FileName,SQL,SQLBuffer);
	// Get old existing name value for the number  if found.
	if (!(sqlite3Result(SQLBuffer,0,&OldName))) { OldName[0] = 0; }

	if (NewName[0] == 0) {
		// Delete since no name value given
		strcpy(SQL,"DELETE FROM tabby WHERE nr = ");
		strcat(SQL,NewNrC);
		strcat(SQL,";");
		SQLBuffer = sqlite3(FileName,SQL,SQLBuffer);
		}
	else {
		// Insert or Update
		if ((OldName[0] == 0)) {
			strcpy(SQL,"INSERT INTO tabby (nr,name) VALUES(");
			strcat(SQL,NewNrC);
			strcat(SQL,",'");
			strcat(SQL,NewName);
			strcat(SQL,"');");
		}
		else {
			strcpy(SQL,"UPDATE tabby SET name='");
			strcat(SQL,NewName);
			strcat(SQL,"' WHERE nr = ");
			strcat(SQL,NewNrC);
			strcat(SQL,";");
		}
		SQLBuffer = sqlite3(FileName,SQL,SQLBuffer);
	}


	SQLDisplay(SQLBuffer);
}

void ManageMyWindow(char What) {
	switch (What) {
	case 'O': // Open directly
		BuggyMessage("O");
		MyMainWindowHandle = WimpOpenNormalWindow(MyMainWindow,MyMainWindowHandle,True);
		MyPaneWindowHandle = WimpOpenPaneWindowTLO(MyPaneWindow,MyPaneWindowHandle,MyMainWindowHandle);
		MyPartWindowHandle = WimpOpenPaneWindow(MyPartWindow,MyPartWindowHandle,MyMainWindowHandle,XY("S"),XY("S2T"),XY("S2R"),XY("S3TR"));
		break;
	case 'P': // Open in WimpPoll
		BuggyMessage("P");
		WimpOpenWindow();
		MyPaneWindowHandle = WimpOpenPaneWindowTLO(MyPaneWindow,MyPaneWindowHandle,MyMainWindowHandle);
		MyPartWindowHandle = WimpOpenPaneWindow(MyPartWindow,MyPartWindowHandle,MyMainWindowHandle,XY("S"),XY("S2T"),XY("S2R"),XY("S3TR"));
		break;
	case 'C': // Close
		BuggyMessage("C");
		WimpCloseWindow(MyMainWindowHandle);
		WimpCloseWindow(MyPaneWindowHandle);
		WimpCloseWindow(MyPartWindowHandle);
		break;
	}
}


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

	int ReasonCode;

	BuggyClear;

	WimpInitialise();
	MyBarIcon = WimpCreateIconBarIcon("Switcher",IconBar_IconRight);

	// Load Messages
	MessagesLoad("<Obey$Dir>.Messages");


	// The classic infobox
	MyInfoWindow = CreateBasicWindow(">I_TITLE",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_QUIT",NULL);
	MyBarMenu->MenuItem[0].MenuLink.Window  = WimpCreateWindow(MyInfoWindow);
	int MenuEntry_Quit = 1;

	// Window
	MyMainWindow = CreateBigWindow((char*)MyTaskName,WindowFlags_AllTools,1,800,800,400,400);
	FillEditIconXY(MyMainWindow,0,">W_BLA",0,IconValidation_Text,0,"S",0,"S",0,100);

	// The Pane
	MyPaneWindow = CreateBasicWindow("",WindowFlags_Pane,3,XY("S2T"),XY("S4T3"));
	FillOnOffIconXY(MyPaneWindow,0,IconValidation_Radio,0,"S",0,"S",  0);
	FillOnOffIconXY(MyPaneWindow,1,IconValidation_Option,0,"S",0,"STS",0);
	FillEditIconXY(MyPaneWindow,2,"",0,IconValidation_Text,0,"S",0,"STSTS",0,44);


	// The Part
	MyPartWindow = CreateBasicWindow("",WindowFlags_PaneScroll,100,1000,1000);
	int i,j;
	char t[100][3];
	for (i=0;i<10;i++) {
		for (j=0;j<10;j++) {
			sprintf((char*)&t[i+10*j],"%d%d",i,j);
			FillTextIconXY(MyPartWindow,i+10*j,IconFlags_TextL,(char*)&t[i+10*j],IconValidation_Flat,"S",48*i,"S",90*j,88);
		}
	}


	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 MouseButtonLeft:
					ManageMyWindow('O');
					break;
				case MouseButtonMiddle: // Menu click
					OpenMenu(MyBarMenu);
					break;
				case MouseButtonRight:
					ManageMyWindow('C');
				}
			}
			break;

		// Key press
		case ReasonCode_KeyPress:
			//BuggyBuffI("Key",WimpPollBlock,12);
			break;

		// 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");
			if (WimpPollBlock->OpenWindow.WindowHandle == MyMainWindowHandle) {
				ManageMyWindow('P');
			}
			else {
				WimpOpenWindow();
			}
			break;
		case ReasonCode_CloseWindow:
			//BuggyMessage("ReasonCode_CloseWindow");
			if (WimpPollBlock->OpenWindow.WindowHandle == MyMainWindowHandle) {
				ManageMyWindow('C');
			}
			else {
				WimpCloseWindow(Window_WimpBlock);
			}
			break;

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

}

