/*
 * Remote Client+Server Message Passing Channel
 * 
 */

import java.io.*;
import java.net.*;

public class Rchannel extends Object {

  public final static int DEFAULT_PORT = 4711;
  protected String host; 
  protected int port;

  protected ObjectInputStream in;
  protected ObjectOutputStream out;

  private ServerSocket srv;
  private Socket s;

  /**
   * Constructs a Remote channel
   * @param h hostname
   * @param p port
   */
  public Rchannel(String h, int p) {
    host = h;
    if (p<=0) { 
      port = DEFAULT_PORT; 
    } else {
      port = p;
    }

    if (host == "") { startserver(); }
       else         { startclient(); }
  }

  /**
   * Start a server
   */
  protected void startserver() {
    try { srv = new ServerSocket(port); }
    catch (IOException e) {
      System.err.println("Error creating ServerSocket on port = " + port);
      System.exit(1);
    }
    System.err.println("Listening for connection on port = " + port);
    try { s = srv.accept(); }
    catch (IOException e) {
      System.err.println("Error accepting connection on socket = " + srv);
      try { s.close(); } catch (IOException e2) {};
      System.exit(1);
    }
    try { 
      in  = new ObjectInputStream(s.getInputStream()); 
      out = new ObjectOutputStream(s.getOutputStream()); 
    }
    catch (IOException e) {
      System.err.println("Error creating connection on socket = " + s);
      try { s.close(); } catch (IOException e2) {};
      System.exit(1);
    }
  }


  /**
   * Start a client
   */
  protected void startclient() { 
    try { s = new Socket(host,port); }
    catch (IOException e) {
      System.err.println("Error creating Socket for host = " + host 
                       + " on port = " + port);
      System.exit(1);
    }
    try { 
      out = new ObjectOutputStream(s.getOutputStream()); 
      in  = new ObjectInputStream(s.getInputStream()); 
    }
    catch (IOException e) {
      System.err.println("Error creating connection on socket = " + s);
      try { s.close(); } catch (IOException e2) {};
      System.exit(1);
    }
  }


  /**
   * Send an object through R channel
   * @param v
   */
  public void send(Object v) {
    try { synchronized(out) { out.writeObject(v);} }
    catch (IOException e) {
      System.err.println("Error writing on stream = " + out);
      try { s.close(); } catch (IOException e2) {};
      System.exit(1);
    }
  }


  /**
   * Receive an object from R channel
   */
  public Object receive() {
    Object v = new Object();
    try { synchronized(in) { v=in.readObject();} }
    catch (IOException e) {
      System.err.println("Error reading from stream = " + in);
      try { s.close(); } catch (IOException e2) {};
      System.exit(1);
    }
    catch (ClassNotFoundException e3) {
      System.err.println("Class Not Found in stream = " + in);
      try { s.close(); } catch (IOException e2) {};
      System.exit(1);
    }
    return v;
  }

}
