public class CommPeer {
  public static boolean         DEBUG         = false;

  /** Accessor to the communicator */
  public Communicator getCommunicator () {return comm;}

  //---------------------------------------------------------------------------
  // Call this to turn off Communicator and KQMLMessage specific debug
  // messages.
  //---------------------------------------------------------------------------
  public void setDebugFlags () {

  //---------------------------------------------------------------------------
  // Detects the hostname for the program, sets HOST to it, and returns it to
  // the caller.
  //---------------------------------------------------------------------------
  public static String detectHost () {

  //---------------------------------------------------------------------------
  //                        Instantiate Instance ID
  //
  // Make an instance of the ID string which will uniquely identify this to the
  // the ANS.
  // Note:
  // 1. Do not use colons as delimiters since "Connection.sendMsg" uses them
  //    to identify a field name.
  // 2. Do not use periods (".") in agent names, as the ANS parses that which
  //    is to the right as a domain name.
  // Hostname precedence:
  // First, use what was specified with the "-Dhost=" argument to "java".
  //      Example:  java -Dhost=pleiades AirResourceMgr &
  //      Example:  java -Dhost=$HOST AirResourceMgr &
  // Second, try to determine the hostname automatically.  Rumor has it that
  //      for some systems this will return "localhost" instead of the real
  //      internet hostname, but that has yet to be verified.
  // Third, if unable to determine hostname from InetAddress, use the
  //      default, which should be "localhost".
  //
  // This version allows the caller to reuse the same "creation_time" so as to
  // identify thread descendants.
  //
  // instance_count:  A short number which identifies the application thread.
  //    If this class is single-threaded, this value should remain 0.
  //---------------------------------------------------------------------------
  public static String makeInstanceID (String appl_prefix, long creation_time,
                                       short instance_count) {

  //---------------------------------------------------------------------------
  // A version of makeInstanceID that generates a unique timestamp for every
  // call.
  //---------------------------------------------------------------------------
  public static String makeInstanceID (String appl_prefix, short inst_count) {

  //---------------------------------------------------------------------------
  //                 The Main CommPeer Constructor Method
  //
  // This method should be modified to throw an exception.  For now just return
  // "null" instead.
  //---------------------------------------------------------------------------
  public CommPeer (String caller_host, String caller_ID, int preferred_port,
                   String agentInfo, MsgLogInterface logFacilityList[],
                   String ANShost, Integer ANSport) {

  //---------------------------------------------------------------------------
  //                         CommPeer Constructor
  //
  // A variant of the main constructor that lets the caller specify its host,
  // caller_ID, and port.  It does not allow for the specification of
  // ANS information.
  //---------------------------------------------------------------------------
  public CommPeer (String caller_host, String caller_ID, int preferred_port,
                   String agentInfo, MsgLogInterface logFacilityList[]) {

  //---------------------------------------------------------------------------
  //                         CommPeer Constructor
  //
  // A variant of the main constructor that lets the caller specify its host,
  // caller_ID, and port.  It does not allow for the specification of a message
  // log facility.
  //---------------------------------------------------------------------------
  public CommPeer (String caller_host, String caller_ID, int preferred_port,
                   String ANShost, Integer ANSport) {

  //---------------------------------------------------------------------------
  //                         CommPeer Constructor
  //
  // A variant of the main constructor that lets the caller specify its host,
  // caller_ID, and port.  It does not allow for the specification of a message
  // log facility.
  //---------------------------------------------------------------------------
  public CommPeer (String caller_host, String caller_ID, int preferred_port,
                   String ANShost, Integer ANSport) {

  //---------------------------------------------------------------------------
  //                         CommPeer Constructor
  //
  // A variant of the main constructor that lets the caller specify its host,
  // caller_ID, and port.  It does not allow for the specification of a message
  // log facility, or ANS information.
  //---------------------------------------------------------------------------
  public CommPeer (String caller_host, String caller_ID, int preferred_port) {

  //---------------------------------------------------------------------------
  //                         CommPeer Constructor
  //
  // A variant of the main constructor that lets the Communicator assign the
  // port by default.  It does not allow for the specification of a message log
  // facility.
  //---------------------------------------------------------------------------
  public CommPeer (String caller_host, String caller_ID, 
                   String ANShost, Integer ANSport) {

  //---------------------------------------------------------------------------
  //                         CommPeer Constructor
  //
  // A variant of the main constructor that lets the Communicator assign the
  // port by default.  It does not allow for the specification of a message log
  // facility or ANS information.
  //---------------------------------------------------------------------------
  public CommPeer (String caller_host, String caller_ID) {

  //---------------------------------------------------------------------------
  //                         CommPeer Constructor
  //
  // A variant of the main constructor that lets the Communicator assign the
  // caller_host and the port by default.  It does not allow for the
  // specification of a message log facility.
  //---------------------------------------------------------------------------
  public CommPeer (String caller_ID, String ANShost, Integer ANSport) {

  //---------------------------------------------------------------------------
  //                         CommPeer Constructor
  //
  // A variant of the main constructor that lets the Communicator assign the
  // caller_host and the port by default.  It does not allow for the
  // specification of a message log facility, or ANS information.
  //---------------------------------------------------------------------------
  public CommPeer (String caller_ID) {

  //---------------------------------------------------------------------------
  //                         CommPeer Constructor
  //
  // A variant of the main constructor that assigns a port by default and
  // permits the caller to specify a message log facility.
  //---------------------------------------------------------------------------
  public CommPeer (String caller_host, String caller_ID, String agentInfo,
                   MsgLogInterface logFacilityList[], 
                   String ANShost, Integer ANSport) {

  //---------------------------------------------------------------------------
  //                         CommPeer Constructor
  //
  // A variant of the main constructor that assigns a port by default and
  // permits the caller to specify a message log facility, or ANS information.
  //---------------------------------------------------------------------------
  public CommPeer (String caller_host, String caller_ID, String agentInfo,
                   MsgLogInterface logFacilityList[]) {
    this (caller_host, caller_ID, DEFAULT_PORT, agentInfo, logFacilityList,

  //---------------------------------------------------------------------------
  //                         CommPeer Constructor
  //
  // A variant of the main constructor that assigns the caller_host and the
  // port by default, and permits the caller to specify a message log facility.
  //---------------------------------------------------------------------------
  public CommPeer (String caller_ID, String agentInfo,
                   MsgLogInterface logFacilityList[], 
                   String ANShost, Integer ANSport) {

  //---------------------------------------------------------------------------
  //                         CommPeer Constructor
  //
  // A variant of the main constructor that assigns the caller_host and the
  // port by default, and permits the caller to specify a message log facility,
  // or ANS information.
  //---------------------------------------------------------------------------
  public CommPeer (String caller_ID, String agentInfo,
                   MsgLogInterface logFacilityList[]) {

  //---------------------------------------------------------------------------
  //                         CommPeer Constructor
  //
  // A variant of the main constructor that is used when the communicator 
  // is available.  For instance, the communicator is available to the 
  // code of the actions of retsina agents.  This constructor allows 
  // CommPeer to be used by those actions.
  //---------------------------------------------------------------------------
  public CommPeer (Communicator comm) {

  //---------------------------------------------------------------------------
  // Attempt to return the ConnectionDescriptor identified by "agentName".
  // Will return 'null' if the ConnectionDescriptor cannot be found.
  //---------------------------------------------------------------------------
  public ConnectionDescriptor getCD (String agentName) {

  //==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==.
  //                        Message Passing Methods
  //==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==.


  //---------------------------------------------------------------------------
  //                 Send Message To (, )
  //
  // Example:  CommPeer.Send_Msg_To ("caps", capsMsg);
  // agent:
  //    The same name specified by ":AgentName" in the agent's ".config" file.
  // message:
  //    The message to be sent to the agent, in string format, similar to the
  //    examples declared in the ".ob.gin" file for that agent.
  //    N.B.:  it may be advantageous to prepare this string with
  //    "makeKQMLMsgContentString()".
  //
  //---------------------------------------------------------------------------
  public void Send_Msg_To (String agentName, String message) {

  /** send message to the agent named agentName, on a specific connection
    * @param agentName the name of the receiver
    * @param message the message sent
    * @param tempCD the connection descriptor that specifies the connection to use
    */
  public void Send_Msg_To (String agentName, String message, 
                           ConnectionDescriptor tempCD) {

  //---------------------------------------------------------------------------
  //         Send Message To (, , , , 
  //                          ,  , )
  //
  // Example:  CommPeer.Send_Msg_To ("caps", capsMsg, KQMLmessage.REPLY_KEY);
  //                                        
  // Note, we use misc.KQMLParser.UtilMsgMethods.createInternKQMLMsg
  // to build the message to send.  Thus is some args are null, they
  // will be filled in by that method with appropriate defaults.
  //
  // agent:
  //    The same name specified by ":AgentName" in the agent's ".config" file.
  // message:
  //    The message to be sent to the agent, in string format, similar to the
  //    examples declared in the ".ob.gin" file for that agent.
  //    N.B.:  it may be advantageous to prepare this string with
  //    "makeKQMLMsgContentString()".
  // performative:
  //    Any legal performative.  For best and safe results, use those defined
  //    by "KQMLmessage".  (4/13/2000 SRO - I couldn't find any KQMLmessage class 
  //    that listed performatives.  Perhaps meant the performatives listed in 
  //    softagents.misc.KQMLParser.UtilMsgMethods.)
  // ontology:
  //    Ontology of the message, i.e. default-ontology, matchmaker, etc.
  // language:
  //    language of the message, i.e. gin_v0.01, simple-query, etc.
  // replyTo:
  //    the reply-with field of the message we are replying to, if any. 
  // replyWith:
  //    the tag we wish the receiver to use in 'replyTo' to respond to this 
  //    message.
  //
  //---------------------------------------------------------------------------
  public void Send_Msg_To (String agentName, String message, String perf, String ontology, String language, String replyTo, String replyWith) {

  //---------------------------------------------------------------------------
  //         Send Message To (, , )
  //
  // Example:  CommPeer.Send_Msg_To ("caps", capsMsg, KQMLmessage.REPLY_KEY);
  //                                        
  // agent:
  //    The same name specified by ":AgentName" in the agent's ".config" file.
  // message:
  //    The message to be sent to the agent, in string format, similar to the
  //    examples declared in the ".ob.gin" file for that agent.
  //    N.B.:  it may be advantageous to prepare this string with
  //    "makeKQMLMsgContentString()".
  // performative:
  //    Any legal performative.  For best and safe results, use those defined
  //    by "KQMLmessage".
  //---------------------------------------------------------------------------
  public void Send_Msg_To (String agentName, String message, String perf) {

  //---------------------------------------------------------------------------
  // Use this method if you already prepared your own instance of
  // InternalKQMLmessage.
  //---------------------------------------------------------------------------
  public void Send_Msg_To (String agentName, InternalKQMLmessage ikm) {

  //---------------------------------------------------------------------------
  //                   Get_Reply_From (agentName, ikm_p)
  //
  // agentName:
  //    The name of the agent from which you would like to receive a reply.
  //
  // ikm_p:
  //    A dummy argument used to work-around the Java compiler restriction that
  //    you cannot have same-name methods with the same number of arguments
  //    return different data types.  If they have a different number of
  //    arguments, then they may return different data types.
  //
  // Use this method ONLY if you have already initiated a connection to
  // "agentName" via "Send_Msg_To()".
  //---------------------------------------------------------------------------
  public InternalKQMLmessage Get_Reply_From (String agentName, boolean ikm_p) {

  //---------------------------------------------------------------------------
  //                      Get_Reply_From (agentName)
  //
  // agentName:
  //    The same name specified by ":AgentName" in the agent's ".config" file.
  //
  // Use this method ONLY if you have already initiated a connection to
  // "agentName" via "Send_Msg_To()".
  //---------------------------------------------------------------------------
  public String Get_Reply_From (String agentName) {

  //==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==.
  //                          Server Mode Methods
  //
  // The the application using CommPeer sits and waits for somebody to send a
  // message to it, then it is using CommPeer in "Server Mode".
  //
  // In this section there are four Server Mode methods.  Two of them,
  // "blockUntilActivated()", were implemented for the side-effect of having an
  // application block until somebody sends a message to it.  See their
  // comments for more details.
  // The other two ... were implemented for having an outside application
  // initiate the communication and for the communication between the two peers
  // to continue.
  //==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==.


  //---------------------------------------------------------------------------
  // Motivation:  Marios Savvid's MoDSAFMapRecognizer would like to block its
  // load action until he receives a message from an enabling program.  He does
  // not care what the message it, all he is concerned about is the blocking
  // behavior as a means of remotely controlling thread execution.  
  // This method implements such behavior.
  // There is no need to establish a connection with a remote agent.  This
  // method will unblock for any message sent to this client.
  //---------------------------------------------------------------------------
  public void blockUntilActivated () {

  //---------------------------------------------------------------------------
  // A version of "blockUntilActivated()" that returns "msg" to its caller as a
  // confirmation.
  //---------------------------------------------------------------------------
  public void blockUntilActivated (String msg) {

  //---------------------------------------------------------------------------
  // Block and wait for a connection.  Once received, discover who initiated
  // it, add the ConnectionDescriptor to the CD_Table, and return the string
  // identifying the remote client.  "closeConnection()" may be called on this
  // new ConnectionDescriptor, but that connection will not be closed since
  // the CommPeer in Server Mode does not own it.
  //
  // If the remote entity initiates multiple connections on different ports (as
  // KQMLMessageSenderGUI does), there are two possible actions:
  // 1. Update the CD_Table entry for "Entity" by overwriting its descriptor.
  //    This action is effected by setting "ignore_multiple_CDs" to `false'.
  //    or
  // 2. Ignore the new ConnectionDescriptor and continue to use the old one.
  //    This action is effected by setting "ignore_multiple_CDs" to `true'.
  //---------------------------------------------------------------------------
  public String waitForConnection (boolean ignore_multiple_CDs) {

  //---------------------------------------------------------------------------
  // A client should be able to send messages to the connection owner
  // regardless of "ignore_multiple_CDs".  Use this method if you do not care.
  // This method calls its sibling method with "ignore_multiple_CDs" set to
  // `true'.
  //---------------------------------------------------------------------------
  public String waitForConnection () {

  //---------------------------------------------------------------------------
  //                         waitForIMConnection()
  //
  // A server-mode method which waits for an incoming message and returns it in
  // InternalMsg format.  Motivated by the Retsina/OAA Interoperator.
  //
  // 1. Block and wait for a connection.
  // 2. Once a connection is received, discover who initiated it, add the
  //    ConnectionDescriptor to the "CD_Table", and return the "InternalMsg" of
  //    the connecting request.
  // 3. Since the ConnectionDescriptor is registered with the "CD_Table" the
  //    caller need only worry about the string representation of the
  //    destination peer.
  // 4. The return value is an InternalMsg object so that the caller can decide
  //    how to process the message.
  // 5. The ConnectionDescriptor is still registered with the CD_Table so that
  //    the caller need only worry about the string representation of the
  //    destination peer.
  //---------------------------------------------------------------------------
  public InternalKQMLmessage waitForIKMConnection (boolean ignore_multiple_CDs)

  //---------------------------------------------------------------------------
  // A client should be able to send messages to the connection owner
  // regardless of "ignore_multiple_CDs".  Use this method if you do not care.
  // This method calls its sibling method with "ignore_multiple_CDs" set to
  // `false'.
  //---------------------------------------------------------------------------
  public InternalKQMLmessage waitForIKMConnection () {

  /** locks on a connection and waits until a message is sent
    * @param conn the connection on which to wait on
    */
  public InternalKQMLmessage waitOnConnection (ConnectionDescriptor conn) {
    // block on the connection

  //---------------------------------------------------------------------------
  //                           pollConnections()
  //
  // 1. This method does not block and wait for a connection to be established.
  //    If there is no message on the input queue, this method returns
  //    immediately.
  // 2. This method will poll connections that it both owns and does not own.
  // 3. This method ignores the possibility that there may be multiple CDs
  // 4. The return value is an InternalMsg object so that the caller can decide
  //    how to process the message.
  // 5. The ConnectionDescriptor is still registered with the CD_Table so that
  //    the caller need only worry about the string representation of the
  //    destination peer.
  //
  // Implementation Note:  getNextInputMsg() can starve other threads of CPU
  // time.  When using it, precede its invocation with a "yield()".  Other
  // techniques might be necessary, such as sleeping.
  //---------------------------------------------------------------------------
  public InternalMsg pollConnections () {

  //==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==.
  //                    Diconnect and Shutdown Methods
  //==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==..==.

  //---------------------------------------------------------------------------
  // Iterates all members of the CD_Table and closes any open connections.
  //---------------------------------------------------------------------------
  private void Close_CD_Connections () {

  //---------------------------------------------------------------------------
  // Close the connection descriptor for the agent identified by "agentID".
  //---------------------------------------------------------------------------
  public void closeConnection (String agentID) {

  //---------------------------------------------------------------------------
  //                   A Mandatory ANS Unregister Method
  //
  // This method must be called to free the ANS entry maintained for the
  // calling application.  Otherwise, an error similar to the following might
  // occur:  "Communicator.registerWithANS: Cannot register with ANS: "
  //
  // N.B.:  This method was not explicitly designed to support multithreading,
  // although it might do so accidentally.  Review your multithread model to be
  // sure.
  //---------------------------------------------------------------------------
  public void ANS_Unregister () {