-- Copyright (C) 1984  by Xerox Corporation. All rights reserved. 
-- TestTranslation.mesa, HGM,  4-Nov-84  8:57:31

DIRECTORY
  AddressTranslation USING [Error, PrintError, StringToNetworkAddress],
  Format USING [HostNumber, StringProc],
  FormSW USING [
    AllocateItemDescriptor, ClientItemsProcType, CommandItem, ItemHandle, newLine,
    ProcType, StringItem],
  Heap USING [systemZone],
  MsgSW USING [Post],
  Put USING [Char, CR, Line, NetworkAddress, Text],
  Runtime USING [GetBcdTime],
  SpecialSystem USING [GetProcessorID],
  String USING [AppendString],
  System USING [HostNumber, NetworkAddress, nullSocketNumber, SocketNumber],
  Time USING [Append, Unpack],
  Tool USING [
    Create, UnusedLogName, MakeFormSW, MakeFileSW, MakeMsgSW, MakeSWsProc],
  ToolWindow USING [TransitionProcType],
  Unformat USING [Error, HostNumber, NetworkAddress],
  Window USING [Handle],

  Buffer USING [NSBuffer],
  NSTypes USING [],
  NSConstants USING [pupAddressTranslation],
  PupDefs USING [AppendPupAddress, PupAddress],
  Socket USING [
    AssignNetworkAddress, BroadcastAddressFromSocket, ChannelHandle, Create,
    Delete, GetPacket, GetPacketBytes, GetSendBuffer, GetSource, PutPacket,
    ReturnBuffer, SetDestination, SetPacketWords, SetWaitTime, TimeOut];

TestTranslation: PROGRAM
  IMPORTS
    AddressTranslation, Format, FormSW, Heap, MsgSW, Put,
    Runtime, SpecialSystem, String, Time, Tool, Unformat,
    Socket, PupDefs =
  BEGIN

  z: UNCOUNTED ZONE = Heap.systemZone;

  -- From PupAddressTranslationServer.mesa
  translationRequest: CARDINAL = 1;
  translationResponse: CARDINAL = 2;
  translationError: CARDINAL = 3;

  -- global variable declarations
  msg, log, form: Window.Handle ← NIL;
  machine, server: LONG STRING ← NIL;
  localAddr: System.NetworkAddress;

  Init: PROCEDURE =
    BEGIN
    herald: STRING = [100];
    String.AppendString[herald, "TestTranslation of  "L];
    Time.Append[herald, Time.Unpack[Runtime.GetBcdTime[]]];
    [] ← Tool.Create[
      name: herald, makeSWsProc: MakeSWs, clientTransition: Transition];
    END;

  MakeSWs: Tool.MakeSWsProc =
    BEGIN
    logFileName: STRING = [40];
    msg ← Tool.MakeMsgSW[window: window, lines: 1];
    form ← Tool.MakeFormSW[window: window, formProc: MakeItemArray];
    Tool.UnusedLogName[logFileName, "TestTranslation.log$"L];
    log ← Tool.MakeFileSW[window: window, name: logFileName];
    END;

  MakeItemArray: FormSW.ClientItemsProcType =
    BEGIN
    nItems: CARDINAL = 4;
    i: INTEGER ← -1;
    items ← FormSW.AllocateItemDescriptor[nItems];
    items[i ← i + 1] ← FormSW.CommandItem[
      tag: "LocalBroadcast"L, place: FormSW.newLine, proc: LocalBroadcast];
    items[i ← i + 1] ← FormSW.CommandItem[tag: "AskRemote"L, proc: AskRemote];
    items[i ← i + 1] ← FormSW.StringItem[tag: "Server"L, string: @server, inHeap: TRUE];
    items[i ← i + 1] ← FormSW.StringItem[
      tag: "Machine"L, string: @machine, place: FormSW.newLine, inHeap: TRUE];
    IF (i + 1) # nItems THEN ERROR;
    RETURN[items, TRUE];
    END;

  Transition: ToolWindow.TransitionProcType =
    BEGIN
    SELECT TRUE FROM
      old = inactive =>
        BEGIN
        AppendMe: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] =
          BEGIN String.AppendString[machine, s]; END;
        localAddr ← Socket.AssignNetworkAddress[];
        server ← z.NEW[StringBody[40]];
        String.AppendString[server, "0#*#"L];
        machine ← z.NEW[StringBody[40]];
        Format.HostNumber[AppendMe, LOOPHOLE[SpecialSystem.GetProcessorID[]], octal];
        END;
      new = inactive =>
        BEGIN
	z.FREE[@server];
	z.FREE[@machine];
	END;
      ENDCASE;
    END;

  LocalBroadcast: FormSW.ProcType =
    BEGIN
    him: System.NetworkAddress;
    who: System.HostNumber;
    soc: Socket.ChannelHandle;
    where: LONG POINTER TO System.HostNumber;
    b: Buffer.NSBuffer;
    errFlag, hit: BOOLEAN ← FALSE;

    MsgSW.Post[msg, ""L];
    who ← Unformat.HostNumber[machine !
      Unformat.Error =>
        BEGIN
	Put.Line[msg, "Can't parse Machine"L];
        errFlag ← TRUE;
        CONTINUE;
        END];
    IF errFlag THEN RETURN;
    MsgSW.Post[msg, "Here we go...."L];

    soc ← Socket.Create[local: localAddr, receive: 10];
    Socket.SetWaitTime[soc, 500];  -- milli-seconds
    him ← Socket.BroadcastAddressFromSocket[NSConstants.pupAddressTranslation];

    FOR i: CARDINAL IN [0..10) UNTIL hit DO
      b ← Socket.GetSendBuffer[soc];
      Socket.SetDestination[b, him];
      b.ns.packetType ← pupAddrTransPacket;
      b.ns.nsWords[0] ← b.ns.nsWords[1] ← i;
      b.ns.nsWords[2] ← translationRequest;
      Socket.SetPacketWords[b, 3 + SIZE[System.HostNumber]];
      where ← LOOPHOLE[@b.ns.nsWords[3]];
      where↑ ← who;
      Socket.PutPacket[soc, b];
      DO
        b ← Socket.GetPacket[
          soc ! Socket.TimeOut => BEGIN IF ~hit THEN Put.Char[log, '?]; EXIT; END];
        IF him # Socket.GetSource[b] THEN
          BEGIN
          Put.Text[log, "Response from: "L];
          Put.NetworkAddress[log, Socket.GetSource[b], octal];
          Put.Line[log, NIL];
          END;
        SELECT TRUE FROM
          (b.ns.nsWords[2] = translationError) =>
            BEGIN
            n: CARDINAL ← Socket.GetPacketBytes[b];
            text: LONG POINTER TO PACKED ARRAY [0..0) OF CHARACTER;
            text ← LOOPHOLE[@b.ns.nsWords[0]];
            FOR i: CARDINAL IN [6..n) DO Put.Char[log, text[i]]; ENDLOOP;
            Put.CR[log];
            END;
          Socket.GetPacketBytes[b] # 2*(3 + SIZE[PupDefs.PupAddress])
            OR (b.ns.nsWords[2] # translationResponse) =>
            BEGIN Put.Char[log, '#]; END;
          ENDCASE =>
            BEGIN  -- the response we were looking for
            temp: STRING = [50];
            answer: LONG POINTER TO PupDefs.PupAddress;
            answer ← LOOPHOLE[@b.ns.nsWords[3]];
            hit ← TRUE;
            Put.Text[log, "Answer: "L];
            PupDefs.AppendPupAddress[temp, answer↑];
            Put.Line[log, temp];
            Put.CR[log];
            END;
        Socket.ReturnBuffer[b];
        ENDLOOP;
      ENDLOOP;
    Put.CR[log];
    Socket.Delete[soc];
    MsgSW.Post[msg, ""L];
    END;

  AskRemote: FormSW.ProcType =
    BEGIN
    him: System.NetworkAddress;
    who: System.HostNumber;
    soc: Socket.ChannelHandle;
    where: LONG POINTER TO System.HostNumber;
    b: Buffer.NSBuffer;
    errFlag, hit: BOOLEAN ← FALSE;

    MsgSW.Post[msg, ""L];
    him ← GetAddress[server, NSConstants.pupAddressTranslation !
      Trouble =>
        BEGIN
	Put.Line[msg, reason];
        errFlag ← TRUE;
        CONTINUE;
        END];
    who ← Unformat.HostNumber[machine !
      Unformat.Error =>
        BEGIN
	Put.Line[msg, "Can't parse Machine"L];
        errFlag ← TRUE;
        CONTINUE;
        END];
    IF errFlag THEN RETURN;
    MsgSW.Post[msg, "Here we go...."L];

    soc ← Socket.Create[local: localAddr, receive: 10];
    Socket.SetWaitTime[soc, 5000];  -- milli-seconds

    FOR i: CARDINAL IN [0..10) UNTIL hit DO
      b ← Socket.GetSendBuffer[soc];
      Socket.SetDestination[b, him];
      b.ns.packetType ← pupAddrTransPacket;
      b.ns.nsWords[0] ← b.ns.nsWords[1] ← i;
      b.ns.nsWords[2] ← translationRequest;
      Socket.SetPacketWords[b, 3 + SIZE[System.HostNumber]];
      where ← LOOPHOLE[@b.ns.nsWords[3]];
      where↑ ← who;
      Socket.PutPacket[soc, b];
      DO
        b ← Socket.GetPacket[
          soc ! Socket.TimeOut => BEGIN IF ~hit THEN Put.Char[log, '?]; EXIT; END];
        IF him # Socket.GetSource[b] THEN
          BEGIN
          Put.Text[log, "Response from: "L];
          Put.NetworkAddress[log, Socket.GetSource[b], octal];
          Put.Line[log, NIL];
          END;
        SELECT TRUE FROM
          (b.ns.nsWords[2] = translationError) =>
            BEGIN
            n: CARDINAL ← Socket.GetPacketBytes[b];
            text: LONG POINTER TO PACKED ARRAY [0..0) OF CHARACTER;
            text ← LOOPHOLE[@b.ns.nsWords[0]];
            FOR i: CARDINAL IN [6..n) DO Put.Char[log, text[i]]; ENDLOOP;
            Put.CR[log];
            END;
          Socket.GetPacketBytes[b] # 2*(3 + SIZE[PupDefs.PupAddress])
            OR (b.ns.nsWords[2] # translationResponse) =>
            BEGIN Put.Char[log, '#]; END;
          ENDCASE =>
            BEGIN  -- the response we were looking for
            temp: STRING = [50];
            answer: LONG POINTER TO PupDefs.PupAddress;
            answer ← LOOPHOLE[@b.ns.nsWords[3]];
            hit ← TRUE;
            Put.Text[log, "Answer: "L];
            PupDefs.AppendPupAddress[temp, answer↑];
            Put.Line[log, temp];
            Put.CR[log];
            END;
        Socket.ReturnBuffer[b];
        ENDLOOP;
      ENDLOOP;
    Put.CR[log];
    Socket.Delete[soc];
    MsgSW.Post[msg, ""L];
    END;

  Trouble: ERROR [reason: LONG STRING] = CODE;
  GetAddress: PROCEDURE [host: LONG STRING, socket: System.SocketNumber]
    RETURNS [addr: System.NetworkAddress] =
    BEGIN
    localFailed: BOOLEAN ← FALSE;
    IF host = NIL THEN ERROR Trouble["NIL => Address Fault"L];
    addr ← Unformat.NetworkAddress[host, octal !
      Unformat.Error => BEGIN localFailed ← TRUE; CONTINUE; END ];
    IF localFailed THEN
      BEGIN
      addr ← AddressTranslation.StringToNetworkAddress[host !
        AddressTranslation.Error =>
	  BEGIN
	  temp: STRING = [200];
	  proc: Format.StringProc = {String.AppendString[temp, s]};
	  AddressTranslation.PrintError[errorRecord, proc];
	  ERROR Trouble[temp];
	  END].addr;
        addr.socket ← socket;  -- CH returns trash in socket
      END;
    IF addr.socket = System.nullSocketNumber THEN addr.socket ← socket;
    END;

  Init[];  -- this gets string out of global frame
  END...