package RemoteService.context;

import RemoteService.agent.*;
import RemoteService.resource.*;

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

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

/**
 * Subclass of SocketContext which provides a context for a ClientAgent.
 * The main function of the ClientAgent is to load and execute interfaces to
 * multiple remote services. Each remote service 
 * interface can communicate with a local process via the stdin and
 * stdout of the context (PipeCommunicator).<p>
 * 
 * <hr>
 * Copyright (c) 1995, H. Robert Frost, Stanford University.
 * All rights reserved.<p>
 * Copyright (c) 1996, H. Robert Frost, Enterprise Integration Technologies,
 * Inc. All rights reserved.<p>
 *
 * RESTRICTED RIGHTS LEGEND: Use, duplication or disclosure by the 
 * Government is subject to restrictions as set forth in 
 * subparagraph(c)(1)(ii) of the Rights in Technical Data and Computer
 * Software clause at DFARS 252.227-7013 and in similar clauses in the
 * FAR and NASA FAR supplement.<p>
 * 
 * This software is bound by the terms and conditions listed in the
 * attached <a href="../LICENSE">LICENSE file</A>.
 * <hr>
 * @author <A HREF="http://cdr.stanford.edu/html/people/frost-bio.html"> Rob Frost</A>
 * @version 0.3 5/21/96 for Java(tm) Language Version 1.0.2
 */

public class ClientContext extends SocketContext{

  /**
   * Thread which handles communications through the 
   * stdin and stdout.
   */
  protected PipeCommunicator pipecomm = null;  

  /**
   * ClientContext constructor.
   */

  public ClientContext(ClientParams params){
    super(params);
    if(params.localcomm){
      startPipeCommunicator();
    }  
  }

  /**
   * Starts the PipeCommunicator thread.
   */
  
  protected void startPipeCommunicator(){
    if(pipecomm == null){
      /* create the PipeCommunicator */
      pipecomm = new PipeCommunicator(this);
      pipecomm.setPriority(Thread.MIN_PRIORITY);
      pipecomm.start();
      addSystemMessage("PipeCommunicator started.");
    }
  }

  /**
   *  If the gui flag is set, creates an RSFrame object.
   */

  protected void createGUI(){
    if(params.gui){
      frame = new ClientFrame(this,params.name);
      frame.resize(RSContextParams.RSF_WIDTH, 
		   RSContextParams.RSF_HEIGHT);
      frame.show();
    } 	
  }
  
  /**
   * Creates the ClientAgent object.
   */  
  
  protected boolean addAgent(){
    if(params.init_url != null){
      A = new ClientAgent(this,(params.name != null)?params.name:"ClientAgent",
			   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;
  }
  
  /**
   * Sends a String message through the stdout w/ optional interrupt.
   * @message message PipeMessage to be sent
   */
  public void NonAgentMsg(Object message) throws NonAgentMsgException{
    String cmd_array[] = {"/bin/kill", ((ClientParams)params).sig, 
			    ((ClientParams)params).pid};

    if(pipecomm != null){
      /* Send a special signal to the parent process */
      try {
	System.out.println(((PipeMessage)message).content);
	System.out.flush();
	if(((PipeMessage)message).interrupt){
	  Runtime.getRuntime().exec(cmd_array);
	}
      } catch (Exception e){
	throw new NonAgentMsgException("Failed to send PipeMessage: " +
				       ((PipeMessage)message).content
				       + ", " +e.toString());
      }
    } else {
      throw new NonAgentMsgException("Local comm not enabled," +
				     " cannot send message: " + message);
    }
  }

  /**
   * Called when a message is received through the PipeCommunicator.
   * @param message String received.
   */

  protected void PipeMsgReceived(String message){
    ((ClientAgent)getAgent()).PipeMsgReceived(message);
  }
  
  /**
   * Called when some Agent resource has changed.
   * If it is available_service could be a registration or an unregistration.
   * @param type String identifying the type of the resource.
   */

  public void resourceChanged(String type){
    if(type.equals("available_service")){
      frame.resourceChanged(type);
    } else {
      super.resourceChanged(type);
    }
  }

  /**
   * Called if the ClientContext is started as an application from the command
   * line. Command line args:<p><ul>
   * <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] Port for ServerSocket
   * <li> [-comm] local communication is supported, must have a dummy arg.
   * <li> [-pid] pid of local process
   * <li> [-sig] signal number for interrupting local process
   * </ul>
   * @param arg Array of command line arguments.
   */

  public static void main(String arg[]) {
    Hashtable args = AgentContext.parseArgs(arg);
    ClientContext cc = new ClientContext(new ClientParams(args));
  }

}

/**
 * Class which communicates with another process via pipes connected to the
 * stdin and stdout of the ClientContext process.
 */

class PipeCommunicator extends Thread {
  
  ClientContext parent;
  DataInputStream dis;

  public PipeCommunicator(ClientContext parent){
    super("pipe");
    this.parent = parent;
  }

  public void close(){
    try {
      dis.close();
    } catch (java.io.IOException e){}
  }
  
  public void run(){
    
    dis = new DataInputStream(System.in);
    
    while(true){
      try{
	String input = dis.readLine();
	if( input != null){
	  parent.addSystemMessage("Input length = " + input.length());
	  if(input.equals("\n"))parent.addSystemMessage("Received the newline.");
	  parent.addSystemMessage(input);
	  if(input.startsWith("terminate")){
	    break;
	  } else {
	    parent.PipeMsgReceived(input);
	  }
	}
      } catch (Exception e){
	parent.addSystemMessage("Error receiving message from ProI.",e);
      }
    }
    parent.initiateTermination();
  }

}


















