package anastore.net;

import java.net.*;
import java.io.IOException;

/**
 * Server for a channel abstraction. This server binds a socket,
 * and loops infinitely accepting remote connections and spawning
 * threads to handle their requests.
 *
 * The user is notified of new connections via a
 * ChannelServerListener, which contains a connectionEstablished
 * function that is called each time a new connection is established.
 *
 * Note that the ChannelServer must be run as its own thread, since
 * listen() does return. Moreover, since the ChannelServerListener is
 * invoked from the server's thread, the listener should launch its
 * own thread to handle the request, or else the server thread will
 * not be able to accept other connections that may arrive.
 */
public class ChannelServer {
    private ServerSocket socket;
    private int port;
    
    /**
     * Create a new server, but do not start listening yet.
     *
     * @param port The port to bind to
     */
    public ChannelServer(int port) {
        this.port = port;
    }

    /**
     * @return the port number that this server listens on
     */
    public final int getPort() {
        return port;
    }

    /**
     * Begins accepting connections. listener.connectionEstablished is
     * called with the root send and receive channels for each
     * newly-established connection.
     *
     * Does not return. See the note in the class description about
     * running this in it own thread.
     */
    public void listen(ChannelServerListener listener)
        throws IOException {
        this.socket = new ServerSocket(port);

        while (true) {
            Socket remoteSocket = socket.accept();
            InetSocketAddress addr =
                (InetSocketAddress) remoteSocket.getRemoteSocketAddress();
            ChannelProtocolThread t =
                new ChannelProtocolThread(remoteSocket,
                                          addr.getHostName(),
                                          addr.getPort(),
                                          null);
            t.start();
            
            listener.connectionEstablished(addr.getHostName(),
                                           addr.getPort(),
                                           t.getRootSendChannel(),
                                           t.getRootReceiveChannel());
        }

    }
}
