-- ClientMapImpl.mesa
-- Last edited by
--   MBrown on February 2, 1984 11:15:20 am PST

  DIRECTORY
    AlpineEnvironment USING [Conversation, Principal],
    Rope USING [IsEmpty],
    RPC USING [ConversationID, GetCaller, GetConversationID],
    ClientMap USING [];

ClientMapImpl: MONITOR
  IMPORTS
    Rope,
    RPC
  EXPORTS
    ClientMap =
  BEGIN
  Conversation: TYPE = AlpineEnvironment.Conversation;
  Principal: TYPE = AlpineEnvironment.Principal;

  ConversationPrincipal: TYPE = RECORD [
    conv: RPC.ConversationID,
    prin: Principal ← NIL];

  registeredPrincipalList: LIST OF ConversationPrincipal ← NIL;

  Register: PUBLIC ENTRY PROC [conversation: Conversation, principal: Principal] = {
    IF RPC.GetCaller[conversation].IsEmpty THEN {
      l: LIST OF ConversationPrincipal ← GetRegisteredName[conversation];
      IF l = NIL THEN {
        l ← CONS[
          first: [conv: RPC.GetConversationID[conversation]], rest: registeredPrincipalList];
        registeredPrincipalList ← l;
        };
      l.first.prin ← principal;
      };
    };

  Unregister: PUBLIC ENTRY PROC [conversation: Conversation] = {
    l: LIST OF ConversationPrincipal ← GetRegisteredName[conversation];
    IF l = NIL THEN RETURN;
    RemoveRegisteredName[l];
    };

  GetName: PUBLIC ENTRY PROC [conversation: Conversation]
    RETURNS [principal: Principal] = {
    l: LIST OF ConversationPrincipal;
    IF NOT (principal ← RPC.GetCaller[conversation]).IsEmpty THEN RETURN [principal];
    RETURN[IF (l ← GetRegisteredName[conversation]) # NIL THEN l.first.prin ELSE NIL];
    };

  GetRegisteredName: INTERNAL PROC [conversation: Conversation]
    RETURNS [LIST OF ConversationPrincipal] = {
    conversationID: RPC.ConversationID = RPC.GetConversationID[conversation];
    FOR l: LIST OF ConversationPrincipal ← registeredPrincipalList, l.rest
     UNTIL l = NIL DO
      IF l.first.conv = conversationID THEN RETURN [l];
      ENDLOOP;
    RETURN [NIL] };

  RemoveRegisteredName: INTERNAL PROC [r: LIST OF ConversationPrincipal] = {
    IF r = registeredPrincipalList THEN {
      registeredPrincipalList ← registeredPrincipalList.rest;
      RETURN };
    FOR l: LIST OF ConversationPrincipal ← registeredPrincipalList, l.rest DO
      IF l.rest = r THEN { l.rest ← r.rest; RETURN };
      ENDLOOP;
    };

  END.