package context.arch.comm.protocol;

import java.net.ServerSocket;
import java.net.Socket;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Enumeration;

/**
 * This class implements a threaded serversocket that accepts TCP packets.
 * It does nothing with the TCP packets themselves but can be subclassed
 * to do real work.  Whenever it receives data, it clones itself.  The original
 * class listens for more new connections while the clone handles the received
 * data.
 *
 * @see java.lang.Runnable
 * @see java.lang.Cloneable
 */
public class TCPServerSocket implements Runnable, Cloneable {

  /**
   * Debug flag. Set to true to see debug messages.
   */
  private static final boolean DEBUG = false;

  /**
   * The default port number to use is 5555
   */
  public static final int DEFAULT_PORT = 5555;
 
  private ServerSocket serverSocket;
  private Thread runner = null;
  private Socket data = null;
  private int portNumber;

  /**
   *  Default constructor for TCPServerSocket, with the default port.
   *
   * @see #DEFAULT_PORT
   */
  public TCPServerSocket() {
    portNumber = DEFAULT_PORT;
  }

  /**
   * TCPServerSocket constructor with user-specified port.
   *
   * @param port Port number to use
   */
  public TCPServerSocket(int port) {
    portNumber = port;
  }

  /**
   * Starts a ServerSocket and a thread with this TCPServerSocket as the
   * Runnable.
   *
   */
  public void start() {
    if (runner == null) {
      try {
        serverSocket = new ServerSocket(portNumber);
        runner = new Thread(this);
        runner.start();
      } catch (IOException ioe) {
          System.out.println("TCPServerSocket init error: "+ioe + " on port number "+portNumber);
      }
    }
  }

  /**
   * Stops the original thread (just the original?) running and closes the socket.
   */
  public void stopServer() {
    if (serverSocket != null) {
      runner = null;
      try {
        serverSocket.close();
      } catch (IOException ioe) {
          System.out.println("TCPServerSocket stopServer error: "+ioe);
      }
    }
  }  

  /**
   * This method loops forever waiting for data on the socket.  When data
   * arrives, it clones a new instance of TCPServerSocket so the new
   * thread can deal with the data, while the current instance looks for new
   * data.  The new thread deals with the data by calling handleIncomingRequest().
   *
   * @see #handleIncomingRequest(java.net.Socket)
   */
  public void run() {
    if (serverSocket != null) {
      while (true) {
        try {
          Socket dataSocket = serverSocket.accept();
          TCPServerSocket newSocket = (TCPServerSocket) clone();
          newSocket.serverSocket = null;
          newSocket.data = dataSocket;
	    newSocket.runner = new Thread(newSocket);
          newSocket.runner.start();
        } catch (IOException ioe) {
            System.out.println("TCPServerSocket run IOexception: "+ioe);
        } catch (CloneNotSupportedException cnse) {
            System.out.println("TCPServerSocket run CloningException: "+cnse);
        }           
      }
    }
    else {
      handleIncomingRequest(data);
    }
  }

  /**
   * This method handles data received on a given TCPServerSocket.
   * Could be abstract since the method does nothing.  A subclass is
   * expected to override this method to handle the incoming data as
   * necessary.
   *
   * @param data Socket the data is arriving on
   */
  public void handleIncomingRequest(Socket data) {
    if (DEBUG) {
      System.out.println("in TCPServerSocket handleIncomingRequest(data)");
    }
  }

}
