-- ModelImpl.mesa
-- last edit by Schmidt, January 6, 1983 2:23 pm
-- last edit by Satterthwaite, March 8, 1983 10:56 am
-- main program for the system modeller

-- this is the top-level command module for the modeller
-- it provides an interface to the modeller using
-- a conventional viewers window with buttons to push

				
DIRECTORY
  Buttons: TYPE USING [Button, ButtonProc, Create],
  Containers: TYPE USING [ChildXBound, ChildYBound, Container, Create],
  CWF: TYPE USING [SetWriteProcedure, WF0, WF1, WF2],
  DBStash: TYPE USING [ForceOut, Insert],
  Directory: TYPE USING [Error, Handle, ignore, Lookup],
  File: TYPE USING [Capability],
  FileIO: TYPE USING [Open],
  FileStream: TYPE USING [SetLeaderPropertiesForCapability],
  IO: TYPE USING [
    bool, Close, CreateDribbleStream, Flush, GetChar, Handle,
    Put, PutChar, PutF, PutFR, PutRope, Signal, string, time],
  Labels: TYPE USING [Create, Label, Set], 
  LowLoader: TYPE USING [LoadBcdAndCount],
  MDMain: TYPE USING [
    AttachSymbiote, Begin, Compile, Continue, DetachSymbiote,
    Loader, MDMainImpl, modellerIsIdle, Notice, NoticeAll, Permanent,
    PrintSeparatorLine, ReStartModelling, SetWorkingModel, Start, StartModelling, 
    StopModelling, Temporary, Transaction, Type, UnLoader],
  MDUtil: TYPE USING [AcquireMsgLock, AnyR, ReleaseMsgLock],
  Menus: TYPE USING [CreateEntry, CreateMenu, InsertMenuEntry, Menu, MenuProc], 
  Process: TYPE USING [Detach],
  Rope: TYPE USING [Cat, Length, Lower, ROPE, Text],
  RopeInline: TYPE USING [InlineFlatten],
  Rules: TYPE USING [Create, Rule],
  Runtime: TYPE USING [IsBound, RunConfig],
  Subr: TYPE USING [debugflg, LongZone, MakeTTYProcs, PackedTime, SubrStop, TTYProcs],
  Time: TYPE USING [Current],
  TypeScript: TYPE USING [TS, Create, SetUserAbort],
  UserProfile: TYPE USING [Boolean, Token],
  ViewerClasses: TYPE USING [Viewer],
  ViewerEvents: TYPE USING [
    EventProc, EventRegistration, RegisterEventProc, UnRegisterEventProc],
  ViewerIO: TYPE USING [CreateViewerStreams],
  ViewerOps: TYPE USING [
    BlinkIcon, EstablishViewerPosition, PaintViewer, SetMenu, SetOpenHeight], 
  ViewerTools: TYPE USING [MakeNewTextViewer, GetContents, SetContents, SetSelection];


ModelImpl: PROGRAM
  IMPORTS
    Buttons, Containers, CWF, DBStash, Directory, FileIO, FileStream, IO,
    Labels, LowLoader, MDMain, MDUtil, Menus, Process, Rope, RopeInline,
    Rules, Runtime, Subr, Time, TypeScript, UserProfile,
    ViewerEvents, ViewerOps, ViewerIO, ViewerTools = {

-- the code is organized as follows:
--	Procedures used for the Viewers windows only
--	Viewers procedures to implement the exterior of the windows
--	utility routines
--	Initialization code

 -- global data
  Global: TYPE = RECORD[
   -- viewers data
    container: Containers.Container ← NIL, 
    msgTypeScript: TypeScript.TS ← NIL,		-- for compiler progress messages
    msgout: IO.Handle ← NIL,
    msgFile: IO.Handle ← NIL,
    debugTypeScript: TypeScript.TS ← NIL,	-- for debugging messages
    debugout: IO.Handle ← NIL,
    debugFile: IO.Handle ← NIL,
    ttyTypeScript: TypeScript.TS ← NIL,		-- modeller log
    tty: Subr.TTYProcs ← NIL,
    ttyin: IO.Handle ← NIL,
    ttyout: IO.Handle ← NIL,
    ttyFile: IO.Handle ← NIL,
   -- fields
    startModellingFileNameButton: Buttons.Button ← NIL,
    startModellingFileNameViewer: ViewerClasses.Viewer ← NIL,
    noticeFileNameButton: Buttons.Button ← NIL,
    noticeFileNameViewer: ViewerClasses.Viewer ← NIL,
    setWorkingFileNameButton: Buttons.Button ← NIL,
    setWorkingModelViewer: ViewerClasses.Viewer ← NIL,
    attachEditorButton: Buttons.Button ← NIL,
    attachEditorLabel: Labels.Label ← NIL,
    confirmButton: Buttons.Button ← NIL,
    confirmLabel: Labels.Label ← NIL,
    debuggingButton: Buttons.Button ← NIL,
    debuggingLabel: Labels.Label ← NIL,
    touchFileNameButton: Buttons.Button ← NIL,
    touchFileNameViewer: ViewerClasses.Viewer ← NIL,
   --
   -- program data
    attachsymbiote: BOOL ← FALSE,	-- if true then please attach symbiote
    confirm: REF BOOL ← NIL,
    makewizard: BOOL ← FALSE
    ];
	
 -- MDS usage!
  g: REF Global ← NIL;
  destroyEventRegistration: ViewerEvents.EventRegistration;
 -- endof MDS usage !!!


 -- these are commands for the viewers world

  entryHeight: NAT = 15; 
  entryVSpace: NAT = 7; 
  entryHSpace: NAT = 10; 
  
  BuildOuter: PROC = {
    vName: Rope.ROPE = IO.PutFR["Modeller, started on %t", IO.time[Time.Current[]]];
    startModellingRef: Rope.Text;
    menu: Menus.Menu = Menus.CreateMenu[lines: 3];
    g ← NEW[Global←[]];
    g.confirm ← NEW[BOOL←TRUE];
    g.container ← Containers.Create[
      info: [name: vName, iconic: FALSE, scrollable: FALSE, column: $right]];
   -- first row of menu items
    menu.InsertMenuEntry[Menus.CreateEntry["StopModel", StopModellingProc], 0]; 
    menu.InsertMenuEntry[Menus.CreateEntry["Unload", UnloadProc], 0]; 
    menu.InsertMenuEntry[Menus.CreateEntry["Continue", ContinueProc], 0]; 
    menu.InsertMenuEntry[Menus.CreateEntry["Begin", BeginProc], 0]; 
    menu.InsertMenuEntry[Menus.CreateEntry["NoticeAll", NoticeAllProc], 0]; 
    menu.InsertMenuEntry[Menus.CreateEntry["StartModel", StartModellingProc], 0]; 
    menu.InsertMenuEntry[Menus.CreateEntry["Abort", MyAbort], 0]; 
   -- second row of menu items
    -- menu.InsertMenuEntry[Menus.CreateEntry["Permanent", PermanentProc], 1]; ** disabled **
    menu.InsertMenuEntry[Menus.CreateEntry["Temporary", TemporaryProc], 1]; 
    menu.InsertMenuEntry[Menus.CreateEntry["Start", StartProc], 1]; 
    menu.InsertMenuEntry[Menus.CreateEntry["LoadAll", LoadAllProc], 1]; 
    menu.InsertMenuEntry[Menus.CreateEntry["LoadWithRepl", LoadWithReplProc], 1]; 
    menu.InsertMenuEntry[Menus.CreateEntry["Compile", CompileProc], 1]; 
  -- third row of menu items
   menu.InsertMenuEntry[Menus.CreateEntry["Notice", NoticeProc], 2]; 
   menu.InsertMenuEntry[Menus.CreateEntry["ReStartModelling", ReStartModellingProc], 2]; 
   menu.InsertMenuEntry[Menus.CreateEntry["TypeWDefaults", TypeWDefaultsProc], 2]; 
   menu.InsertMenuEntry[Menus.CreateEntry["TypeWODefaults", TypeWODefaultsProc], 2]; 
   menu.InsertMenuEntry[Menus.CreateEntry["SetWorkingModel", SetWorkingModelProc], 2]; 
   menu.InsertMenuEntry[Menus.CreateEntry["Touch", TouchProc], 2];  
   --
   ViewerOps.SetMenu[g.container, menu, FALSE];
   [g.attachsymbiote, g.confirm↑, g.makewizard, startModellingRef]
   			← GetDefaultsFromUserProfile[];
   BuildUserInput[startModellingRef];
   -- kludge required for multiple rows in menus
   ViewerOps.EstablishViewerPosition[g.container, g.container.wx, g.container.wy,
   	g.container.ww, g.container.wh];
   ViewerOps.PaintViewer[g.container, all];
   [g.ttyout, g.ttyFile, g.ttyin, g.tty] ← SetUpLogStreams[g.ttyTypeScript, "Model.Log",
   	TRUE];
   [g.msgout, g.msgFile, ] ← SetUpLogStreams[g.msgTypeScript, "Msg.Log", FALSE];
   IF g.makewizard THEN
      [g.debugout, g.debugFile, ] ← SetUpLogStreams[g.debugTypeScript, "Debug.Log", FALSE];
   [] ← CWF.SetWriteProcedure[ToolTTYProc];
   IF g.attachsymbiote THEN MDMain.AttachSymbiote[g.msgout];
   destroyEventRegistration ← ViewerEvents.RegisterEventProc[MyDestroy, $destroy]};

  BuildUserInput: PROC[startModellingRef: Rope.Text] = {
    heightSoFar: CARDINAL; 
    l: ViewerClasses.Viewer;
    rule: Rules.Rule;
   
    CreateButton: PROC[bname, lname: Rope.Text, newLine: BOOL, drawRule: BOOL←FALSE] 
	RETURNS[button: Buttons.Button, label: Labels.Label] = {
      x: CARDINAL;
      IF newLine THEN {
	heightSoFar ← (IF l = NIL THEN entryVSpace/2 ELSE heightSoFar + entryVSpace + l.wh);
	IF drawRule THEN {
	  rule ← Rules.Create[info: [parent: g.container, wx: 0, wy: heightSoFar, ww: 0, wh: 1]];
	  Containers.ChildXBound[g.container, rule];
	  heightSoFar ← heightSoFar + entryVSpace};
	x ← 0}
      ELSE x ← l.wx + l.ww + entryHSpace;
      l ← button ← Buttons.Create[info: [name: bname, parent: g.container,
	    		border: FALSE, wx: x, wy: heightSoFar], proc: PushButton];
      IF lname ~= NIL THEN
	l ← label ← Labels.Create[info: [name: lname, parent: g.container,
   	       	wx: button.wx + button.ww + entryHSpace, wy: heightSoFar, border: TRUE]]};

   -- first line
    [g.startModellingFileNameButton, ] ← CreateButton["ModelName:", NIL, TRUE];
    l ← g.startModellingFileNameViewer ← ViewerTools.MakeNewTextViewer[info: [parent: g.container,
      wx: l.wx+l.ww+entryHSpace, wy: heightSoFar, ww: 100, wh: entryHeight, 
      data: NIL, scrollable: FALSE, border: FALSE], paint: FALSE];
    IF startModellingRef ~= NIL THEN 
      ViewerTools.SetContents[g.startModellingFileNameViewer, startModellingRef];
    [g.noticeFileNameButton, ] ← CreateButton["NoticeName:", NIL, FALSE];
    l ← g.noticeFileNameViewer ← ViewerTools.MakeNewTextViewer[info: [parent: g.container,
      wx: l.wx+l.ww+entryHSpace, wy: heightSoFar, ww: 100, wh: entryHeight, 
      data: NIL, scrollable: FALSE, border: FALSE], paint: FALSE];
    [g.setWorkingFileNameButton, ] ← CreateButton["ProcName:", NIL, FALSE];
    l ← g.setWorkingModelViewer ← ViewerTools.MakeNewTextViewer[info: [parent: g.container,
      wx: l.wx+l.ww+entryHSpace, wy: heightSoFar, ww: 100, wh: entryHeight, 
      data: NIL, scrollable: FALSE, border: FALSE], paint: FALSE];
    Containers.ChildXBound[g.container, g.setWorkingModelViewer];
   --second line
    [g.attachEditorButton, g.attachEditorLabel] ← CreateButton["AttachEditor:",
      "FALSE", TRUE];
    IF g.attachsymbiote THEN Labels.Set[g.attachEditorLabel, "TRUE"];
    [g.confirmButton, g.confirmLabel] ← CreateButton["Confirm:", "FALSE", FALSE];
    IF g.confirm↑ THEN Labels.Set[g.confirmLabel, "TRUE"];
    [g.debuggingButton, g.debuggingLabel] ← CreateButton["Debugging:", "FALSE", FALSE];
    IF Subr.debugflg THEN Labels.Set[g.debuggingLabel, "TRUE"];
    [g.touchFileNameButton,] ← CreateButton["TouchName:", NIL, FALSE];
    l ← g.touchFileNameViewer ← ViewerTools.MakeNewTextViewer[info: [parent: g.container,
      wx: l.wx+l.ww+entryHSpace, wy: heightSoFar, ww: 0, wh: entryHeight, 
      data: NIL, scrollable: FALSE, border: FALSE], paint: FALSE];
    Containers.ChildXBound[g.container, g.touchFileNameViewer];
    heightSoFar ← heightSoFar+entryVSpace/2+l.wh;
   --
   -- first the msg window
   --  now the line above the typescript
    rule ← Rules.Create[info: [parent: g.container, wx: 0, wy: heightSoFar, ww: 0, wh: 1]];
    Containers.ChildXBound[g.container, rule];
    heightSoFar ← heightSoFar+entryVSpace/2;
   -- now the typescript
    g.msgTypeScript ← TypeScript.Create[info: [parent: g.container,
      wx: 0, wy: heightSoFar, ww: 0, wh: 25, border: FALSE]];
    Containers.ChildXBound[g.container, g.msgTypeScript];
    heightSoFar ← heightSoFar + entryVSpace + 20;
   -- then the debugging window
    IF g.makewizard THEN {
      rule ← Rules.Create[info: [parent: g.container, wx: 0, wy: heightSoFar, ww: 0, wh: 1]];
      Containers.ChildXBound[g.container, rule];
      heightSoFar ← heightSoFar+entryVSpace/2;
      -- now the typescript
      g.debugTypeScript ← TypeScript.Create[info: [parent: g.container,
         wx: 0, wy: heightSoFar, ww: 0, wh: 40, border: FALSE]];
      Containers.ChildXBound[g.container, g.debugTypeScript];
      heightSoFar ← heightSoFar + entryVSpace/2 + 40};
   --  now the line above the typescript
    rule ← Rules.Create[info: [parent: g.container, wx: 0, wy: heightSoFar, ww: 0, wh: 1]];
    Containers.ChildXBound[g.container, rule];
    heightSoFar ← heightSoFar+entryVSpace/2;
   -- now the typescript
    g.ttyTypeScript ← TypeScript.Create[info: [parent: g.container,
      wx: 0, wy: heightSoFar, ww: 0, wh: 800, border: FALSE]];	-- 800 due to viewers bug
    Containers.ChildXBound[g.container, g.ttyTypeScript];
    Containers.ChildYBound[g.container, g.ttyTypeScript];
    ViewerOps.SetOpenHeight[g.container, heightSoFar + 200]};

  BoolLabels: ARRAY BOOL OF Rope.Text ← --=-- [FALSE: "FALSE", TRUE: "TRUE"];

  PushButton: Buttons.ButtonProc = TRUSTED {
    SELECT NARROW[parent, ViewerClasses.Viewer] FROM
      g.attachEditorButton => {
	g.attachsymbiote ← ~g.attachsymbiote;
	Labels.Set[g.attachEditorLabel, BoolLabels[g.attachsymbiote]];
	-- this prints on the msgwindow after acquiring the lock
	IF g.attachsymbiote THEN MDMain.AttachSymbiote[g.msgout]
	ELSE MDMain.DetachSymbiote[g.msgout]};
      g.confirmButton => {
	g.confirm↑ ← ~g.confirm↑;
	Labels.Set[g.confirmLabel, BoolLabels[g.confirm↑]]};
      g.debuggingButton => {
	Subr.debugflg ← ~Subr.debugflg;
	Labels.Set[g.debuggingLabel, BoolLabels[Subr.debugflg]];
	-- this prints on the msgwindow after acquiring the lock
	MDUtil.AcquireMsgLock[];
	g.msgout.PutF["Debugging is now %g.\n", IO.bool[Subr.debugflg]
			! UNWIND => {MDUtil.ReleaseMsgLock[]}];
	MDUtil.ReleaseMsgLock[]};
      g.noticeFileNameButton => 
	ViewerTools.SetSelection[g.noticeFileNameViewer, NIL];
      g.setWorkingFileNameButton => 
	ViewerTools.SetSelection[g.setWorkingModelViewer, NIL];
      g.startModellingFileNameButton =>
	ViewerTools.SetSelection[g.startModellingFileNameViewer, NIL];
      g.touchFileNameButton =>
	ViewerTools.SetSelection[g.touchFileNameViewer, NIL];
      ENDCASE => ERROR};
	
  GetVString: PROC[viewer: ViewerClasses.Viewer] RETURNS[contentsRef: Rope.Text] = {
    vString: Rope.ROPE = ViewerTools.GetContents[viewer];
    RETURN[IF vString.Length = 0 THEN NIL ELSE RopeInline.InlineFlatten[vString]]};
   
  SetUpLogStreams: PROC[ts: TypeScript.TS, fileName: Rope.Text, createTTY: BOOL]
	RETURNS[out, file, in: IO.Handle, tty: Subr.TTYProcs] = {
    file ← FileIO.Open[fileName, overwrite];
    [in, out] ← ViewerIO.CreateViewerStreams[viewer: ts, name: NIL, editedStream: FALSE];
    out ← IO.CreateDribbleStream[out, file];
    tty ← IF createTTY THEN Subr.MakeTTYProcs[in, out, ts, MyConfirm] ELSE NIL};

  MyConfirm: PROC[in, out: IO.Handle, data: REF ANY, msg: Rope.ROPE, dch: CHAR]
	RETURNS[CHAR] = {
    out.PutRope[msg];
    DO
      ENABLE IO.Signal => TRUSTED {IF ec = Rubout THEN LOOP};
      bs: IO.Handle = (IF in.backingStream = NIL THEN in ELSE in.backingStream);
      ch: CHAR;
      out.PutF["? "];
      ch ← bs.GetChar[];
      RETURN[Rope.Lower[IF ch = '\n THEN dch ELSE ch]];
      ENDLOOP};
	
 -- print to viewers screen
  ToolTTYProc: PROC[ch: CHAR] = {
    (g.ttyout).PutChar[ch]};

 -- file acquisition
 
  GetFile: PROC[viewer: ViewerClasses.Viewer, ext: Rope.Text] RETURNS [ref: Rope.Text] = {
    ref ← GetVString[viewer];
    IF ref = NIL THEN {
      MDMain.PrintSeparatorLine[];
      CWF.WF0["Error - Must specify a filename.\n"L];
      MDMain.PrintSeparatorLine[];
      RETURN};
    IF ref.Length[] > 0 AND ~MDUtil.AnyR[ref, '.] THEN 
      ref ← RopeInline.InlineFlatten[Rope.Cat[ref, ext]];
    RETURN};

  BeginProc: Menus.MenuProc = TRUSTED {
    IF ChkIdle[g.msgout] THEN {
      modelRef: Rope.Text = GetFile[g.startModellingFileNameViewer, ".model"];
      IF modelRef = NIL THEN RETURN;
      [] ← Subr.LongZone[];	-- this forces Subr.SubrInit to be called
      Process.Detach[FORK MDMain.Begin[
        action: NEW[MDMain.Transaction←[
        		modelRef, FALSE, 
			g.tty, g.ttyTypeScript, g.ttyin, g.ttyout, g.msgout, g.debugout]],
	confirm: g.confirm]]}};

  CompileProc: Menus.MenuProc = TRUSTED {
    IF ChkIdle[g.msgout] THEN {
      modelRef: Rope.Text = GetFile[g.startModellingFileNameViewer, ".model"];
      IF modelRef = NIL THEN RETURN;
      [] ← Subr.LongZone[];	-- this forces Subr.SubrInit to be called
      Process.Detach[FORK MDMain.Compile[
        action: NEW[MDMain.Transaction←[
        		modelRef, FALSE, 
        		g.tty, g.ttyTypeScript, g.ttyin, g.ttyout, g.msgout, g.debugout]], 
	uniquename: FALSE, -- ignored-- tryreplacement: FALSE, 
	confirm: g.confirm]]}};
      
  ContinueProc: Menus.MenuProc = TRUSTED {
    IF ChkIdle[g.msgout] THEN
      Process.Detach[FORK MDMain.Continue[g.confirm]]};

  LoadAllProc: Menus.MenuProc = TRUSTED {
    IF ChkIdle[g.msgout] THEN
      Process.Detach[FORK MDMain.Loader[FALSE]]};

  LoadWithReplProc: Menus.MenuProc = TRUSTED {
    IF ChkIdle[g.msgout] THEN
      Process.Detach[FORK MDMain.Loader[TRUE]]};

  NoticeProc: Menus.MenuProc = TRUSTED {
    IF ChkIdle[g.msgout] THEN {
      noticeRef: Rope.Text = GetFile[g.noticeFileNameViewer, ".mesa"];
      IF noticeRef = NIL THEN RETURN;
      Process.Detach[FORK MDMain.Notice[noticeRef]]}};

  NoticeAllProc: Menus.MenuProc = TRUSTED {
    IF ChkIdle[g.msgout] THEN
      Process.Detach[FORK MDMain.NoticeAll[]]};
	
  -- Permanent is disabled
  PermanentProc: Menus.MenuProc = TRUSTED {
    IF ChkIdle[g.msgout] THEN
      Process.Detach[FORK MDMain.Permanent[]]};
   
  ReStartModellingProc: Menus.MenuProc = TRUSTED {
    IF ChkIdle[g.msgout] THEN {
      modelRef: Rope.Text = GetFile[g.startModellingFileNameViewer, ".model"];
      IF modelRef = NIL THEN RETURN;
      [] ← Subr.LongZone[];	-- this forces Subr.SubrInit to be called
      Process.Detach[FORK MDMain.ReStartModelling[
        NEW[MDMain.Transaction←[
        	modelRef, FALSE, 
        	g.tty, g.ttyTypeScript, g.ttyin, g.ttyout, g.msgout, g.debugout]]]]}};

  SetWorkingModelProc: Menus.MenuProc = TRUSTED {
    IF ChkIdle[g.msgout] THEN {
      modelRef: Rope.Text = GetFile[g.setWorkingModelViewer, ".model"];
      IF modelRef = NIL THEN RETURN; 
      Process.Detach[FORK MDMain.SetWorkingModel[modelRef]]}};

  StartProc: Menus.MenuProc = TRUSTED {
    IF ChkIdle[g.msgout] THEN
      Process.Detach[FORK MDMain.Start[]]};
     
     
  StartModellingProc: Menus.MenuProc = TRUSTED {
    IF ChkIdle[g.msgout] THEN {
      modelRef: Rope.Text = GetFile[g.startModellingFileNameViewer, ".model"];
      IF modelRef = NIL THEN RETURN;
      [] ← Subr.LongZone[];	-- this forces Subr.SubrInit to be called
      Process.Detach[FORK MDMain.StartModelling[
        NEW[MDMain.Transaction←[
        	modelRef, FALSE, 
        	g.tty, g.ttyTypeScript, g.ttyin, g.ttyout, g.msgout, g.debugout]]]]}};
   
  StopModellingProc: Menus.MenuProc = TRUSTED {
    IF ChkIdle[g.msgout] THEN
      Process.Detach[FORK MDMain.StopModelling[]]};

  TemporaryProc: Menus.MenuProc = TRUSTED {
    IF ChkIdle[g.msgout] THEN
      Process.Detach[FORK MDMain.Temporary[]]};

  TouchProc: Menus.MenuProc = TRUSTED {
    IF ChkIdle[g.msgout] THEN {
      date: Subr.PackedTime ← Time.Current[];
      cap: File.Capability;
      fileRef: Rope.Text  = GetFile[g.touchFileNameViewer, ".mesa"];
      MDMain.PrintSeparatorLine[];
      IF fileRef = NIL THEN RETURN;
      CWF.WF2["Touch %s: time set to %lt\n"L, LOOPHOLE[fileRef], @date];
      cap ← Directory.Lookup[fileName: LOOPHOLE[fileRef], permissions: Directory.ignore
	! Directory.Error => {
	    CWF.WF1["Error - Can't find file '%s'.\n"L, LOOPHOLE[fileRef]];
	    GOTO out}];
      FileStream.SetLeaderPropertiesForCapability[cap: cap, create: [date]];
      CWF.WF0["Now calling Notice.\n"L];
      Process.Detach[FORK MDMain.Notice[fileRef]];
      EXITS
        out => NULL}
      };

  TypeWDefaultsProc: Menus.MenuProc = TRUSTED {
    IF ChkIdle[g.msgout] THEN {
      fileRef: Rope.Text = GetFile[g.setWorkingModelViewer, ".model"];
      Process.Detach[FORK MDMain.Type[fileRef, TRUE]]}};

  TypeWODefaultsProc: Menus.MenuProc = TRUSTED {
    IF ChkIdle[g.msgout] THEN {
      fileRef: Rope.Text = GetFile[g.setWorkingModelViewer, ".model"];
      Process.Detach[FORK MDMain.Type[fileRef, FALSE]]}};

  UnloadProc: Menus.MenuProc = TRUSTED {
    IF ChkIdle[g.msgout] THEN
      Process.Detach[FORK MDMain.UnLoader[]]};

  NullTTYProc: PROC[ch: CHAR] = {};	-- prints nothing

  MyDestroy: ViewerEvents.EventProc = TRUSTED {
    IF g = NIL OR event ~= destroy OR viewer ~= g.container THEN RETURN;
    [] ← CWF.SetWriteProcedure[NullTTYProc];	-- turn off printing
    MDMain.DetachSymbiote[g.msgout];
    [] ← DBStash.ForceOut[];
    Subr.SubrStop[];
    g.ttyFile.Close[];
    g.msgFile.Close[];
    IF g.makewizard THEN g.debugFile.Close[];
    g ← NIL;
    ViewerEvents.UnRegisterEventProc[$destroyEventRegistration, $destroy]};
   
  MyAbort: Menus.MenuProc = TRUSTED {
    TypeScript.SetUserAbort[g.ttyTypeScript]};
	
-- common utility procedures

  GetDefaultsFromUserProfile: PROC
	RETURNS[attacheditor, confirmCompilation, makewizard: BOOL, defaultFile: Rope.Text] = {
   defaultFile ← RopeInline.InlineFlatten[UserProfile.Token["Modeller.DefaultModel", NIL]];
   attacheditor ← UserProfile.Boolean["Modeller.AttachEditor", TRUE]; -- default is true
   confirmCompilation ← UserProfile.Boolean["Modeller.Confirm", FALSE]; -- default is false
   makewizard ← UserProfile.Boolean["Modeller.Wizard", FALSE]};	-- default is false


  ChkIdle: PROC[out: IO.Handle] RETURNS[chkok: BOOL] = {
    IF ~MDMain.modellerIsIdle THEN {
      MDUtil.AcquireMsgLock[];
      out.Put[IO.string["Modeller is not ready yet.\nTry again in a few seconds.\n"L]
	! UNWIND => MDUtil.ReleaseMsgLock[]];
      out.Flush[];
      ViewerOps.BlinkIcon[g.container];
      MDUtil.ReleaseMsgLock[];
      RETURN[FALSE]};
    RETURN[TRUE]};
	

  SetTTY: PROC = {
    [] ← CWF.SetWriteProcedure[ToolTTYProc]};

 
 -- initialization code

  LoadPackage: PROC[file: LONG STRING] = {
    CWF.WF1["Loading %s ... "L, file];
      {
      ENABLE ANY => { CWF.WF0["failed.\n"L]; GOTO out};
      cap: File.Capability = Directory.Lookup[file];
      Runtime.RunConfig[file: cap, offset: 1, codeLinks: TRUE];
      CWF.WF0["done.\n"L];
      EXITS
	out => NULL;
      }};

  Init: PROC = {
    -- This makes sure the global variables in MDMainImpl are initialized
    START MDMain.MDMainImpl;
    BuildOuter[];	-- fire up the tool
    -- the main program exits at this point
    -- SimpleExec will call these procedures when the user invokes them
    -- TemporarySpecialExecOps is only available to the modeller if
    -- Compiler.Bcd has been loaded BEFORE loaderpack accumulates
    -- all the system interface records
    IF ~Runtime.IsBound[LowLoader.LoadBcdAndCount] THEN
      LoadPackage["LoaderPack.bcd"L];
    IF ~Runtime.IsBound[DBStash.Insert] THEN
      LoadPackage["DBStashPack.bcd"L];
    MDMain.modellerIsIdle ← TRUE};

  Init[];
  }.