package JavaAgent.oplan;

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

/**
** The OPReader is a Thread that reads all messages from OPlan. Messages
** are expected in brackets and all other output from OPlan is 
** ignored, e.g. the initial text being printed.
*/
public class OPReader extends Thread {

  /** 
  ** Constructor for the Thread that reads from the given Process
  ** which should be the OutputStream of an OPlan Process. 
  ** @param opa the OPAgent to which this OPReader belongs
  ** @param opp the Process from which output will be read
  */
  public OPReader(OPAgent opa, Process opp) {
    theOPAgent = opa;
    oPlanProcess = opp;
    fromOPlan = opp.getInputStream();
    oPlanBusy = false;
    this.setDaemon(true);
  }

  /** 
  ** This method is called when the Thread is started. It waits for output 
  ** from the OPlan Process. Messages from O-Plan must be in brackets
  ** or they will be ignored. A message starts with a '(', then any text
  ** can follow including other brackets. They are being counted. When
  ** the matching ')' for the message is read, the message is considered 
  ** complete.
  */
  public void run() {
    while (true) {
      try {
	this.yield();
	char nextCh = (char)fromOPlan.read();
	processChar(nextCh);
      } catch (IOException e) {
	theOPAgent.addSystemMessage("Error: could not read from OPlan!");
	this.stop();
      }
    }
  }

  private synchronized void processChar(char nextCh) {
    iBuffer.append(nextCh);
    if ((nextCh == '(') && (brCount++ == 0)) {
      iBuffer = new StringBuffer();
      iBuffer.append(nextCh);
    }
    if ((nextCh == ')') && (--brCount == 0)) {
      theOPAgent.addSystemMessage("OPlan: " + iBuffer.toString());
      oPlanBusy = false;
    }
  }

  /**
  ** This function can be called to tell the OPReader that it should expect
  ** a message from OPlan. Subsequent calls to <tt>msgExpected</tt> will
  ** return true until this OPReader has read a complete message from OPlan.
  */
  protected synchronized void expectMsg() {
    oPlanBusy = true;
  }

  /**
  ** This function can be called to see whether there are currently
  ** messages expected from O-Plan. Usually, these would be replies 
  ** to messages sent by the OPWriter.
  ** @return whether a message from OPlan is currently expected
  */
  protected synchronized boolean msgExpected() {
    return oPlanBusy;
  }

  /** 
  ** the handle of the OPAgent the created this OPReader
  */
  protected OPAgent theOPAgent;

  /** 
  ** the handle of the OPlan process from which is being read
  */
  protected Process oPlanProcess;

  /** 
  ** the OutputStream of the OPlan Process (an InputStream for this OPReader)
  */
  private InputStream fromOPlan;

  /**
  ** the StringBuffer into which the current message is being read
  */
  private StringBuffer iBuffer = new StringBuffer();

  private boolean oPlanBusy;
  private int brCount = 0;

}
