package chatserver;

import java.net.*;
import java.util.Calendar;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

public class Chatserver {
	private static int port ; /*a static port number on which this chat service will run . 
	is set by passing the second arg from the command line */
	private static String welcome;/*a welcome message to new user. To be sent if user is accepted*/
	private static byte[] sorry;/*a reject user message.to be sent if the chat room is full or there is already a user on the same ip address */
/* a method that checks if the user ip is already registered. It helps to maintain 
 * the list of active users and limit the number of client in the chat room.It identifies 
 * new user and check if server is able to include their broadcast  
 * @parameter1 myList a list of ip address of clients
 * @parameter2 newUser the new user's ipaddress 
 * @returns 1 table size +1 if the user is already registered
 * 			2 an empty spot in the table if user is new and table is not full.
 * 			3 -1 if the table is full although user is new.
 * 
 * */	
public static int checkArray( InetAddress[] myList,InetAddress newUser){
	boolean foundInTable =false;
	int position=-1;
	int size=0;
	for (int i=0;i<myList.length;i++){
		if(myList[i]==null){
			position=1;}
		else if(newUser.equals(myList[i])){
			foundInTable=true;
			return size++;
			}
	}
	if (foundInTable){
		return size++;}
	else
		return position;
	}


/*broadcast message to all users.0ptionally could use a multicast ip address instead of the user table
 * @parameter1 myList a list of ip address of clients							
 * @parameter2 received message to be transmitted 
 *                          //@parameter4 mesageAuthor 
 * @parameter3 mySocket socket to send message
 * @returns int no of client message send
 * */
public static int broadCastMessage(InetAddress[] myList,byte[] received,DatagramSocket mySocket ){
	/*basic versions.no client administration. it just broadcast the message it received */
	int no_client_messaged=0;
	int tSize=myList.length;
	for(int i= 0;i<tSize;i++){
		if (myList[i]!=null){
		DatagramPacket outGo = new DatagramPacket(received,received.length , myList[i], port);
		no_client_messaged++;
		try	{	
			mySocket.send(outGo);
			}catch (PortUnreachableException e){no_client_messaged--;
				System.out.println("Port: "+ myList[i].getHostAddress() + e.getMessage());
			}catch (SocketException e) {no_client_messaged--;
				System.out.println("Socket: " + e.getMessage());
			}catch ( IOException e ){no_client_messaged--;
			System.out.println("IOexception: "+ myList[i].getHostAddress() + e.getMessage());
			}
		}
	}	
	return no_client_messaged;
}
/* just a useful wrapper.*/
private static InetAddress[] make_user_singletable(InetAddress newUser) {
	InetAddress[]newUserT= new InetAddress[1];
	newUserT[0]= newUser;
	return newUserT;
}


/*pass as argument the max number of client and then the port number */
    public static void main(String[] args) {
        /*Initialise static variables and process command line args*/
    	welcome= "welcome to BobChat";
        int size= Integer.parseInt(args[0]);
        try {
			sorry = "bobchaterroruserlimitreached".getBytes("UTF-16");
		} catch (UnsupportedEncodingException e1) {
			System.out.println("could not encode handshake code sorry " + e1.getMessage());
		}
        port =Integer.parseInt(args[1]);
        /*create UDP socket*/
        DatagramSocket listenSocket = null;
        /*Create a table of chat users with their IP address and userName */
        InetAddress[] userTable = new InetAddress[size];
        String[] userName = new String[size];
        /*Initialising the tables with null values*/
        for(int i=0;i<size;i++ ){
        	userTable[i]=null;
        	userName[i]=null;
        }
        /*start network */
        try { /*bind socket with a port number */
            listenSocket = new DatagramSocket(port);
        }  catch (SocketException e) {
            System.out.println("Socket: " + e.getMessage());
        } catch (Exception e) { 
            System.out.println("Weird excption " + e.getMessage());
        } 
            byte[] buffer = new byte[1000];
            while(true) {
            	//int broadcastNo =0;
            	/*Receive UDP Datagram mode*/
                DatagramPacket inCome =  new DatagramPacket(buffer, buffer.length);
                try {
					listenSocket.receive(inCome);
				} catch (IOException e) {
					System.out.println("IO receive ; " + e.getMessage());
				}
                System.out.print("got " + inCome.getLength() + " bytes - "+"from" +inCome.getAddress());
                InetAddress newUser= inCome.getAddress();
                int i=checkArray(userTable,newUser);
                if(i==-1){
                	System.out.println("client limit maxed");
                	/* optionally should tell the client the error message. and return to receive mode*/
                	InetAddress[] newUserT = make_user_singletable(newUser);
                	broadCastMessage(newUserT,sorry,listenSocket);
                }else if (i>size){
                	/*user is already registered. just broadcast his message. */
                	int broadCastDone= broadCastMessage(userTable,inCome.getData(),listenSocket);
                		{ System.out.println("broadcasted to "+ broadCastDone + " clients. "); }
                } else if((i<=size)&&(i>0)) {
                	/*user is a new user. his name and ip address should be added to the table. the empty index is i*/
                	/*optionally send him a welcome message  and fortune cookies*/
                	InetAddress[] newUserT = make_user_singletable(newUser);
                	byte[] welcomeUser = new byte[1000];
                	boolean stringConversion=true; 	
                	try {
						userName[i]= new String(inCome.getData(),"UTF-16");
						welcomeUser = (userName[i]+ welcome +"server time is "+ Calendar.getInstance().getTime()).getBytes("UTF-16");
					} catch (UnsupportedEncodingException e) {
						System.out.println(" could not read client name or or encode welcome message: possibly using a different charset " +e.getMessage());
						stringConversion=false;
					}
					if (stringConversion) {
					userTable[i]= newUser;
					/*the first datagram is the part of server client handshake*/
					try {
						broadCastMessage(newUserT,welcome.getBytes("UTF-16"),listenSocket);
					} catch (UnsupportedEncodingException e) {
						System.out.println("could not encode accept handshake" + e.getMessage());
					}
					int success=broadCastMessage(newUserT,welcomeUser,listenSocket);
					if (success==1)System.out.println("a new user added:"+ userTable[i]);
					}
                }
           }
    }



}