//0: disconnect
//1: addname
//9: normal text
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Server extends JFrame {
   private JTextArea display;

   private DatagramPacket sendPacket, receivePacket;
   private DatagramSocket socket;

   private String [] UserArray=new String[30];
   private InetAddress[] IArray=new InetAddress[30];
   private int []IntArray=new int[30];
   private int ArrayCounter=0;//first free element in array

   public Server()
   {
      super( "Server" );

      display = new JTextArea();
      getContentPane().add( new JScrollPane( display),
                            BorderLayout.CENTER );
      setSize( 400, 300 );
      show();

      try {
         socket = new DatagramSocket( 5000 );
      }
      catch( SocketException se ) {
         se.printStackTrace();
         System.exit( 1 );
      }
   }

   public void waitForPackets()
   {
      while ( true ) {
         try {
            // set up packet
            byte data[] = new byte[ 100 ];
            receivePacket =
               new DatagramPacket( data, data.length );

            // wait for packet
            socket.receive( receivePacket );
 
	    //search for code
	    String input=new String( receivePacket.getData(), 0, 
               receivePacket.getLength() );
	    int code=(int)input.charAt(0)-(int)('0');
	    String realInput=new String(input.substring(1));

            // process packet
	 switch(code){
	    case 0: removeUser(realInput);
	       notifyUsers(realInput,0);
	    break;
	    case 1: notifyUsers(realInput,1);
	       addUser(realInput,receivePacket.getAddress(),
		  receivePacket.getPort());
		  sendUserlistToClient();
  	    break;
	    case 9:
               display.append( "\nPacket received:" + 
               "\nFrom host: " + receivePacket.getAddress() + 
               "\nHost port: " + receivePacket.getPort() + 
               "\nLength: " + receivePacket.getLength() + 
               "\nContaining:\n\t" + realInput);
	       // echo information from packet back to client
	       display.append( "\n\nEcho data to client..."); 
	       sendMessageToUsers(new String( realInput));
 	    break;
	 }

         }
         catch( IOException io ) {
            display.append( io.toString() + "\n" );
            io.printStackTrace();
         }
      }
   }

   private void removeUser(String name){
      int i=0;
      while(i<ArrayCounter && !name.equals(UserArray[i]))i++;
      ArrayCounter--;
      for (int j=i;j<ArrayCounter;j++){
	 UserArray[j]=UserArray[j+1];
	 IArray[j]=IArray[j+1];
	 IntArray[j]=IntArray[j+1];
      }//it is impossible that a user can't be found
   }

   private void removeUser(InetAddress address){
      int i=0;
      while (i<ArrayCounter && !address.equals(IArray[i]))i++;
      removeUser(UserArray[i]);
   }

   private void addUser(String name,InetAddress address,int port){
      int i=0;
      while (i<ArrayCounter && name.compareTo(UserArray[i])<0)i++;
      for (int j=ArrayCounter;j>i;j--){
	 UserArray[j]=UserArray[j-1];
	 IArray[j]=IArray[j-1];
	 IntArray[j]=IntArray[j-1];
      };
      ArrayCounter++;
      UserArray[i]=name;
      IArray[i]=address;
      IntArray[i]=port;
   }

   private void notifyUsers(String name,int action){
      String completeString;
      display.append("\nSend update to users");
      for (int i=0;i<ArrayCounter;i++){
	 completeString=new String(action+name);
	 sendPacketToClient(completeString.getBytes(),
	 IArray[i], IntArray[i]);
      }
   }

   private void sendPacketToClient(byte [] bytePacket, InetAddress address,
      int port){
      sendPacket=new DatagramPacket(bytePacket,bytePacket.length,address,port);
      try{
	 socket.send(sendPacket);
      }
      catch( IOException io ) { 
	 removeUser(address); 
      } 
      display.append("Packet sent\n");
      display.setCaretPosition(display.getText().length());
   }

   private void sendUserlistToClient(){
      String completeString;
      display.append("\nSend userlist to client");
      for (int i=0;i<ArrayCounter;i++){
	 completeString=new
	 String('1'+UserArray[i]);
	 sendPacketToClient(completeString.getBytes(),
	 receivePacket.getAddress(), receivePacket.getPort());
      }
   }

   private void sendMessageToUsers(String message){
      String completeString;
      display.append("\nSend Message to users");
      for (int i=0;i<ArrayCounter;i++){
	 completeString=new String('9'+message);
	 sendPacketToClient(completeString.getBytes(),
	 IArray[i], IntArray[i]);
      }
   }

   public static void main( String args[] )
   {
      Server app = new Server();

      app.addWindowListener(
         new WindowAdapter() {
            public void windowClosing( WindowEvent e )
            {
               System.exit( 0 );
            }
         }
      );

      app.waitForPackets();
   }
}
