//     $Id: Connections.java,v 3.3 1998/12/09 20:06:38 mk2z Exp $    
 ////////////////////////////////////////////////////////////////////////////
 //
 // File: Connections.java
 //
 // Purpose: Used to track all connections in ServerRMI. Passed to DemonRMI,
 //        then DemonEngine.
 //
 // Authors:
 //   Orim  Miro Kresonja    mk2z@virginia.edu
 //
 // Modifications:
 //
 //   17-NOV-1998  Orim  Initial creation
 //   02-DEC-1998  Orim  Support for Version 4.0 (Disconn.)
 //
 ////////////////////////////////////////////////////////////////////////////
 
 import java.util.Random;
 
 public class Connections
     extends ClientConnectStatus
     implements java.io.Serializable {
 
   private final static int FAILED = 0; // failed registration
   private static Random random = new Random();
 
   private ClientRMIIface[] client_table = null; // client iface table
   private DemonRMIIface[] demon_table   = null; // demon  iface table
   private int[] client_passwords  = null;
   private int[] demon_passwords   = null;
   private boolean[] demon_connected = null;
   private int exp_demons=0;
 
   ///////////////////////////////////////////////////////////////////
   //
   // Connections  [constructor] - This creates a new Connections 
   // object, initializes all relevant data.
   //   
   ///////////////////////////////////////////////////////////////////
   
   public Connections (int exp_clients, int exp_demons) 
   throws Exception {
     // call the superclass constructor to init all its data
     super();
     SetNumClients(exp_clients);
     SetNumDemons(exp_demons);
 
     // instantiate the data space for table
     client_table = new ClientRMIIface[exp_clients];
     client_passwords = new int[exp_clients];
 
     demon_table = new DemonRMIIface[exp_demons];
     demon_passwords = new int[exp_demons];
 
     demon_connected = new boolean[exp_demons];
     for (int i=0; i<exp_demons; ++i) {
         SetDemonConnStatus(i, false);
     }
   }
   
   ///////////////////////////////////////////////////////////////////
   //
   // AddClient - if the client's id is OK, then add all data, return 
   // its random number, otherwise return false.
   //
   ///////////////////////////////////////////////////////////////////
   
   public int AddClient (int index, ClientRMIIface obj) 
   throws BoundsException {
 
     if (GetClientConnStatus(index) == false) {
         SetClientConnStatus(index, true);
 
         // assign the new client a uniquely random number
         int new_pass = UniqueRandom(client_passwords, GetNumClients());
         client_passwords[index] = new_pass;
 
         // remember the actual inteface (pointer)
         client_table[index]=obj;
         return(new_pass);
     }
     return(FAILED);
   }
 
   ///////////////////////////////////////////////////////////////////
   //
   // RemoveClient - if the client is there, then remove it, and its
   // binding and iface information.
   //   
   ///////////////////////////////////////////////////////////////////
   
   public boolean RemoveClient (int index, int password)
   throws Exception {
 
     if (GetClientConnStatus(index) && password == client_passwords[index]) {
         SetClientConnStatus(index, false);
         client_table[index]=null;
         client_passwords[index]=FAILED;
         return(true);
     }
     return(false);
   }
   
   ///////////////////////////////////////////////////////////////////
   //
   // AddDemon - if the demon's iface is OK, then add its info. Can
   // only be invoked once.
   //   
   ///////////////////////////////////////////////////////////////////
 
   public int AddDemon (int index, DemonRMIIface obj)
   throws Exception {
 
     if (GetDemonConnStatus(index) == false) {
         SetDemonConnStatus(index, true);
 
         // assign the new demon a uniquely random number
         int new_pass = UniqueRandom(demon_passwords, GetNumDemons());
         demon_passwords[index] = new_pass;
 
         // remember the actual inteface (pointer)
         demon_table[index] = obj;
         return(new_pass);
     }
     return(FAILED);
     
   }
 
   ///////////////////////////////////////////////////////////////////
   //
   // RemoveDemon - The Demon has been shut down. 
   //   
   ///////////////////////////////////////////////////////////////////
 
   public boolean RemoveDemon (int index, int password)
   throws Exception {
 
     if (GetDemonConnStatus(index) && password == demon_passwords[index]) {
         SetDemonConnStatus(index, false);
         demon_table[index]=null;
         demon_passwords[index]=FAILED;
         return(true);
     }
     return(false);
   }
 
   ///////////////////////////////////////////////////////////////////
   //
   // SetAllSubmitFalse - at either the beginning of a new run, or 
   // the end of the old run, set all submittedstats to false.
   //   
   ///////////////////////////////////////////////////////////////////
   
   public void SetAllSubmitFalse ()
   throws Exception {
 
     int num_exp = GetNumClients();
     for (int i = 0; i<num_exp; ++i) {
         SetClientSubStatus(i, false);
     }
   }
 
   ///////////////////////////////////////////////////////////////////
   //
   // GetClientIface - if the client has registered, this returns its
   // interface. If not, a null is returned instead.
   //   
   ///////////////////////////////////////////////////////////////////
   
   public ClientRMIIface GetClientIface (int index)
     throws BoundsException {
 
     if (GetClientConnStatus(index)) {
         return(client_table[index]);
     }
     else {
         return(null);
     }
 
   }
 
   ///////////////////////////////////////////////////////////////////
   //
   // GetDemonIface - if the demon has registered, this returns its
   // interface. If not, a null is returned instead.
   //   
   ///////////////////////////////////////////////////////////////////
   
   public DemonRMIIface GetDemonIface (int index)
     throws BoundsException {
 
     if (GetDemonConnStatus(index)) {
         return(demon_table[index]);
     }
     else {
         return(null);
     }
 
   }
 
   ///////////////////////////////////////////////////////////////////
   //
   // GetDemonConnStatus - if the demon has registered, this 
   // returns a true. Otherwise, false.
   //   
   ///////////////////////////////////////////////////////////////////
   
   public boolean GetDemonConnStatus (int index) {
     return(demon_connected[index]);
   }
 
   ///////////////////////////////////////////////////////////////////
   //
   // SetDemonConnStatus - sets the status of demon connection to
   // either true or false.
   //   
   ///////////////////////////////////////////////////////////////////
   
   public void SetDemonConnStatus (int index, boolean status) {
     demon_connected[index]=status;
   }
 
   ///////////////////////////////////////////////////////////////////
   //
   // SetNumDemons - sets the number of expected demons 
   //   
   ///////////////////////////////////////////////////////////////////
   
   public void SetNumDemons(int number) {
     exp_demons=number;
   }
 
   ///////////////////////////////////////////////////////////////////
   //
   // GetNumDemons - returns the number of expected demons 
   //   
   ///////////////////////////////////////////////////////////////////
   
   public int GetNumDemons() {
     return(exp_demons);
   }
 
   ///////////////////////////////////////////////////////////////////
   //
   // UniqueRandom - gets passed a list of ints and a size of the list.
   // The routine will pick a unique random integer not already in the
   // list.
   //   
   ///////////////////////////////////////////////////////////////////
 
   public int UniqueRandom (int[] list, int listsize) {
     boolean IsPicked = false;
     int temp_num = FAILED;
 
     while (!IsPicked) {
        while ( (temp_num=Math.abs (random.nextInt()) ) == FAILED);
        IsPicked=true;
        for (int i=0; i<listsize; ++i) {
         if (list[i]==temp_num) {
            IsPicked=false;
         }
        }
     }
     return(temp_num);
   }    
 }