-- SExecOpsImpl.mesa; Edited by McGregor on 14-Apr-82  9:43:14

DIRECTORY
  ConvertUnsafe USING [ToRope],
  CVExecutive USING [AddCommand, CommandProc, GetToken,
  	UserName, UserPassword],
  Directory USING [DeleteFile, Error, ignore, Lookup, GetProps],
  ExecOps USING [Outcome],	-- [Igor]<PreCascade>Utilities>
  Feedback USING [BeginItemProc, CreateProc, DestroyProc, FinishItemProc,
  	NoteProgressProc, Procs],	-- [Igor]<PreCascade>Compiler>
  File USING [Capability],
  PrincOps,     -- <APilot>Mesa>Public>
  Rope USING [Compare, Concat, Ref, Int, Size, Substr, ToString],
  Runtime USING [ConfigError, IsBound, RunConfig],
  SExecOps,
  TemporarySpecialExecOps USING [BindUsingFeedback,
  	CompileUsingFeedback],	-- [Igor]<PreCascade>Compiler>
  TypeScript USING [CharProc, GetLine, PutChar, PutRope, TS],
  UserTerminal USING [BlinkDisplay],
  ViewerOps USING [CreateViewer, DestroyViewer, FindViewer, OpenViewer,
  	RestoreViewer, SetNewFile],
  ViewerClasses USING [Viewer],
  VirtualDesktops USING [SetName],
  WindowManager USING [UnWaitCursor, WaitCursor];

SExecOpsImpl: PROGRAM

IMPORTS ConvertUnsafe, CVExecutive, Directory,
	Rope, Runtime, SExecOps, TemporarySpecialExecOps,
	TypeScript, UserTerminal, ViewerOps, VirtualDesktops, WindowManager
EXPORTS SExecOps =

BEGIN OPEN TypeScript, ViewerClasses;

LoadAndGo: PROC [file: LONG STRING] RETURNS [name, error: Rope.Ref] = BEGIN
	ENABLE BEGIN
	    Runtime.ConfigError => {SELECT type FROM
		    invalidConfig	=> error ← "Illegal bcd format: ";
		    versionMismatch	=> error ← "Version mismatch for: ";
		    ENDCASE		=> error ← "RunConfig failed for: ";
		 CONTINUE};
	    Directory.Error =>
		{SELECT type FROM
		    invalidFileName	=> error ← "Illegal file name: ";
		    fileNotFound	=> error ← "Couldn't find a runnable file named: ";
		    ENDCASE		=> error ← "Lookup failed on: ";
		 CONTINUE};
	    END;
	f: File.Capability;
	f ← Directory.Lookup[file];
	IF error=NIL THEN Runtime.RunConfig[f, 1
		! ABORTED => {error ← "Execution Aborted!"; CONTINUE}];
	IF error=NIL THEN [] ← Directory.GetProps[f, file];
	IF error=NIL THEN name ← LOOPHOLE[file]
	END;

Run: PUBLIC CVExecutive.CommandProc = BEGIN
	bug: BOOLEAN ← FALSE;
	error: Rope.Ref;
	directoryName: Rope.Ref ← param;
	length: Rope.Int ← Rope.Size[param];
	WindowManager.WaitCursor[];
	IF length < 5 OR Rope.Compare[Rope.Substr[param,length-4,4],".bcd",FALSE] # 0 
	THEN directoryName ← Rope.Concat[param,".bcd"];
	[directoryName, error] ← LoadAndGo[LOOPHOLE[Rope.ToString[directoryName]]
		! ANY => {bug ← TRUE; CONTINUE}];
	IF error#NIL THEN PutRope[ts, error]
	ELSE IF bug THEN PutRope[ts, "UNKNOWN ERROR -- Couldn't run: "]
	ELSE PutRope[ts, "Loaded and ran: "];
	PutRope[ts, IF error=NIL THEN directoryName ELSE param];
	WindowManager.UnWaitCursor[];
	END;

DirectoryName: PROC [name: LONG STRING] RETURNS [Rope.Ref] = BEGIN
	f: File.Capability ← Directory.Lookup[fileName: name, permissions: Directory.ignore];
	[] ← Directory.GetProps[f, name];
	RETURN [LOOPHOLE[name]]
	END;

CheckForFile: PUBLIC PROC [file: Rope.Ref] RETURNS [found: BOOLEAN] = BEGIN
	fName: LONG STRING ← LOOPHOLE[Rope.ToString[file]];
	found ← TRUE;
	[] ← Directory.Lookup[fileName: fName, permissions: Directory.ignore
		! Directory.Error => {found ← FALSE; CONTINUE}];
	END;

New: PUBLIC CVExecutive.CommandProc = BEGIN
	viewer: ViewerClasses.Viewer;
	new: BOOLEAN ← FALSE;
	directoryName: Rope.Ref;
	WindowManager.WaitCursor[];
	directoryName ← DirectoryName[LOOPHOLE[Rope.ToString[param]]
		! ANY => {directoryName ← param; new ← TRUE; CONTINUE}];
	viewer ← ViewerOps.CreateViewer[flavor: $Text, name: directoryName,
		file: directoryName, iconic: FALSE, attributes: left];
	PutRope[ts, "Created Viewer: "];
	PutRope[ts, directoryName];
	IF new THEN ViewerOps.SetNewFile[viewer];
	WindowManager.UnWaitCursor[];
	END;

Old: PUBLIC CVExecutive.CommandProc = BEGIN
	found: BOOLEAN;
	IF (found ← CheckForFile[Rope.Concat[param, ".mesa"]]) THEN
		param ← Rope.Concat[param, ".mesa"]
	ELSE found ← CheckForFile[param];
	IF found THEN New[ts, param] ELSE BEGIN
		PutRope[ts, "Viewer file not found: "];
		PutRope[ts, param];
		END;
	END;

cr: Rope.Ref ← "
";	-- GDF'ing compiler needs a CR at the end of a command

CBCreate: Feedback.CreateProc = BEGIN
	--PutRope[gts, ConvertUnsafe.ToRope[system]];
	RETURN[NIL];
	END;

CBDestroy: Feedback.DestroyProc = BEGIN
	PutRope[gts, ConvertUnsafe.ToRope[trailer]];
	cbBusy ← FALSE;
	END;

CBBeginItem: Feedback.BeginItemProc = BEGIN
	PutRope[gts, ConvertUnsafe.ToRope[item]];
	END;

CBNoteProgress: Feedback.NoteProgressProc = BEGIN
	PutRope[gts, " ."];
	END;

CBFinishItem: Feedback.FinishItemProc = BEGIN
	--PutRope[gts, OutComesRope[outcome]];
	PutChar[gts, ' ];
	PutRope[gts, ConvertUnsafe.ToRope[trailer]];
	PutChar[gts, 15C];
	END;

cbProcs: Feedback.Procs ← [CBCreate, CBDestroy, CBBeginItem,
	CBNoteProgress, CBFinishItem];

cbBusy: BOOLEAN ← FALSE;
cmdText: REF StringBody;
cmd: LONG POINTER TO PACKED ARRAY [0..0) OF CHARACTER;
gts: TypeScript.TS;

Bind: PUBLIC CVExecutive.CommandProc = BEGIN
	outCome: ExecOps.Outcome;
	log: ViewerClasses.Viewer;
	IF cbBusy THEN BEGIN
		PutRope[ts, "Binder or Compiler is busy, try again later!"];
		RETURN;
		END;
	cmdText ← LOOPHOLE[Rope.ToString[Rope.Concat[param, cr]]];
	cmd ← LOOPHOLE[@(cmdText.text)];
	cbBusy ← TRUE;
	gts ← ts;
	IF ~Runtime.IsBound[TemporarySpecialExecOps.BindUsingFeedback] THEN
		BEGIN
		PutRope[ts, "Loading Binder.bcd...
"];
		Runtime.RunConfig[Directory.Lookup["Binder.bcd"], 1];
		END;
	outCome ← TemporarySpecialExecOps.BindUsingFeedback[cmd, @cbProcs];
	log ← ViewerOps.FindViewer["Binder.log"];
	IF log#NIL THEN BEGIN
		IF outCome=ok THEN ViewerOps.DestroyViewer[log]
		ELSE BEGIN
			ViewerOps.RestoreViewer[log];
			IF log.iconic THEN ViewerOps.OpenViewer[log];
			END;
		END
	ELSE IF outCome#ok THEN {PutChar[ts, 15C]; Old[ts, "Binder.log"]};
	END;

Compile: PUBLIC CVExecutive.CommandProc = BEGIN
	outCome: ExecOps.Outcome;
	log: ViewerClasses.Viewer;
	IF cbBusy THEN BEGIN
		PutRope[ts, "Compiler or Binder is busy, try again later!"];
		RETURN;
		END;
	cmdText ← LOOPHOLE[Rope.ToString[Rope.Concat[param, cr]]];
	cmd ← LOOPHOLE[@(cmdText.text)];
	cbBusy ← TRUE;
	gts ← ts;
	IF ~Runtime.IsBound[TemporarySpecialExecOps.CompileUsingFeedback] THEN
		BEGIN
		PutRope[ts, "Loading Compiler.bcd...
"];
		Runtime.RunConfig[Directory.Lookup["Compiler.bcd"], 1];
		END;
	outCome ← TemporarySpecialExecOps.CompileUsingFeedback[cmd, @cbProcs];
	log ← ViewerOps.FindViewer["Compiler.log"];
	IF log#NIL THEN BEGIN
		IF outCome=ok THEN ViewerOps.DestroyViewer[log]
		ELSE BEGIN
			ViewerOps.RestoreViewer[log];
			IF log.iconic THEN ViewerOps.OpenViewer[log];
			END;
		END
	ELSE IF outCome#ok THEN {PutChar[ts, 15C]; Old[ts, "Compiler.log"]};
	END;

DeleteFiles: PUBLIC CVExecutive.CommandProc = BEGIN
	offset: LONG INTEGER ← 0;
	file: Rope.Ref;
	first: BOOLEAN ← TRUE;
	Delete: PROC [file: Rope.Ref] = BEGIN
		failed: BOOLEAN ← FALSE;
		Directory.DeleteFile[LOOPHOLE[Rope.ToString[file]]
			! Directory.Error => {failed ← TRUE; CONTINUE}];
		PutRope[ts, IF failed THEN "File not found: " ELSE "Deleted: "];
		PutRope[ts, file]
		END;
	DO [file, offset] ← CVExecutive.GetToken[param, offset];
		IF Rope.Size[file]=0 THEN EXIT;
		IF first THEN first ← FALSE ELSE PutChar[ts, 15C];
		Delete[file];
		ENDLOOP;
	END;

DoOpen: PROC [file: Rope.Ref] = BEGIN
	viewer: Viewer ← ViewerOps.FindViewer[file];
	new: BOOLEAN ← FALSE;
	directoryName: Rope.Ref;
	IF viewer#NIL THEN {IF viewer.iconic THEN ViewerOps.OpenViewer[viewer]; RETURN};
	WindowManager.WaitCursor[];
	directoryName ← DirectoryName[LOOPHOLE[Rope.ToString[file]]
		! ANY => {directoryName ← file; new ← TRUE; CONTINUE}];
	IF new THEN {UserTerminal.BlinkDisplay[]; WindowManager.UnWaitCursor[]; RETURN};
	viewer ← ViewerOps.CreateViewer[flavor: $Text, name: directoryName,
		file: directoryName, iconic: FALSE, attributes: left];
	WindowManager.UnWaitCursor[];
	END;

Login: CVExecutive.CommandProc = BEGIN
	UserCharProc: TypeScript.CharProc = BEGIN
		SELECT char FROM
			15C, ' , 33C	=> RETURN[TRUE, TRUE];
			177C		=> RETURN[FALSE, FALSE];
			ENDCASE	=> RETURN[TRUE, FALSE];
		END;
	PswdCharProc: TypeScript.CharProc = BEGIN
		SELECT char FROM
			1C, 27C	=> RETURN[TRUE, FALSE];
			177C		=> RETURN[FALSE, FALSE];
			15C, ' , 33C	=> RETURN[FALSE, TRUE];
			ENDCASE	=> {TypeScript.PutChar[ts, '*]; RETURN[FALSE, FALSE]};
		END;
	PutRope[ts, "User: "];
	IF CVExecutive.UserName#NIL THEN ts.class.notify[ts, LIST[CVExecutive.UserName]];
	CVExecutive.UserName ← TypeScript.GetLine[ts, FALSE, UserCharProc];
	PutRope[ts, "Password: "];
	CVExecutive.UserPassword ← TypeScript.GetLine[ts, FALSE, PswdCharProc];
	END;


Name: CVExecutive.CommandProc = BEGIN
	VirtualDesktops.SetName[param];
	PutRope[ts, "This virtual desktop has been named: "];
	PutRope[ts, param];
	END;

CVExecutive.AddCommand["?", SExecOps.Help, "Display this message."];
CVExecutive.AddCommand["Bind", Bind, "Bind a list of configurations."];
CVExecutive.AddCommand["Compile", Compile, "Compile a list of modules."];
CVExecutive.AddCommand["Delete", DeleteFiles, "Delete a list of files."];
CVExecutive.AddCommand["Login", Login, "Supply user name and password."];
CVExecutive.AddCommand["Name", Name, "Specify a new name for current virtual desktop."];
CVExecutive.AddCommand["New", New, "Create a viewer (possibly new file)."];
CVExecutive.AddCommand["Old", Old, "Create a viewer (old file only)."];
CVExecutive.AddCommand["Run", Run, "Load and Run the named program."];

END.