package JavaAgent.oplan;

import JavaAgent.resource.*;
import JavaAgent.resource.cdl.ExpressionReader;
import JavaAgent.agent.Agent;

import java.io.*;

/**
** This Interpreter is the agent interface to an O-Plan process. It also 
** acts as the controller of O-Plan that manages all necessary information.
** It accepts KQML messages with several performatives. The content language 
** for any such message must be given as OP-TAIL, the O-Plan Task Assignment 
** Interface Language. There is no according class for this language which 
** is why the <tt>interpretLanguage</tt> method of this Interpreter must not 
** be called.
** @see KQMLmessage
*/

public class OPInterpreter extends Interpreter {

  /**
  ** This function is called when an OPAgent receives a KQML message 
  ** with the <tt>:ontology</tt> OPlan. The content <tt>:language</tt>
  ** must be OP-TAIL at present. The following performatives are currently
  ** accepted:
  ** <ul>
  ** <li> <tt>tell</tt> calls <tt>tellAction(...)</tt>
  ** </ul>
  ** @param message the KQMLmessage to be interpreted here
  ** @param receiver the Agent to which this OPInterpreter belongs and which
  ** has received the message
  ** @exception InterpretationException An exception will occur if this
  ** OPInterpreter fails to process this message for some reason, e.g. if
  ** the content language is not OP-TAIL.
  */
  public void interpretMessage(KQMLmessage message, Agent receiver) throws
      InterpretationException {

    // testing for the correct content language:
    if (!message.getValue("language").equals("OP-TAIL"))
      throw new InterpretationException(
        "Interpreter " + message.getValue("ontology") + 
	" does not support language " + message.getValue("langauge"));

    // calling a function to process the message according to the performative:
    String performative = message.getValue("performative");
    if (performative.equals("tell")) {
      tellAction(message, (OPAgent)receiver);
    } 
    else {
      throw new InterpretationException(
        "Interpreter " + message.getValue("ontology") + 
	" does not support performative " + performative);
    }
  }
      
  /**
  ** This function must not be called. All messages to O-Plan should be 
  ** processed by <tt>interpretMessage</tt> above. A call to this function 
  ** will result in an immediate InterpretationException.
  */
  protected void interpretLanguage(KQMLmessage message, Agent receiver, 
      Language language) throws InterpretationException {
    throw new InterpretationException(
        "Messages to O-Plan should be handled by interpretMessage.");
  }

  /**
  ** This function gets called when this OPInterpreter receives a 
  ** <tt>tell</tt> message. The content of the message will be passed on to 
  ** O-Plan (mostly) as is. Unfortunately the KQMLmessage parser may delete 
  ** some of the spaces in the message which might lead to problems.
  ** Depending on the content of the message various other
  ** actions might take place too:
  ** <ul>
  ** <li> <tt>(:domain "</tt><i>file</i><tt>")</tt>
  **   <br> where <i>file</i> is a filename including any path information 
  **   but excluding the <tt>.tf</tt> extesion.The domain can only be set 
  **   by the init-file.
  **   Before this message is sent to O-Plan a <tt>:init</tt> message will
  **   be created to initialize O-Plan. After the reply from O-Plan has been 
  **   received the content of the message will be sent to O-Plan setting 
  **   the domain. Finally, this message will also cause the OPAgent to 
  **   advertize its capabilitites to the broker.
  ** </ul>
  */
  protected void tellAction (KQMLmessage message, OPAgent receiver) 
      throws InterpretationException {

    // extracting the position of the first keyword from the content:
    String mContent = message.getValue("content");
    int keyIndex = (mContent.indexOf(':'));

    // the action taken depends on the keyword:
    if (mContent.startsWith(":domain", keyIndex)) {
      // check whether the sender was the init-file:
      if (!message.getValue("sender").equals("init-file"))
	throw new InterpretationException(
            "O-Plan domain can only be set by init-file.");
      // sending the initialization message to O-Plan:
      receiver.toOPlan.send("(:init)");
      // extracting domain file information:
      domainFile = mContent.substring(mContent.indexOf('\"')+1, 
          mContent.lastIndexOf('\"'));
      // sending the message that sets the domain:
      receiver.toOPlan.send(mContent);
      // and finally advertise the capabilities:
      advertiseCaps(receiver);
    }
  }

  private void advertiseCaps(OPAgent receiver) {
    try {
      ExpressionReader cs = new ExpressionReader(new BufferedInputStream(
          new FileInputStream(domainFile + ".cdl")));
      String capaMsg = cs.readExpression();
      while (capaMsg != null) {
	KQMLmessage msg = new KQMLmessage();
	msg.addFieldValuePair("performative", "advertise");
	msg.addFieldValuePair("receiver", "ANS");
	msg.addFieldValuePair("ontology", "capabilities");
	msg.addFieldValuePair("language", "KQML");
	msg.addFieldValuePair("content", capaMsg);
	receiver.sendMessage(msg);
	capaMsg = cs.readExpression();
      }
    } catch (Exception e) {
      receiver.addSystemMessage("Error: Unable to advertise capabilitiy!");
    }
  }

  /**
  ** the path and filename of the domain file, excluding any extension
  */
  private String domainFile = null;

}

