#include <stdio.h>
#include <stdlib.h>
#include <string.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_Null;
int WimpPollWait = 200;
t_WimpPollBlock WimpPollBlockStorage;
t_WimpPollBlock *WimpPollBlock;
t_TaskHandle MyTaskHandle = 0;

const char MyTaskName[] = "FileWatch";
const char MyVersion[]  = "Version 1.00";

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

// FileView variables
char FileName[256] = "- type a path or drop a file here -";
char InfoLine[100] = "- no file loaded -";
#define LineMax 20 // Icons 0-2 are other stuff, as of 3 are the lines...
#define IconLoad 0
#define IconName 1
#define IconInfo 2
#define IconTail 3
char *Lines[LineMax];
unsigned FileTimestamp = 0;

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

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

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

	//BuggyRegs(AbortMessage,4);

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

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

	return(OSError);
}


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

// 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 *CreateSimpleMenu(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
	strncpy(MenuHeader->Title.Text,Title,sizeof(MenuHeader->Title));
	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;
		MenuItem->IconFlags = IconFlags_TextWhiteDirect;
		strncpy(MenuItem->IconData.IconText,Entry,sizeof(MenuItem->IconData.IconText));
		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

	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_WindowTitleIndirect;
	WindowHeader->WorkareaButtonType = 0; // Ignore all clicks
	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);
}

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


// Fill text icon
void FillTextIcon(t_Icon *Icon, char* Text, int White, 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;
	if (White) { Icon->IconFlags = IconFlags_TextWhiteIndirect; }
	else       { Icon->IconFlags = IconFlags_TextTransparentIndirect; }
	Icon->IconData.IconTextIndirect.Text = Text;
	Icon->IconData.IconTextIndirect.Validation = NULL;
	Icon->IconData.IconTextIndirect.Length = strlen(Text);
}

// Fill text icon
void FillEditIcon(t_Icon *Icon, char* Text, int Length, 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 = IconFlags_TextEditIndirect;
	Icon->IconData.IconTextIndirect.Text = Text;
	Icon->IconData.IconTextIndirect.Validation = NULL;
	Icon->IconData.IconTextIndirect.Length = Length;
}

void FillButtonIcon(t_Icon *Icon, char* Text, 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 = IconFlags_ButtonSimpleIndirect;
	Icon->IconData.IconTextIndirect.Text = Text;
	Icon->IconData.IconTextIndirect.Validation = IconValidation_Button;
	Icon->IconData.IconTextIndirect.Length = strlen(Text);
}

void FillOnOffIcon(t_Icon *Icon, char* Buttons, int X, int Y) {
	Icon->BoundingBox.MinX = X;
	Icon->BoundingBox.MinY = -Y-44;
	Icon->BoundingBox.MaxX = X+44;
	Icon->BoundingBox.MaxY = -Y;
	Icon->IconFlags = IconFlags_OnOff;
	Icon->IconData.IconTextIndirect.Text = Icon_NoText;
	Icon->IconData.IconTextIndirect.Validation = Buttons;
	Icon->IconData.IconTextIndirect.Length = 1;
	//BuggyIcon("R",Icon);
}

// 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);
	//BuggyBuffI("Open",&(WimpPollBlock->OpenWindow.Visible),sizeof(t_WindowHeader)/4);
	SWI(Wimp_OpenWindow);
}

void RedrawContent(t_WindowHandle Window, int X, int Y) {
	int i;
	int PosX, PosY;
	if (Window == MyMainWindowHandle)  {
		PosX = X+20;
		PosY = Y-20-44-20-44-20;
		for (i=0;i<LineMax;i++) {
			if (Lines[i] != NULL) {
				SWIRegs.r[0] = 4;
				SWIRegs.r[1] = PosX;
				SWIRegs.r[2] = PosY;
				SWI(OS_Plot);
				printf("%s",Lines[i]);
				PosY -= 44;
			}
		}
	}
}


// Wimp redraw window
void WimpRedrawWindow(void) {
	int Looping;
	int OriginX, OriginY;
	SWIRegs.r[1] = (int)(WimpPollBlock);
	// Note that Wimp_RedrawWindow implicitly calls the first Wimp_GetRectangle for me...
	SWI(Wimp_RedrawWindow);
	Looping = SWIRegs.r[0];
	while(Looping != 0) {
		// Get On-Screen position of top left corner of my work area (MinX,MaxY)
		OriginX = WimpPollBlock->RedrawWindow.Visible.MinX - WimpPollBlock->RedrawWindow.ScrollX;
		OriginY = WimpPollBlock->RedrawWindow.Visible.MaxY - WimpPollBlock->RedrawWindow.ScrollY;
		RedrawContent(WimpPollBlock->RedrawWindow.WindowHandle,OriginX,OriginY);
		SWIRegs.r[1] = (int)(WimpPollBlock);
		SWI(Wimp_GetRectangle);
		Looping = SWIRegs.r[0];
	}
}

void WimpUpdateWindow(t_Window *Window, t_WindowHandle WindowHandle) {
	int Looping;
	int OriginX, OriginY;
	WimpPollBlock->RedrawWindow.WindowHandle = (int)WindowHandle;
	WimpPollBlock->RedrawWindow.Visible.MinX = Window->WindowHeader.Workarea.MinX;
	WimpPollBlock->RedrawWindow.Visible.MinY = Window->WindowHeader.Workarea.MinY;
	WimpPollBlock->RedrawWindow.Visible.MaxX = Window->WindowHeader.Workarea.MaxX;
	WimpPollBlock->RedrawWindow.Visible.MaxY = Window->WindowHeader.Workarea.MaxY;
	SWIRegs.r[1] = (int)(WimpPollBlock);
	// Note that Wimp_RedrawWindow implicitly calls the first Wimp_GetRectangle for me...
	SWI(Wimp_RedrawWindow);
	Looping = SWIRegs.r[0];
	while(Looping != 0) {
		// Get On-Screen position of top left corner of my work area (MinX,MaxY)
		OriginX = WimpPollBlock->RedrawWindow.Visible.MinX - WimpPollBlock->RedrawWindow.ScrollX;
		OriginY = WimpPollBlock->RedrawWindow.Visible.MaxY - WimpPollBlock->RedrawWindow.ScrollY;
		SWIRegs.r[0] = 12; SWI(OS_WriteC);
		RedrawContent(WimpPollBlock->RedrawWindow.WindowHandle,OriginX,OriginY);
		SWIRegs.r[1] = (int)(WimpPollBlock);
		SWI(Wimp_GetRectangle);
		Looping = SWIRegs.r[0];
	}
}

void WimpRedrawWholeWindow(t_Window *Window, t_WindowHandle WindowHandle) {
	SWIRegs.r[0] = (int)WindowHandle;
	SWIRegs.r[1] = Window->WindowHeader.Workarea.MinX;
	SWIRegs.r[2] = Window->WindowHeader.Workarea.MinY;
	SWIRegs.r[3] = Window->WindowHeader.Workarea.MaxX;
	SWIRegs.r[4] = Window->WindowHeader.Workarea.MaxY;
	SWI(Wimp_ForceRedraw);
}

// 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]);
	//BuggyInt("X",X); BuggyInt("Y",Y);
	// 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;
	//BuggyBuffI("Center",Box,4);

}

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


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 & IconFlag_Mask_Selected) == 0 ? False : True);
}

unsigned GetFileExec(char *File) {
	SWIRegs.r[0] = 17;
	SWIRegs.r[1] = (int)(File);
	if (SWIX(OS_File) != NULL) { return(0); }
	if (SWIRegs.r[0] == 0) { return(0); }
	return(SWIRegs.r[3]);
}

void LoadFile(int TailOrNot) {
	FILE *FileHandle;
	char *FileBuffer = NULL;
	unsigned FileSize;
	char *c;
	int i;
	unsigned e;

	for (i=0;i<LineMax;i++) { Lines[i] = NULL; }
	FileHandle = fopen(FileName, "r");
	if (!FileHandle) {
		strcpy(InfoLine,"Sorry, file not found");
		FileTimestamp = 0;
	}
	else {
		fseek(FileHandle,0,SEEK_END);
		FileSize = (unsigned)ftell(FileHandle);
		//BuggyInt(".",(int)FileSize);
		rewind(FileHandle);
		if (FileBuffer != NULL) free(FileBuffer);
		FileBuffer = malloc(FileSize+2);
		if (!FileBuffer) {
			fclose(FileHandle);
			strcpy(InfoLine,"Sorry, file too big");
			FileTimestamp = 0;
		}
		else {
			fread(FileBuffer+1,1,FileSize,FileHandle);
			e = GetFileExec((char*)&FileName);
			FileSize++;
			fclose(FileHandle);
			FileBuffer[0] = (char)0;
			FileBuffer[FileSize] = (char)0;
			if (FileTimestamp == e) { strcpy(InfoLine,"File unchanged but reloaded"); }
			else                    { strcpy(InfoLine,"File loaded"); }
			FileTimestamp = e;
			// drop control characters except for tab
			c = FileBuffer;
			for (i=0;i<FileSize;i++) {
				if (*c < ' ') { *c = (*c == (char)9) ? ' ' : (char)0; }
				c++;
			}
			// get last or first few lines
			if (TailOrNot) {
				c = FileBuffer+FileSize;
				for (i=LineMax-1;i>=0;i--) {
					// skip trailing zeroes
					while (*c == (char)0) {c--;}
					if (c <= FileBuffer) break; // done
					// get start of line
					while (*c != (char)0) {c--;}
					if (c <= FileBuffer) break; // done
				}
			}
			else {
				c = FileBuffer;
			}
			for (i=0;i<LineMax;i++) {
				// Skip leading zeroes
				while (*c == (char)0) {c++;}
				if (c >= FileBuffer+FileSize) break; // done
				// take the line
				Lines[i] = c;
				//BuggyText("LoadFile",Lines[i]);
				// go to end of the line
				c = strchr(c,(char)0); // since I added one a the end after loading I get it...
				if (c >= FileBuffer+FileSize) break; // done
			}
			//free(FileBuffer);
		}
	}
	WimpRedrawWholeWindow(MyMainWindow,MyMainWindowHandle);
}

// Send an Ack-Reply - the original message being in the WimpPollBlock!
void WimpMessageAck(int MessageCode) {
	WimpPollBlock->UserMessage.MessageCode = MessageCode;
	WimpPollBlock->UserMessage.YourRef = WimpPollBlock->UserMessage.MyRef;
	SWIRegs.r[0] = ReasonCode_UserMessageAcknowledge;
	SWIRegs.r[1] = (int)(WimpPollBlock);
	SWIRegs.r[2] = WimpPollBlock->UserMessage.SenderHandle;
	SWI(Wimp_SendMessage);
}

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

	int ReasonCode;
	int i;

	BuggyClear;

	WimpInitialise();
	WimpAddRemoveMessages(MessageCode_DataLoad);

	MyBarIcon = WimpCreateIconBarIcon("Switcher",IconBar_IconRight);

	// The classic infobox
	MyInfoWindow = CreateBasicWindow("Ego",WindowFlags_InfoWindow,2,323,20+44+20+44+20);
	FillButtonIcon(&(MyInfoWindow->WindowIcon[0]),(char*)MyTaskName,20,20+44+20,323-20-20,44);
	FillEditIcon(&(MyInfoWindow->WindowIcon[1]),(char*)MyVersion,256,20,20,323-20-20,44);

	// A simple menu with just Info and Quit
	MyBarMenu = CreateSimpleMenu((char*)MyTaskName,"Ego","Tsch",NULL);
	MyBarMenu->MenuItem[0].MenuLink.Window  = WimpCreateWindow(MyInfoWindow);

	// Window from bottom: Space - LineMax Text - Space - Info - Space - Button/Filename - Space:
	MyMainWindow = CreateBigWindow((char*)MyTaskName,WindowFlags_AllToolsWindowRedraw,4,1200,20+44+20+44+20+LineMax*44+20,600,200);
	FillButtonIcon(&(MyMainWindow->WindowIcon[IconLoad]),"Load",20,20,100,44);
	FillOnOffIcon(&(MyMainWindow->WindowIcon[IconTail]),IconValidation_Option,20+100+20,20);
	FillEditIcon(&(MyMainWindow->WindowIcon[IconName]),(char*)(&FileName),255,20+100+20+44+20,20,1200-100-44-20-20-20-20,44);
	FillTextIcon(&(MyMainWindow->WindowIcon[IconInfo]),(char*)(&InfoLine),False,20,20+44+20,1200-20-20,44);
	for (i=0;i<LineMax;i++) { Lines[i] = NULL; }

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

		// Handle the request
		switch(ReasonCode) {
		// Null
		case ReasonCode_Null:
			if (MyMainWindowHandle != -1) {
				t_WimpGetWindowStateBlock Buf;
				Buf.WindowHandle = MyMainWindowHandle;
				SWIRegs.r[1] = (int)&Buf;
				SWI(Wimp_GetWindowState);
				if ((Buf.WindowFlags & WindowFlags_Mask_Open) != 0) {
					int e;
					e = GetFileExec((char*)&FileName);
					if (e != FileTimestamp) {
						LoadFile(WimpGetIconState(MyMainWindowHandle,IconTail));
					}
				}
			}
			break;
		// Mouse click
		case ReasonCode_MouseClick:
			//BuggyMessage("ReasonCode_MouseClick");
			//BuggyBuffI("Poll",WimpPollBlock,12);
			// Iconbar icon
			if ((WimpPollBlock->MouseClick.WindowHandle == WindowIconbar) && (WimpPollBlock->MouseClick.IconHandle == MyBarIcon)) {
				switch(WimpPollBlock->MouseClick.Buttons) {
				case MouseButtonRight: // Kill my task - if Shift pressed
					if (KeyPressCheck(KeyShift)) { WimpCloseDown(); }
					break;
				case MouseButtonMiddle: // Menu click
					OpenMenu(MyBarMenu);
					break;
				case MouseButtonLeft:
					MyMainWindowHandle = WimpOpenNewWindow(MyMainWindow,MyMainWindowHandle,True);
				}
			}
			// Main Window Load button
			if ((WimpPollBlock->MouseClick.WindowHandle == MyMainWindowHandle) && (WimpPollBlock->MouseClick.IconHandle == IconLoad)) {
				LoadFile(WimpGetIconState(MyMainWindowHandle,IconTail));
			}
			// Main Window Tail button
			if ((WimpPollBlock->MouseClick.WindowHandle == MyMainWindowHandle) && (WimpPollBlock->MouseClick.IconHandle == IconTail)) {
				LoadFile(WimpGetIconState(MyMainWindowHandle,IconTail));
			}
			break;

		// Key press
		case ReasonCode_KeyPress:
			if ((WimpPollBlock->KeyPress.WindowHandle == MyMainWindowHandle) && (WimpPollBlock->KeyPress.IconHandle == IconName) && (WimpPollBlock->KeyPress.CharacterCode == 0x0d)) {
				LoadFile(WimpGetIconState(MyMainWindowHandle,IconTail));
			}
			break;

		// Menu selection
		case ReasonCode_MenuSelection:
			//BuggyMessage("ReasonCode_MenuSelection");
			switch(WimpPollBlock->MenuSelection.MenuItem[0]) {
			case 0: // Ego
				break;
			case 1: // Quit
				WimpCloseDown();
				break;
			}
			if (MouseButtonCheck(MouseButtonRight)) { OpenMenu(MyBarMenu); }

		// Window stuff
		case ReasonCode_RedrawWindow:
			//BuggyMessage("ReasonCode_RedrawWindow");
			WimpRedrawWindow();
			break;
		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("ReasonCode",ReasonCode);
			//BuggyBuffI("Poll",WimpPollBlock,20);
			if (WimpPollBlock->UserMessage.MessageCode == MessageCode_Quit) {
				 WimpCloseDown();
			}
			if (WimpPollBlock->UserMessage.MessageCode == MessageCode_DataLoad) {
			BuggyText("File",WimpPollBlock->UserMessage.MessageData.DataLoad.FileName);
				strncpy(FileName,WimpPollBlock->UserMessage.MessageData.DataLoad.FileName,255);
				LoadFile(WimpGetIconState(MyMainWindowHandle,IconTail));
				WimpMessageAck(MessageCode_DataLoadAck);
			}
			break;
		}
	}

}

