module CleanIDE;

import StdInt,StdString,StdClass,StdArray;
import deltaTimer;
from deltaWindow import DrawInActiveWindow;
from EdShift import shift_selection_right, shift_selection_left;

import	EdFileMenu, EdEditMenu, EdSearchMenu,  EdCommandsMenu, EdProjectMenu, EdOptionsMenu1,
		EdWindowsMenu, EdOptionsMenu2, EdSysOptions, EdProgramState, EdDraw, EdFiles,
		LinkOptionsDialogue, EdCleanSystem;

::	IOFunction *p	:== p -> *((IOState p) -> *(p, IOState p));

Start :: !* World -> * World;
Start world = world4;
 	where {
 	(fullApplicationPath, world0) =	accFiles GetFullApplicationPath world;
	(editor0,world1)		= accFiles (InitEditor fullApplicationPath) world0;
	(editor1,world2)		= accFiles (ReadDefaultSettings editor0) world1;
	(about_dialog,world3)	= accFiles (\f->MakeAboutDialog "Clean Programming Environment" f Help) world2;

	inistate			= {editor=editor1};
	about				= DialogSystem [about_dialog];
	(_,world4)	= StartIO [about, menus, timer : SystemDependentDevices] inistate
								SystemDependentInitialIO world3;

	menus=	MenuSystem (AddSysMenuItem MFreeID IFreeID [file, edit, search, commands, project, options, windows]);

	file=		PullDownMenu MFileID "File" Able
				[	MenuItem	INewID		"New..."				(Key 'N')	Able	New
				,	MenuItem	IOpenID		"Open..."				(Key 'O')	Able	Open
				,	MenuItem	ICloseID	"Close"					(Key 'W')	Unable	Close
				,	MenuSeparator
				,	MenuItem	IOpDefID	"Open Definition..."		(Key 'D')	Able	(OpenDefOrImp True False)
				,	MenuItem	IOpImpID	"Open Implementation..."	(Key 'I')	Able	(OpenDefOrImp False False)
				,	MenuItem	ISwapID		"Open Other"			(Key '/')	Unable	OpenOther
				,	MenuSeparator
				,	MenuItem	ISaveID		"Save"					(Key 'S')	Unable	Save
				,	MenuItem	ISavesID	"Save As..."			NoKey		Unable	SaveAs
				:	IfUnixSystem
						[	MenuItem	IReverID	"Revert"				NoKey		Unable	Revert
						,	MenuSeparator
						,	MenuItem	IQuitID		"Quit"					(Key 'Q')	Able	Quit
						]
						[	MenuItem	IPrintID	"Print"					(Key 'P')	Unable	Print
						,	MenuItem	IReverID	"Revert"				NoKey		Unable	Revert
						,	MenuSeparator
						,	MenuItem	IQuitID		"Quit"					(Key 'Q')	Able	Quit
						]
				];

	edit=		PullDownMenu MEditID "Edit" Able
				[	MenuItem	IUndoID		"Undo"					(Key 'Z')	Unable	Undo,
					MenuSeparator,
					MenuItem	ICutID		"Cut"					(Key 'X')	Unable	Cut,
					MenuItem	ICopyID		"Copy"					(Key 'C')	Unable	Copy,
					MenuItem	IPasteID	"Paste"					(Key 'V')	Unable	Paste,
					MenuItem	IClearID	"Clear"					NoKey		Unable	Clear,
					MenuSeparator,
					MenuItem	IShiftLeftID	"Shift Left"		(Key '[')	Unable	shift_selection_left,
					MenuItem	IShiftRightID	"Shift Right"		(Key ']')	Unable	shift_selection_right,
					MenuItem	IBalanID		"Balance"			(Key 'B')	Unable	Balance,
					MenuItem	ISelecID		"Select All"		(Key 'A')	Unable	SelectAll,
					MenuSeparator,
					MenuItem 	IFormaID	"Format..."				(Key 'J')	Unable	Format
				];

	search=	PullDownMenu MSearcID "Search" Able
				[	MenuItem	IFindID		"Find..."				(Key 'F')	Unable	Find,
					MenuItem	IFindNID	"Find Next"				(Key 'G')	Unable	(ShiftKeyModifiedFunction FindNext),
					MenuItem	IFindSID	"Find Selection"		(Key 'H')	Unable	(ShiftKeyModifiedFunction FindSelection),
					MenuItem	IReplaID	"Replace & Find"		(Key 'T')	Unable	(ShiftKeyModifiedFunction ReplaceAndFind),
					MenuSeparator,
					MenuItem	IFindEID	"Find Error"			(Key 'E')	Unable	(ShiftKeyModifiedFunction FindError),
					MenuItem	IFindIdID	"Find Def & Imp"		(Key '=')	Unable	FindIdentifier,
					MenuItem 	IFindDID	"Find Definition"		(Key 'L')	Unable	(FindDefOrImp True),
					MenuItem	IFindIID	"Find Implementation"	(Key 'M')	Unable	(FindDefOrImp False),
					MenuSeparator,
					MenuItem	IGotoCID	"Goto Cursor"			NoKey		Unable	GotoCursor,
					MenuItem	IGotoLID	"Goto Line..."			NoKey		Unable	GotoLine
				];

	commands=	PullDownMenu MCommaID "Commands" Able
				[	MenuItem	ICompiID	"Compile"				(Key 'K')	Unable	Compiler,
					MenuItem	ICheckID	"Check"					(Key 'Y')	Unable	CheckSyntax,
					MenuItem	IGenerID	"Generate Assembly"		NoKey		Unable	GenerateAssembly,
					MenuSeparator,
					MenuItem	IBriUDID	"Bring Up To Date"		(Key 'U')	Unable	BringUpToDate,
					MenuItem	IExecuID	"Run"					(Key 'R')	Unable	Run
				];

	project=	PullDownMenu MProjeID "Project" Able
				[	MenuItem	INewPrID	"New Project"			NoKey		Unable	NewProject,
					MenuItem	IOpePrID	"Open Project..."		NoKey		Able	OpenProject,
					MenuItem	ISetPrID	"Set Main Module"		NoKey		Unable	SetProject,
					MenuItem	ICloPrID	"Close Project"			NoKey		Unable	CloseProject,
					MenuSeparator,
					MenuItemGroup IWinPrjID	[]
				];

	options=	PullDownMenu MOptioID "Options" Able
	        	[	MenuItem 	ICleanID	"Clean Compiler..."		NoKey		Able	CCompiler,
	        		MenuItem	ICodeGID	"Code Generator..."		NoKey		Able	CodeGenerator,
	        		MenuItem	ILinkOptionsID	"Link Options..."	NoKey		Unable	LinkOptionsDialogue,
	        		MenuItem	IAppliID	"Application..."		NoKey		Able	Application,
	        		MenuItem	IProjeID	"Project Manager..."	NoKey		Able	ProjectManager,
	        		MenuSeparator,
	        		MenuItem	IPathsID	"Paths..."				NoKey		Able	Paths
	        	];

	windows=	PullDownMenu MWindoID "Windows" Able
				[	MenuItem	INextWID	"Next Window"			(Key '\\')	Unable	NextWindow,
					MenuItem	IShowCID	"Show Clipboard"		NoKey		Able	ShowClipboard,
					MenuItem	IHelpID		"Help..."				NoKey		Able	Help,
					MenuSeparator,
					MenuItem	ISaveaID	"Save All"				NoKey		Unable	SaveAll,
					MenuItem	IClosaID	"Close All"				NoKey		Unable	CloseAll,
					MenuSeparator,
					MenuItemGroup IWindoID []
				];

	timer= 	TimerSystem [Timer TimerID Unable BlinkRate BlinkCursor];
	};

ShiftKeyModifiedFunction :: (Bool -> IOFunction *p) *p (IOState *p) -> (*p, IOState *p);
ShiftKeyModifiedFunction f programState ioState
	#	(shiftKeyIsDown, ioState)
			=	ShiftKeyIsDown ioState
	=	f shiftKeyIsDown programState ioState;

BlinkCursor	:: !TimerState !ProgState !IO -> ProgIO;
BlinkCursor state prog=:{editor=ed=:{editwindows}} io
	| blink > 0
		= ({prog & editor={ed & editwindows=editwindows`}},SetTimerInterval TimerID blink io2);
		{
			editwindows`	= SetFrontWindow front` editwindows;
			front`			= {front & wtext={front.wtext & cursorpos={cursorpos & vis=not cursorpos.vis}}};
		}
		= (prog, CloseTimer TimerID io2);
	where {
		(_,front)	= GetFrontWindow editwindows;
		cursorpos	= front.wtext.cursorpos;
		metrics		= front.wformat.metrics;
		(blink,io2)	= GetTimerBlinkInterval (
						DrawInActiveWindow [DrawCursor cursorpos (metrics.ascent+metrics.descent) metrics.lead] io);
	}
