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

import java.util.Hashtable;
import java.util.Enumeration;

public class Server {
	
	public ServerSocket me;
	public Hashtable clientlist;
	
	public Server(int por) {
	
		int port = por;
		
		try {
			me = new ServerSocket(port, 5);
			
			clientlist = new Hashtable();
		}
		catch (Exception e) {
			System.err.println(e);
		}
	
	}

	public static void main(String [] args) throws Exception {
		
		int port = 9001;
		if (args.length > 0) port = Integer.parseInt(args[0]);
		Server ser = new Server(port);
		
		
		while(true) { 
			
			Socket conn = ser.me.accept();
			Commlinks links = new Commlinks(conn);
			String message = links.in.readLine();
			String [] arr = Msg_Parser.makeArray(message);
			if(arr[0].equals(Commands.NICK)) {
				ser.clientlist.put(arr[1], links);
						//System.err.println(arr[1] + " joined");
			}
			Thread t = new ServiceThread(arr[1], links, ser.clientlist);
			t.start();
			
		}
		
	}
}

/* Thread tasks: 
 *	main - 
 *		accept client connections,
 *		create streams with the new client,
 *		find new client's nickname, and add to clientlist, along with its commlinks
 *		spawn a thread to handle this new client
 *
 *	ServiceThread instances -
 *		read from link.in - client will provide a list request first
 *		after that clients start telling each other things.  so listen, and forward
 */
 
 
class ServiceThread extends Thread {
	
	Commlinks links;
	Hashtable clientlist;	// refer to hashtable possessed by Server
	String clientnick;
	
	public ServiceThread(String cli, Commlinks li, Hashtable ht) {
		clientnick = cli;
		links = li;
		clientlist = ht;
	}

	static synchronized void println(PrintStream out, String message) {
		out.println(message);
		out.flush();
	}	//this is the only method that SHOULD be mutex


	public void run() {
		String msg;
		
		while(true) try {
					//System.out.println("reading for " + clientnick);
			msg = links.in.readLine();
			String [] arr = Msg_Parser.makeArray(msg);
			String message = ""; 
			PrintStream op = null;
					//System.err.println(clientnick+ " sent "+arr[0]);
			if(arr[0].equals(Commands.TO.trim()) ) {
							//Commands.TO contains a space, which will not come here
				String tonick = arr[1];
				op = ((Commlinks)clientlist.get(tonick)).out;
				if(op == null) 
					throw (new NullPointerException(
						"not able to do proper hashtable lookup"));
				
				message = clientnick + ": ";
				for (int i = 2; i < arr.length; i++)
					message +=  arr[i] + " ";						
			}
			else if (arr[0].equals(Commands.LIST) ) {
				
				op = links.out;
				message = "list ";
				for(Enumeration e = clientlist.keys(); e.hasMoreElements(); )
					message += (String)e.nextElement() + " ";
		
			}
			else if(arr[0].equals(Commands.BYE) ) {
				links.so.close();
				clientlist.remove(clientnick);
						//System.err.println(clientnick + " closed");
				break;		//end this thread
			}
			else continue;
			ServiceThread.println(op, message);
			
		} catch(Exception e) {
			System.err.println("in thread " +clientnick + e);
		}
			
	}
	
}
