package JavaAgent.oplan;

import JavaAgent.context.*;
import JavaAgent.agent.*;
import JavaAgent.resource.*;

import java.io.*;
import java.net.*;
import java.util.*;

/**
** OPAgentContext is the context for an OPAgent. One difference to 
** a SocketContext on which this code is based is, of course, that the 
** agent created in this context is an instance of the class OPAgent.
** Another important difference is that an OPAgentContext expects an
** additional command line argument marked <tt>-b</tt> (for broker) which
** specifies the address of the broker.
** @see SocketContext
** @see OPAgent
*/

public class OPAgentContext extends JavaAgent.context.AgentContext {

  /**
  ** The constructor for the OPAgentContext just calls the constructor for 
  ** an AgentContext. This is necessary as there is no constructor for an
  ** AgentContext that takes no arguments.
  ** @param params Runtime parameters for the AgentContext.
  */
  public OPAgentContext(SocketParams params) {
    super(params);
  }

  /**
  ** This function gets the SocketAddress of the broker out of the params
  ** and returns it.
  ** @return the SocketAddress of the broker (ANS)
  */
  public SocketAddress getBrokerAddress() {
    return ((OPSocketParams)params).getBrokerAddress();
  }

  /**
  ** This function creates the OPAgent and initializes it by calling its
  ** <tt>init()</tt> function. Note this does not include the reading of the 
  ** init-file as for other Agents. It returns true iff the agent was created 
  ** successfully.
  ** @return whether the agent was created sucessfully
  */  
  protected boolean addAgent() {
    if(params.init_url != null) {
      A = new OPAgent(this, (params.name != null)?params.name:"Agent", 
          params.init_url, params.shared_url, params.shared_dir, 
	  params.working_dir);
      A.init();
      return true;
    } else {
      addSystemMessage("Do not have location of initialization file!");
    }
    return false;
  }

  /**
  ** Creates a SocketInterface for the Agent. Unlike other Agents, this
  ** function does not cause the agent to announce its presence to the 
  ** broker/ANS. This is now triggered by the Agent itself in the function
  ** <tt>sendInitMessages()</tt> which calls <tt>SubmitAddress()</tt> below.
  */
  protected void createCommInterface() {
    comm = new SocketInterface(A, ((SocketParams)params).port);
    if(((SocketInterface)comm).port >= 0) {
      setAgentAddress(((SocketInterface)comm).port);
      comm_ready = true;
      A.setComm(comm);
    } else {
      addSystemMessage("Failed to create a Socket Interface for the Agent on "
		       + "port " + ((SocketParams)params).port + ", " +
		       "try a different port.");      
    }
  }

  /**
  ** Sets the agents address, and name if no name was specified.
  ** @param port the port of the agent on this host
  */ 
  protected void setAgentAddress(int port) {
    try{
      String host = null;
      InetAddress local_host = InetAddress.getLocalHost();
      String host_name = local_host.getHostName();
      /* Is the host_name just the computer? */
      if(host_name.indexOf(".") < 0 ) {
	/* use the IPaddress */
	String IPstr = local_host.toString();
	host = IPstr.substring(IPstr.indexOf("/")+1);
      } else {
	host = host_name;
      }
      if(params.name == null){ 
	/* set the Agent name to the URL */
	A.setName(host_name +":" + port);
      }
      A.getResource("address").addElement(A.getName(),
          new SocketAddress(host,port), true);    
    } catch (Exception e){
      addSystemMessage("Failed to set Agent address.", e);
    }
  }
  
  /**
  ** Send the agent's name and address to the ANS. This function must
  ** be called by the OPAgent.
  */
  protected void SubmitAddress() {
    try{
      SocketAddress sa = (SocketAddress)(A.getResource("address")).
          getElement(A.getName(), RetrievalResource.BLOCK);
      String address_str = new String("(evaluate :sender " + A.getName() +
          " :receiver ANS :language KQML" + " :ontology agent)");
      KQMLmessage address_msg = new KQMLmessage(address_str);
      address_msg.addFieldValuePair("content", "(tell-resource " + 
          ":type address :name " + A.getName() + " :value " + 
          sa.getValue()+ ")");
      A.sendMessage(address_msg);
    } catch (Exception e){
      addSystemMessage("Couldn't get local host.", e);
    }
  }

  /**
  ** Called if the OPAgentContext is started as an application from 
  ** the command line. Command line args are:<p><ul>
  ** <li> -b broker address - the address of the broker; must be provided
  ** for an OPAgentContext
  ** <li> -i init_file URL
  ** <li> [-s] shared classes URL, for classes and other files which will
  ** be shared with other agents.
  ** <li> [-l] local directory for writing to the shared classes URL.
  ** <li> [-w] working directory for saving local files, this should not
  ** be included if the agent cannot access the local disk 
  ** <li> [-n] name, only included if the Agent should automatically 
  ** connect to the network.
  ** <li> [-gui] create a GUI if this flag is included
  ** <li> [-p] For for ServerSocket
  ** </ul>
  ** @param arg Array of command line arguments.
  */

  public static void main(String arg[]) {
    Hashtable args = AgentContext.parseArgs(arg);
    if (args.containsKey("-b")) {
      OPAgentContext opac = new OPAgentContext(
          new OPSocketParams(args));
    }
    else
      System.out.println("Error: no broker address supplied!");
  }

}



















