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

interface MiniChatInterface
{
   public void sendMessage(String Message);
   public void deleteUser(Socket UserSocket, PrintWriter UserPrintWriter);
}

class MCS
{
   public static int PortNumber;
   
   public static void main(String args[])
   {
      System.out.println("Chat server started...\n");
      
      // Get the port number for the chat server
      if ( args.length == 1)
         setPortNumber(args[0]);
      else
      {
         System.out.println("Incorrect usage.  Start MiniChatServer by typing:");
         System.out.println("java MiniChatServer XXX");
         System.out.println("where XXX is the port number for the MiniChatServer to listen on");
         System.exit(0);
      }
      
      MiniChatServer TheServer = new MiniChatServer();
      TheServer.acceptConnections(PortNumber);
   }
   
   public static void setPortNumber(String PortString)
   {
      try
      {
         PortNumber = Integer.parseInt(PortString);
      }
      catch (Exception E)
      {
         System.out.println("Port number " + PortString + " is invalid port number\n");
         System.exit(0);
      }
   }
}

class MiniChatServer implements MiniChatInterface 
{
   private int PortNumber;
   private Vector ConnectionList;
   private Vector PWList; 
   
   public void acceptConnections(int PN)
   {
      PortNumber = PN;
      ConnectionList = new Vector();
      PWList = new Vector();
      
      ServerSocket MCServerSocket = null;
      Socket NewClientSocket = null;
      MCSocketListener ClientConnection;
      PrintWriter ClientPW = null;
      
      // Create server socket
      try
      {
         MCServerSocket = new ServerSocket(PortNumber);
      }
      catch (Exception E)
      {
         System.out.println("MiniChatServer Error:  couldn't get server socket port");
         System.out.println("                       MiniChatServer may already be running");
         System.exit(0);
      }
      
      // Accept connections
      for(;;)
      {
         try
         {
            // Get new client connection
            NewClientSocket = MCServerSocket.accept();
            ClientPW = new PrintWriter( NewClientSocket.getOutputStream(), true);
         }
         catch (Exception E)
         {
            System.out.println("MiniChatServer Error:  Couldn't accept new connection");
            System.out.println("E.getMessage");
         }   
            
         // Add new socket to list of sockets
         synchronized (this)
         {
            ConnectionList.add( NewClientSocket );
            PWList.add(ClientPW);
         }
         
         ClientPW.println("MiniChat>  " + ConnectionList.size() + " user(s) online");
         
         // Start a thread to talk to new socket
         ClientConnection = new MCSocketListener(NewClientSocket, this, ClientPW);
         ClientConnection.start();
         System.out.println("Accepted connection from " + NewClientSocket.getInetAddress().getHostAddress() );
      }     
      
   }
   
   public void sendMessage(String Message)
   {
      PrintWriter ClientPW = null;
      
      synchronized (this)
      {
         for(int counter = 0; counter < ConnectionList.size(); counter++)
         {
         ClientPW = (PrintWriter) PWList.elementAt(counter);
         ClientPW.println(Message);
         }
      }
      System.out.println("Chat> " + Message);   
   }
   
   public void deleteUser(Socket UserSocket, PrintWriter UserPrintWriter)
   {
      ConnectionList.removeElement(UserSocket);
      PWList.removeElement(UserPrintWriter);
      
      // if( ConnectionList.size() == 0)
      //    System.exit(0);
      
      sendMessage("MiniChat>  " + ConnectionList.size() + " user(s) still online");
   }
   
}

class MCSocketListener extends Thread
{
   private Socket MySocket;
   private MiniChatInterface MyInterface;
   private PrintWriter OutputToUser;
   
   MCSocketListener(Socket MyConnection, MiniChatInterface MyConnectionInterface, PrintWriter MyPrintWriter)
   {
      MySocket = MyConnection;
      MyInterface = MyConnectionInterface;
      OutputToUser = MyPrintWriter;
   }
   
   public void run()
   {
      BufferedReader IncomingMessage = null;
      String NameOfUser = null;
      String CurrentMessage = null;
      
      // Connect reader to socket
      try
      {
         IncomingMessage = new BufferedReader( new InputStreamReader( MySocket.getInputStream() ) );
      }
      catch (Exception E)
      {
         System.out.println("MiniChatServer ERROR:  Couldn't attach reader to new incoming socket");
         destroy();
      }
      
      // Prompt user for their name
      OutputToUser.println("MiniChat>  Enter your name");
      try
      {
         NameOfUser = IncomingMessage.readLine();
      }
      catch (Exception E)
      {
         System.out.println("MiniChatServer ERROR:  Error reading new users name\n");
      }
      
      MyInterface.sendMessage("MiniChat>  " + NameOfUser + " has entered the chat room");
      
      // Start waiting for messages
      for(;;)
      {
         // Wait for an incoming message
         try
         {
            CurrentMessage = IncomingMessage.readLine();
         }
         catch (Exception E)
         {
            // User exitted
            // System.out.println("MiniChatServer ERROR:  Error reading incoming data");
            MyInterface.sendMessage("MiniChat>  " + NameOfUser + " has exitted the room");
            deleteUser();
            return;
         }
         
         // Broadcast message to everyone else
         MyInterface.sendMessage("----" + NameOfUser + ": " + CurrentMessage);
      }
      
      
   }
   
   private void deleteUser()
   {
      // Close print writer and socket connection
      try
      {
         OutputToUser.close();   // Close print writer
         MySocket.close();       // Close socket connection
      }
      catch(Exception E)
      {
         System.out.println("MiniChatServer ERROR:  Couldn't close quitting user's connections");
      }
      
      MyInterface.deleteUser(MySocket, OutputToUser);
   }
   
   

}


 
