package JavaAgent.oplan;

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

/**
** The OPWriter is the class that sends messages to O-Plan. It is a 
** Thread to avoid blocking the OPAgent it belongs to.
*/
public class OPWriter extends Thread {

  /** 
  ** Constructor for the Thread that writes to the OutputStream
  ** of the given Process.
  ** @param opa the OPAgent to which this OPWriter belongs
  ** @param opp the Process to which messages will be written
  */
  public OPWriter(OPAgent opa, Process opp) {
    theOPAgent = opa;
    oPlanProcess = opp;
    toOPlan = new OutputStreamWriter(opp.getOutputStream());
    msgQueue = new Vector();
    this.setDaemon(true);
  }

  /** 
  ** This function is called when the Thread is started. It waits until 
  ** there is a message for O-Plan available and the OPReader is
  ** not expecting further messages from O-Plan. Then it takes the
  ** first message off the queue, and writes it to O-Plan. It also 
  ** informs the OPReader that it should expect a reply from O-Plan.
  */
  public void run() {
    while (true) {
      if (msgQueue.isEmpty()) {
	suspend();
      }
      if (!theOPAgent.fromOPlan.msgExpected() && !msgQueue.isEmpty()) {
	theOPAgent.fromOPlan.expectMsg();
	String msgToSend = getNextMsg();
	try {
	  toOPlan.write(msgToSend, 0, msgToSend.length());
	  toOPlan.flush();
	} catch (Exception e) {
	  theOPAgent.addSystemMessage("Error: cannot write to OPlan!");
	  this.stop();
	}
      }
      this.yield();
    }
  }
  
  private synchronized String getNextMsg() {
    String msgToSend = (String)msgQueue.firstElement();
    msgQueue.removeElement(msgToSend);
    return msgToSend;
  }

  /**
  ** This function places the given message in the queue of messages 
  ** to be written to O-Plan. A newline character will be added to the 
  ** message at this point.
  ** @param msg the message to be written to O-Plan
  */
  protected synchronized void send(String msg) {
    msgQueue.addElement(msg + '\n');
    theOPAgent.toOPlan.resume();
  }

  /** 
  ** the handle of the OPAgent this OPWriter belongs to
  */
  protected OPAgent theOPAgent;

  /** 
  ** the handle of the OPlan Process this OPWriter will write to
  */
  protected Process oPlanProcess;

  /** 
  ** the OutputStreamWriter for the OPlan Process 
  */
  private OutputStreamWriter toOPlan;

  /** 
  ** the queue of messages to be written to O-Plan 
  */
  private Vector msgQueue;

}
