-- Copyright (C) 1984, 1985  by Xerox Corporation. All rights reserved. 
-- GateInfoNoDisk.mesa, HGM,  6-Aug-85 23:47:49

DIRECTORY
  Process USING [Yield],
  Put USING [CR, Char, Date, Line, LongNumber, Number, Text],
  Time USING [Current],
  Window USING [Handle],

  Buffer USING [],
  BufferOps USING [GetStatistics, Statistics],
  Driver USING [Network, GetDeviceChain],
  EchoServer USING [GetCounters],
  ForwarderDefs USING [
    Counters, GetPointerToBadPupStats, GetPointerToPupGateStats, statGateInfoReplies],
  GateDefs USING [GetVersionText],
  CpuIdle USING [GetSmoothedCpuUtilization],
  Inr USING [ForwardingStats],
  NameServerDefs USING [
    GetNewDirectoryVersion, GetOldDirectoryVersion, statName, statAddress, statXlation,
    statSend],
  Protocol1 USING [GetContext],
  PupRouterDefs USING [NetworkContext],
  PupTimeServer USING [GetAltoTimeRequests],
  Stats USING [
    StatCounterIndex, StatGetCounter, StatPrintCurrent, StatSince, StatUpdate],
  TimeServerOps USING [GetOldTimeRequests, GetTimeRequests],
  
  OthelloDefs USING [CommandProcessor, IndexTooLarge, MyNameIs, RegisterCommandProc];

GateInfoNoDisk: PROGRAM
  IMPORTS
    Process, Put, Time,
    BufferOps, Driver,
    EchoServer, ForwarderDefs, GateDefs, CpuIdle, Inr, NameServerDefs,
    Protocol1, PupTimeServer, Stats, TimeServerOps,
    OthelloDefs
  EXPORTS Buffer =
  BEGIN
  
  Network: PUBLIC TYPE = Driver.Network;

  version: LONG STRING = GateDefs.GetVersionText[];
  firstNetwork: Driver.Network = Driver.GetDeviceChain[];
  packets: LONG POINTER TO ForwarderDefs.Counters;
  bytes: LONG POINTER TO ForwarderDefs.Counters;
  bad: LONG POINTER TO ForwarderDefs.Counters;
  nets: CARDINAL;

  PrintGateStats: PUBLIC PROCEDURE [wh: Window.Handle] =
    BEGIN
    PupForwardingStats: PROCEDURE RETURNS [p, b: LONG CARDINAL ← 0] =
      BEGIN
      FOR from: Driver.Network ← firstNetwork, from.next UNTIL from = NIL DO
        FOR to: Driver.Network ← firstNetwork, to.next UNTIL to = NIL DO
          p ← p + packets[from.index + to.index*nets];
          b ← b + bytes[from.index + to.index*nets];
	  ENDLOOP;
        ENDLOOP;
      END;
    PrintPacketsForwarded: PROCEDURE =
      BEGIN
      Line["Packets forwarded:"L];
      Text["       Discard"L];
      FOR to: Driver.Network ← firstNetwork, to.next UNTIL to = NIL DO
        toContext: PupRouterDefs.NetworkContext ← Protocol1.GetContext[to, pup];
        Text["      "L];
	O4[toContext.pupNetNumber];
	ENDLOOP;
      IF bad # NIL THEN
        FOR network: Driver.Network ← firstNetwork, network.next UNTIL network = NIL DO
	IF bad[network.index] # 0 THEN
	  BEGIN Text["       Bad"L]; EXIT; END;
	ENDLOOP;
      CR[];
      FOR from: Driver.Network ← firstNetwork, from.next UNTIL from = NIL DO
        fromContext: PupRouterDefs.NetworkContext ← Protocol1.GetContext[from, pup];
        O4[fromContext.pupNetNumber];
        Text[IF from.alive THEN " "L ELSE "*"L];
        LD10Dash[packets[from.index + 0*nets]];
        FOR to: Driver.Network ← firstNetwork, to.next UNTIL to = NIL DO
          LD10Dash[packets[from.index + to.index*nets]]; ENDLOOP;
        IF bad # NIL AND (bad[from.index] # 0) THEN LD10Dash[bad[from.index]];
        CR[];
        ENDLOOP;
      END;
    PrintBytesForwarded: PROCEDURE =
      BEGIN
      Line["KBytes forwarded:"L];
      Text["       Discard"L];
      FOR to: Driver.Network ← firstNetwork, to.next UNTIL to = NIL DO
        toContext: PupRouterDefs.NetworkContext ← Protocol1.GetContext[to, pup];
        Text["      "L];
	O4[toContext.pupNetNumber];
	ENDLOOP;
      CR[];
      FOR from: Driver.Network ← firstNetwork, from.next UNTIL from = NIL DO
        fromContext: PupRouterDefs.NetworkContext ← Protocol1.GetContext[from, pup];
        O4[fromContext.pupNetNumber];
        Text[IF from.alive THEN " "L ELSE "*"L];
        LD10Dash[bytes[from.index + 0*nets]/1000];
        FOR to: Driver.Network ← firstNetwork, to.next UNTIL to = NIL DO
          LD10Dash[bytes[from.index + to.index*nets]/1000]; ENDLOOP;
        CR[];
        ENDLOOP;
      END;
    PrintMaybe: PROCEDURE [s: LONG STRING, x: Stats.StatCounterIndex] =
      BEGIN
      n: LONG CARDINAL = Stats.StatGetCounter[x];
      IF n = 0 THEN RETURN;
      Text[s];
      Text[": "L];
      LD[n];
      CR[];
      END;
    O4: PROCEDURE [n: CARDINAL] =
      BEGIN Put.Number[wh, n, [8, FALSE, TRUE, 4]]; END;
    D: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[wh, n, [10, FALSE, TRUE, 0]]; END;
    LD: PROCEDURE [n: LONG CARDINAL] = BEGIN Put.LongNumber[wh, n, [10, FALSE, TRUE, 0]]; END;
    LDS: PROCEDURE [x: Stats.StatCounterIndex] =
      BEGIN LD[Stats.StatGetCounter[x]]; END;
    LD10Dash: PROCEDURE [n: LONG CARDINAL] =
      BEGIN
      IF n = 0 THEN Put.Text[wh, "        - "L]
      ELSE Put.LongNumber[wh, n, [10, FALSE, TRUE, 10]];
      END;
    PrintUpTime: PROCEDURE =
      BEGIN
      sec: LONG INTEGER ← Stats.StatGetCounter[statSeconds];
      min: LONG INTEGER;
      hours: LONG INTEGER;
      hours ← sec/3600;
      sec ← sec - hours*3600;
      min ← sec/60;
      sec ← sec - min*60;
      LD[hours];
      Char[':];
      LD[min];
      Char[':];
      LD[sec];
      END;
    Line: PROCEDURE [s: LONG STRING] = BEGIN Put.Line[wh, s]; END;
    Text: PROCEDURE [s: LONG STRING] = BEGIN Put.Text[wh, s]; END;
    Char: PROCEDURE [c: CHARACTER] = BEGIN Put.Char[wh, c]; END;
    CR: PROCEDURE = BEGIN Put.CR[wh]; END;
    Stats.StatUpdate[];  -- be sure time is up to date
    PutHeader[wh, version, FALSE];
    CR[];
    Text["UP = "L];
    PrintUpTime[];
    Text[", CPU = "];
    D[CpuIdle.GetSmoothedCpuUtilization[]];
    Text["%"];
    CR[];
    BEGIN
    packets, bytes: LONG CARDINAL;
    [packets, bytes] ← EchoServer.GetCounters[];
    Text["Echo: "L];
    LD[packets];
    Text[" packets, "L];
    LD[bytes];
    Text[" bytes"L];
    Text[", Time: "L];
    LD[TimeServerOps.GetTimeRequests[]];
    Text[", Old Time: "L];
    LD[TimeServerOps.GetOldTimeRequests[]];
    CR[];
    END;
    BEGIN
    seconds: LONG CARDINAL = Stats.StatGetCounter[statSeconds];
    packets, bytes: LONG CARDINAL;
    [packets, bytes] ← Inr.ForwardingStats[];
    Text["NS: "L];
    LD[packets];
    Text[" packets, "L];
    LD[bytes];
    Text[" bytes"L];
    IF seconds # 0 THEN
      BEGIN
      Text[", "L];
      LD[packets/seconds];
      Text[" packets/second, "L];
      LD[bytes/(seconds/8)];
      Text[" bits/second"L];
      END;
    CR[];
    [packets, bytes] ← PupForwardingStats[];
    Text["Pup: "L];
    LD[packets];
    Text[" packets, "L];
    LD[bytes];
    Text[" bytes"L];
    IF seconds # 0 THEN
      BEGIN
      Text[", "L];
      LD[packets/seconds];
      Text[" packets/second, "L];
      LD[bytes/(seconds/8)];
      Text[" bits/second"L];
      END;
    CR[];
    END;
    Text["PupEcho: "L];
    LDS[pupsEchoed];
    Text[", Route: "L];
    LDS[ForwarderDefs.statGateInfoReplies];
    Text[", Alto Time: "L];
    LD[PupTimeServer.GetAltoTimeRequests[]];
    CR[];
    Text["Name=>Address: "L];
    LDS[NameServerDefs.statName];
    Text[", Address=>Name: "L];
    LDS[NameServerDefs.statAddress];
    Text[", 48=>8: "L];
    LDS[NameServerDefs.statXlation];
    CR[];
    DoSomeYields[];
    BEGIN
    version: CARDINAL;
    inTransit: BOOLEAN;
    Text["Directory version: "L];
    [version, inTransit] ← NameServerDefs.GetOldDirectoryVersion[];
    D[version];
    IF inTransit THEN Text["(In Transit)"L];
    [version, inTransit] ← NameServerDefs.GetNewDirectoryVersion[];
    Text["/"L];
    D[version];
    END;
    BEGIN
    info: ARRAY BufferOps.Statistics OF CARDINAL ← BufferOps.GetStatistics[];
    Text[", Buffers: "L];
    D[info[available]];
    Text["/"L];
    D[info[allocated]];
    Text["/"L];
    D[info[requested]];
    END;
    CR[];
    DoSomeYields[];
    PrintMaybe["Pup Network Directories sent"L, NameServerDefs.statSend];
    CR[];
    DoSomeYields[];
    IF packets # NIL THEN PrintPacketsForwarded[];
    CR[];
    DoSomeYields[];
    IF bytes # NIL THEN PrintBytesForwarded[];
    DoSomeYields[];
    END;

  PutHeader: PROCEDURE [wh: Window.Handle, s: LONG STRING, cr: BOOLEAN ← TRUE] =
    BEGIN
    Put.CR[wh];
    Put.Date[wh, Time.Current[], dateTime];
    Put.Text[wh, "  "L];
    Put.Text[wh, s];
    IF cr THEN Put.CR[wh];
    END;

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


  Commands: PROC [index: CARDINAL] =
    BEGIN
    Push: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] =
      BEGIN Put.Line[NIL, s]; END;
    SELECT index FROM
      0 =>
        BEGIN
        OthelloDefs.MyNameIs[
	  myNameIs: "Gate Info"L,
	  myHelpIs: "Print Pup Gateway Forwarding Matrix"L];
	PrintGateStats[NIL];
	END;
      1 =>
        BEGIN
        OthelloDefs.MyNameIs[
	  myNameIs: "Stats Recent"L,
	  myHelpIs: "Print Statistics accumulated since the last time they were printed"L];
	Stats.StatSince[Push];
	END;
      2 =>
        BEGIN
        OthelloDefs.MyNameIs[
	  myNameIs: "Stats Totals"L,
	  myHelpIs: "Print Statistics accumulated since we were booted"L];
	Stats.StatPrintCurrent[Push];
	END;
      ENDCASE => OthelloDefs.IndexTooLarge;
    END;
   
  -- Initialization
  commandProcessor: OthelloDefs.CommandProcessor ← [Commands];
  [packets, bytes, nets] ← ForwarderDefs.GetPointerToPupGateStats[];
  bad ← ForwarderDefs.GetPointerToBadPupStats[];
  OthelloDefs.RegisterCommandProc[@commandProcessor];
  END.