import java.net.*;
import java.io.*;
import java.util.*;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.*;
import sun.misc.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

class AESencrp //AES key generator
{
    
     private static final String ALGO = "AES";
    private static final byte[] keyValue = 
        new byte[] { 'T', 'h', 'e', 'B', 'e', 's', 't',

'S', 'e', 'c', 'r','e', 't', 'K', 'e', 'y' };


public static String encrypt(String Data) throws Exception //Encryption Function
    {
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.ENCRYPT_MODE, key);
        byte[] encVal = c.doFinal(Data.getBytes());
        String encryptedValue = new BASE64Encoder().encode(encVal);
        return encryptedValue;
    }

    public static String decrypt(String encryptedData) throws Exception //Decryption Function 
	{
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.DECRYPT_MODE, key);
        byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData);
        byte[] decValue = c.doFinal(decordedValue);
        String decryptedValue = new String(decValue);
        return decryptedValue;
    }
    private static Key generateKey() throws Exception {
        Key key = new SecretKeySpec(keyValue, ALGO);
        return key;
}

}




public class MClient extends Frame 
{

	
	private BufferedReader si;		// to read from the socket
	private PrintWriter so;		// to write on the socket
	private Socket socket;
   
	// the server, the port and the username
	private String server, username;
	private int port;
	
	//GUI 
	TextField sd,enc,disp;
    Button B;
    Label chat,l1,l2,l3;
    Panel p1,p2,p3;
	String sendMessage;
	
	MClient(String server, int port, String username) 
	{
		super(username);
		
		//startup the client
		this.server = server;
		this.port = port;
		this.username = username;
		
		//Layout of GUI
		setLayout(new GridLayout(3,0,0,0));
	    p1   = new Panel(new BorderLayout());
	    p2   = new Panel(new BorderLayout());
	    p3   = new Panel(new BorderLayout());
	    sd   = new TextField(100);
	    enc  = new TextField(100);
	    disp = new TextField(100);
	    B    = new Button("SEND");
	    chat = new Label("Display");
	    l1   = new Label("Message",Label.LEFT);
	    l2   = new Label("Before Decryption",Label.LEFT);
		p1.add(l1,BorderLayout.NORTH);
	    p1.add(sd,BorderLayout.CENTER);
	    p1.add(B,BorderLayout.EAST);
	    p2.add(l2,BorderLayout.NORTH);
	    p2.add(enc,BorderLayout.CENTER);
	    p3.add(chat,BorderLayout.NORTH);
	    p3.add(disp,BorderLayout.CENTER);
	    add(p1);
	    add(p2);
	    add(p3);
	    setSize(700,700);
        setVisible(true);
		addWindowListener(new WindowAdapter()
	                   { public void windowClosing(WindowEvent we)
						   { System.exit(0);}
					    }
					);
		
		//Set the function for send button
        B.addActionListener(
	                      new ActionListener()
						  {
						    public void actionPerformed(ActionEvent ae)
							{
							    sendMessage = sd.getText(); 
								sd.setText("");
								enc.setText("");
								sendMessage(sendMessage);
								
                            }
                          }							
	                    );		
	}
	
	public boolean start() 
	{
		// try to connect to the server
		try {
			socket = new Socket(server, port);
		    } 
		// if it failed not much I can so
		catch(Exception ec) {
			//display("Error connectiong to server:" + ec);
			return false;
		}
		
		String msg = "Connection accepted " + socket.getInetAddress() + ":" + socket.getPort();
	
		/* Creating both Data Stream */
		try
		{
			si  = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			so  = new PrintWriter(socket.getOutputStream(),true);
		}
		catch (IOException eIO) 
		{
			return false;
		}
        
		new ListenFromServer().start();
		
		try
		{
	         so.println(username);
		}
		catch (Exception eIO) 
		{
			disconnect();
			return false;
		}
		return true;
	}

	/*
	 * To send a message to the server
	 */
	void sendMessage(String msg) {
		try {
			so.println(AESencrp.encrypt(msg))//Send encrypted message;
		}
		catch(Exception e) 
		{
	
		}
	}

	
	private void disconnect() {
		try { 
			if(si != null) si.close();
		}
		catch(Exception e) {}
		try {
			if(so != null) so.close();
		}
		catch(Exception e) {} 
        try{
			if(socket != null) socket.close();
		}
		catch(Exception e) {}
	}
	
	public static void main(String[] args) 
	{
		// default values
		int portNumber = 1500;
		String serverAddress = "localhost";
		String userName = "Anonymous";

		// depending of the number of arguments provided we fall through
		switch(args.length) {
			// > javac Client username portNumber serverAddr
			case 3:
				serverAddress = args[2];
			// > javac Client username portNumber
			case 2:
				try {
					portNumber = Integer.parseInt(args[1]);
				}
				catch(Exception e) {
					System.out.println("Invalid port number.");
					System.out.println("Usage is: > java Client [username] [portNumber] [serverAddress]");
					return;
				}
			// > javac Client username
			case 1: 
				userName = args[0];
			// > java Client
			case 0:
				break;
			// invalid number of arguments
			default:
				System.out.println("Usage is: > java Client [username] [portNumber] {serverAddress]");
			return;
		}
		// create the Client object
		MClient client = new MClient(serverAddress, portNumber, userName);
		// test if we can start the connection to the Server
		if(!client.start())
			return;
		
		// wait for messages from user
		/*BufferedReader keyRead = new BufferedReader(new InputStreamReader(System.in));
		// loop forever for message from the user
		while(true) {
			System.out.print("> ");
			// read message from user
			try{
			String msg = keyRead.readLine();
			  // default to ordinary message
				client.sendMessage(msg);
			
			}
			catch(Exception l) {};
			
		}*/
		// done disconnect
		//client.disconnect();	
	}

	
	class ListenFromServer extends Thread 
	{

		public void run() {
			while(true) {
			        String recv;
				try {
					    if((recv = si.readLine())!= null)
						enc.setText(recv);
						String r = ">" + AESencrp.decrypt(recv);
						disp.setText(r);
					}
				catch(Exception e) {
					
				}
				
			}
		}
	}
}

