-- File: PupBootServerTool.mesa,  Last Edit: HGM  February 17, 1981  4:51 AM
-- Please don't forget to update the herald...

DIRECTORY
  Process USING [Yield],
  Space USING [nullHandle],
  Time USING [Current],

  Format USING [], -- Needed by Put.Date and such
  FormSW USING [
    ClientItemsProcType, ProcType, AllocateItemDescriptor, newLine, sameLine,
    Display, FindItem, CommandItem, BooleanItem, StringItem],
  Menu USING [Create, Handle, Instantiate, ItemObject, MCRType],
  MsgSW USING [Post],
  Put USING [Char, CR, Date, Decimal, Line, LongNumber, Number, Text],
  Tool USING [Create, MakeSWsProc, MakeMsgSW, MakeFileSW, MakeFormSW],
  ToolWindow USING [TransitionProcType],
  UserInput USING [GetDefaultWindow, userAbort],
  Window USING [Handle, Place],

  Clock USING [TimeIsKnown],
  StatsDefs USING [StatGetCounter],
  BootServerDefs USING [
    BootFile, timeNotKnown, PupBootServerOn, PupBootServerOff,
    StartProbingForBootFiles, StartLongRangeProbingForBootFiles,
    EnumerateBootTable, msg, slowBooteeHost, slosheeHost, slowBootFileName,
    slosheeFileName, running, slowBooting, probing, sloshing, statFileSent,
    statBootDir, statMicrocodeBooted, statFileSentSlow, statBootNew];

PupBootServerTool: MONITOR
  IMPORTS
    Space, Process, Time, FormSW, Menu, MsgSW, Put, Tool, UserInput, Clock,
    StatsDefs, BootServerDefs
  EXPORTS BootServerDefs =
  BEGIN OPEN BootServerDefs;

  form, log: PUBLIC Window.Handle ← NIL;

  Init: PROCEDURE =
    BEGIN
    [] ← Tool.Create[
      name: "Boot Server of February 17, 1981"L, makeSWsProc: MakeSWs,
      clientTransition: ClientTransition, initialState: inactive];
    Menu.Instantiate[menu, UserInput.GetDefaultWindow[]];
    END;

  UpdatePicture: PUBLIC PROCEDURE =
    BEGIN
    IF form = NIL THEN RETURN;
    FormSW.FindItem[form, startIX].flags.invisible ← running;
    FormSW.FindItem[form, stopIX].flags.invisible ← ~running;
    FormSW.FindItem[form, probeIX].flags.invisible ← ~running;
    FormSW.FindItem[form, longIX].flags.invisible ← ~running;
    FormSW.FindItem[form, printIX].flags.invisible ← ~running;
    FormSW.Display[form];
    END;

  PrintBootInfo: PROCEDURE [wh: Window.Handle] =
    BEGIN
    PrintHeader[wh, "Boot Server Statistics:"L];
    PrintMaybe[wh, "Boot files sent"L, StatsDefs.StatGetCounter[statFileSent]];
    PrintMaybe[
      wh, "Boot directory requests"L, StatsDefs.StatGetCounter[statBootDir]];
    PrintMaybe[
      wh, "Microcode Boots requests"L, StatsDefs.StatGetCounter[
      statMicrocodeBooted]];
    PrintMaybe[
      wh, "Slow boot files sent"L, StatsDefs.StatGetCounter[statFileSentSlow]];
    PrintMaybe[
      wh, "New boot files retrieved"L, StatsDefs.StatGetCounter[statBootNew]];
    END;

  PrintMaybe: PROCEDURE [wh: Window.Handle, s: STRING, n: LONG INTEGER] =
    BEGIN
    IF n = 0 THEN RETURN;
    Put.Text[wh, s];
    Put.Text[wh, ": "L];
    Put.LongNumber[wh, n, [10, FALSE, TRUE, 0]];
    Put.CR[wh];
    END;

  PrintBootFileTable: PROCEDURE [wh: Window.Handle] =
    BEGIN
    PrintOne: PROCEDURE [bf: BootServerDefs.BootFile] =
      BEGIN
      pages ← pages + bf.pages;
      IF bf.space # Space.nullHandle THEN pagesInVM ← pagesInVM + bf.pages;
      IF UserInput.userAbort THEN RETURN;
      Put.Number[wh, bf.code, [8, FALSE, TRUE, 6]];
      IF bf.space # Space.nullHandle THEN Put.Char[wh, '*] ELSE Put.Char[wh, ' ];
      Put.Number[wh, bf.pages, [10, FALSE, TRUE, 5]];
      Put.LongNumber[wh, bf.count, [10, FALSE, TRUE, 6]];
      IF bf.count = 0 THEN Put.Text[wh, "      "L]
      ELSE Put.LongNumber[wh, bf.ms/bf.count, [10, FALSE, TRUE, 6]];
      IF bf.inTransit THEN Put.Text[wh, "T "L] ELSE Put.Text[wh, "  "L];
      SELECT TRUE FROM
	bf.unknown => Put.Text[wh, "Not on this disk  "L];
	(bf.create = BootServerDefs.timeNotKnown) =>
	  Put.Text[wh, "Unknown           "L];
	ENDCASE => Put.Date[wh, bf.create, dateTime];
      Put.Text[wh, "  "L];
      Put.Text[wh, bf.fileName];
      Put.CR[wh];
      DoSomeYields[];
      END;
    pages, pagesInVM: CARDINAL ← 0;
    Put.CR[wh];
    PrintHeader[wh, "Boot File Table:"L];
    Put.Line[wh, "  Code   Pgs Count AvgMs      Create Time     FileName"L];
    EnumerateBootTable[PrintOne];
    IF pagesInVM # 0 THEN
      BEGIN
      Put.Decimal[wh, pagesInVM];
      Put.Text[wh, " out of "L];
      Put.Decimal[wh, pages];
      Put.Line[wh, " pages are mapped into VM."L];
      END;
    END;

  PrintHeader: PROCEDURE [wh: Window.Handle, s: STRING] =
    BEGIN
    Put.CR[wh];
    Put.Date[wh, Time.Current[], dateTime];
    Put.Text[wh, "  "L];
    Put.Line[wh, s];
    END;

  DoSomeYields: PROCEDURE =
    BEGIN THROUGH [0..100) DO Process.Yield[]; ENDLOOP; END;

  Start: FormSW.ProcType = BEGIN PupBootServerOn[]; END;

  Stop: FormSW.ProcType = BEGIN PupBootServerOff[]; END;

  ProbeCommand: FormSW.ProcType =
    BEGIN
    IF msg # NIL THEN
      SELECT TRUE FROM
	probing => MsgSW.Post[msg, "Already probing for new Boot files."L];
	sloshing => MsgSW.Post[msg, "Currently sloshing a new Boot file."L];
	~Clock.TimeIsKnown[] =>
	  MsgSW.Post[msg, "Time not valid -- Boot probes would be ignored."L];
	ENDCASE => MsgSW.Post[msg, "Probing for new Boot files."L];
    StartProbingForBootFiles[];
    END;

  LongRangeProbeCommand: FormSW.ProcType =
    BEGIN
    IF msg # NIL THEN
      SELECT TRUE FROM
	probing => MsgSW.Post[msg, "Already probing for new Boot files."L];
	sloshing => MsgSW.Post[msg, "Currently sloshing a new Boot file."L];
	~Clock.TimeIsKnown[] =>
	  MsgSW.Post[msg, "Time not valid -- Boot probes would be ignored."L];
	ENDCASE => MsgSW.Post[msg, "Probing for new Boot files."L];
    StartLongRangeProbingForBootFiles[];
    END;

  PrintInfo: FormSW.ProcType = BEGIN PrintBootInfo[log]; END;

  PrintTable: FormSW.ProcType = BEGIN PrintBootFileTable[log]; END;

  MakeSWs: Tool.MakeSWsProc =
    BEGIN
    msg ← Tool.MakeMsgSW[window: window, lines: 5];
    form ← Tool.MakeFormSW[window: window, formProc: MakeForm];
    log ← Tool.MakeFileSW[window: window, name: "BootServer.log$"L];
    Menu.Instantiate[menu, log];
    END;

  menu: Menu.Handle = Menu.Create[DESCRIPTOR[items], "Booter", TRUE];
  items: ARRAY [0..1] OF Menu.ItemObject ← [["Info", DoMenu], ["Table", DoMenu]];

  infoMx: CARDINAL = 0;
  tableMx: CARDINAL = 1;

  DoMenu: Menu.MCRType =
    BEGIN
    IF window # log THEN window ← NIL; -- Great window in the sky
    SELECT index FROM
      infoMx => PrintBootInfo[window];
      tableMx => PrintBootFileTable[window];
      ENDCASE => ERROR;
    END;

  startIX: CARDINAL = 0;
  stopIX: CARDINAL = 1;
  probeIX: CARDINAL = 2;
  longIX: CARDINAL = 3;
  printIX: CARDINAL = 6;
  MakeForm: FormSW.ClientItemsProcType =
    BEGIN
    booteePlace: Window.Place = [7*15, FormSW.sameLine];
    bootFilePlace: Window.Place = [7*35, FormSW.sameLine];
    nParams: CARDINAL = 13;
    items ← FormSW.AllocateItemDescriptor[nParams];
    items[0] ← FormSW.CommandItem[
      tag: "Start"L, proc: Start, place: FormSW.newLine, invisible: running];
    items[1] ← FormSW.CommandItem[
      tag: "Stop"L, proc: Stop, place: FormSW.newLine, invisible: ~running];
    items[2] ← FormSW.CommandItem[
      tag: "Probe"L, proc: ProbeCommand, invisible: ~running];
    items[3] ← FormSW.CommandItem[
      tag: "LongRangeProbe"L, proc: LongRangeProbeCommand, invisible: ~running];
    items[4] ← FormSW.BooleanItem[
      tag: "Probing"L, switch: @probing, readOnly: TRUE];
    items[5] ← FormSW.CommandItem[
      tag: "PrintInfo"L, proc: PrintInfo, place: FormSW.newLine];
    items[6] ← FormSW.CommandItem[
      tag: "PrintTable"L, proc: PrintTable, invisible: ~running];
    items[7] ← FormSW.BooleanItem[
      tag: "SlowBooting"L, switch: @slowBooting, place: FormSW.newLine,
      readOnly: TRUE];
    items[8] ← FormSW.StringItem[
      tag: "SlowBootee"L, string: @slowBooteeHost, place: booteePlace,
      readOnly: TRUE];
    items[9] ← FormSW.StringItem[
      tag: "SlowFile"L, string: @slowBootFileName, place: bootFilePlace,
      readOnly: TRUE];
    items[10] ← FormSW.BooleanItem[
      tag: "Sloshing"L, switch: @sloshing, place: FormSW.newLine, readOnly: TRUE];
    items[11] ← FormSW.StringItem[
      tag: "Sloshee"L, string: @slosheeHost, place: booteePlace, readOnly: TRUE];
    items[12] ← FormSW.StringItem[
      tag: "SloshFile"L, string: @slosheeFileName, place: bootFilePlace,
      readOnly: TRUE];
    RETURN[items, TRUE];
    END;

  ClientTransition: ToolWindow.TransitionProcType =
    BEGIN IF new = inactive THEN msg ← form ← log ← NIL; END;

  -- initialization

  Init[];
  BootServerDefs.PupBootServerOn[];
  END.