package talk;

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

// This is an app, not an applet. Any public class 
// with a 'public static void main(String argv[])' method
// can be launched as an app by typing 'java Classname'

public class Server implements Runnable {
	// The socket we will listen for new callers with.
	ServerSocket listener;
	// The vector we will keep a list of connections in.
	Vector connections;
	// The thread that listens for connections.
	Thread listenerThread;

	// This is the entry point for a java app.
	public static void main(String argv[])
	{
		// Find out what port to listen on.
		if (argv.length != 1) {
			usage();
		}
		int port = 0;
		try {
			port = Integer.parseInt(argv[0]);
		} catch (java.lang.NumberFormatException e) {
			System.out.println("Bad port parameter!");
			usage();	
		}
		// Now make a server object.
		new Server(port);
	}
	// The constructor for the server class
	Server(int port)
	{
		connections = new Vector();
		// Create a server socket listening to that port.	
		try {
			listener = new ServerSocket(port);
		} catch (java.io.IOException e) {
			System.out.print("Unable to bind to port ");
			System.out.print(port);
			System.out.println(". Perhaps that port is in use.");
			// Exit the application
			System.exit(0);
		}
		// Create the listening thread.
		listenerThread = new Thread(this);
		listenerThread.start();
	}
	static void usage()
	{
		System.out.println("Usage: java talk.Server port#");
		// Exit the application.
		System.exit(0);
	}
	public void run()
	{
		// The starting point for threads. Hand them off
		// to the appropriate methods.
		if (Thread.currentThread() == listenerThread) {
			listenerRun();
		}
	}
	void listenerRun()
	{
		// Listen for new connections in an endless loop.
		while (true) {
			try {
				Socket s = listener.accept();
				// Make a new Connection object to talk
				// to this person, and add it to our
				// collection.
				Connection c = new Connection(this, s);
				connections.addElement(c);
			} catch (java.io.IOException e) {
				// This particular connection
				// didn't quite make it. That's OK.	
			}
		}
	}
	// Send a string received from one of the connections
	// to all of the rest. The string is not sent to the
	// connection it came from.
	void outputLine(Connection from, String s)
	{
		// Walk through all of the elements
		// in the connections Vector. Enumerations
		// are a pleasant way get at all of the
		// elements in a Vector or Hashtable.

		synchronized (connections) {
			Enumeration enum = connections.elements();
			while (enum.hasMoreElements()) 
			{
				Connection c = (Connection) enum.nextElement();
				if (c != from) 
				{
					c.inputLine(s);	
				}
			}
		}
	}
	// Forget about the specified connection, which has closed.
	void forgetConnection(Connection c)
	{
		connections.removeElement(c);
		outputLine(null, "* * * " + c.name + " has disconnected.");	
	}
}

