import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.util.Date;

public class Server implements ActionListener {
	String WINDOW_NAME = "Server Chat Window";
	int PORT= 2380;
	int MAX_USERS = 2; //Includes Server
	String WELCOME_MSG = "Welcome to the chat!";
	File LOG_PATH = new File("logs\\log.doc");
	
	Socket clientSocket = null;
	Socket clientSocket2 = null;
	ServerSocket serverSocket = null;
	String errorMsg = null;
	
	JFrame mainFrame;
	JPanel labelPanel;
	JPanel historyPanel;
	JPanel textPanel;
	JPanel actionPanel;
	JLabel status;
	JTextArea history;
	JTextField input;
	JButton send, exit;	
	
	String Received[] = {"Welcome to " + WINDOW_NAME + ". (Type \"\\help\" of \"\\h\" for help.)\n","\n","\n","\n","\n","\n","\n","\n","\n","\n"};
	String in;
	String messages = "\n";
	String userList = "No users online(error)";
	boolean userSend = false;
	
	String addresses[] = new String[MAX_USERS];
	int addrCnt = 0;
	boolean newAddr = true;
	
	String kicked[] = new String[100];
	int kickCnt = 0;
	boolean kickedUsr = false;
	boolean ban = false;
	
	int count=0;
	
	boolean error = false, mError = false;
	boolean action = false;
	boolean fileIn = false;
	boolean fileOut = false;
	
	FileOutputStream logFile;
	
	byte[] c = ("Server Start Up!").getBytes();
	
	public Server() 
	throws IOException {
		start();
		mainFrame = new JFrame(WINDOW_NAME);
		Container content = mainFrame.getContentPane();
		content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
		labelPanel = new JPanel();
		historyPanel = new JPanel();
		textPanel = new JPanel();
		actionPanel = new JPanel();
		
		mainFrame.setSize(600, 100);
		mainFrame.setLocation(200, 200);
		
		history = new JTextArea(9,50);
		
		inPanels();
		addPanels();
		
		content.add(labelPanel);
		content.add(historyPanel);
		content.add(textPanel);
		content.add(actionPanel);
		
		mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		mainFrame.pack();
		mainFrame.setVisible(true);
		if(error) dispMsg();
		input.grabFocus();
		msgIn();
	}
	
	public void inPanels() {
		status = new JLabel(errorMsg);
		labelPanel.add(status);
		messages = "";
		for(int i=9; i>=0; i--) messages = messages + Received[i];
		history.setText(messages);
		history.setEditable(false);
		historyPanel.add(history);
	}
	
	public void addPanels() {
		input = new JTextField(in,50);
		input.addActionListener(this);		
		textPanel.add(input);
					
		send = new JButton("Send");
		exit = new JButton("Exit");
		send.addActionListener(this);
		exit.addActionListener(this);
		actionPanel.add(send);
		actionPanel.add(exit);
	}
	
	public void start() {
		try {
			serverSocket = new ServerSocket(PORT);
		} catch (IOException e) {
			errorMsg = "Could not listen on port: " + PORT;
			error = true;
		}
		if(error == false) errorMsg = "Listening on: " + PORT;
	}
	
	public void dispMsg() {
		byte[] c=Received[0].getBytes();
		int m;
		for(m=0; m<2;) {	
			if(Received[0].length() > 100) {
				for(int i=9; i>0; i--) Received[i] = Received[i-1];
				Received[1] = Received[0].substring(0,100) + "\n";
				Received[0] = Received[0].substring(100);
				if(Received[0].length() > 100) {
					for(int i=9; i>0; i--) Received[i] = Received[i-1];
					Received[1] = Received[0].substring(0,100) + "\n";
					Received[0] = Received[0].substring(100);
				}
			}
			try {
				logFile = new FileOutputStream(LOG_PATH,true);
				logFile.write(c);
				logFile.close();
				m=3;
			} catch (FileNotFoundException e) {
				File tempFile = new File(LOG_PATH.getPath());
	
				String path = tempFile.toString();
				boolean newDir = false;
				for(int i=0; i<path.length(); i++) if(path.charAt(i) == '\\') newDir = true;
				if(newDir) {
					int i = path.lastIndexOf('\\');
					path = path.substring(0,i);
					File tempFile2 = new File(path);
					tempFile2.mkdirs();
				}
				m++;
			} catch (IOException e) {
				for(int i=9; i>0; i--) Received[i] = Received[i-1];
				Received[0] = "Can't Write to Log File!\n";
				m=3;
			}
		}
		if(m==2) {
			for(int i=9; i>0; i--) Received[i] = Received[i-1];
				Received[0] = "Log File Not Found!\n";
		}
		Container content = mainFrame.getContentPane();
		content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
		
		labelPanel.removeAll();
		historyPanel.removeAll();
		
		inPanels();
		if(action) {
			textPanel.removeAll();
			actionPanel.removeAll();
			addPanels();
		}
		action = false;
		
		content.add(labelPanel);
		content.add(historyPanel);
		content.add(textPanel);
		content.add(actionPanel);
		
		labelPanel.repaint();
		historyPanel.repaint();
		textPanel.repaint();
		actionPanel.repaint();
		mainFrame.setVisible(true);
		input.grabFocus();
	}
	
	public void msgIn() 
	throws IOException {
		for(int j=0; j<1; ) {
			String mErrorMsg = "";
			boolean maxusers = false;
			newAddr = true;
			boolean nameMatch = false;
			try {
				clientSocket = serverSocket.accept();
				InetAddress address = clientSocket.getInetAddress();
				String address2 = "";
				for(int k=1; k<address.toString().length(); k++) address2 += address.toString().charAt(k);
				for(int k=0; k<addrCnt; k++) if(address2.equals(addresses[k])) newAddr = false;
				for(int k=0; k<kickCnt; k++) if(address2.equals(kicked[k])) kickedUsr = true;
				if(kickedUsr) {
					PrintWriter out = null;
					try {
						mError = false;
						clientSocket2 = new Socket(address2,PORT+1);
						out = new PrintWriter(clientSocket2.getOutputStream(), true);
						out.println("You cannot join this chat!");
						clientSocket2.close();
						errorMsg = "Listening on: " + PORT;
					} catch (UnknownHostException e) {
						mErrorMsg=errorMsg = "Couldn't Send Kicked Message!";
						mError = true;
					} catch (IOException e) {
						mErrorMsg=errorMsg = "Couldn't Send Kicked Message!";
						mError = true;
					}
				} else if(addrCnt+1 > MAX_USERS && newAddr) {
					PrintWriter out = null;
					try {
						mError = false;
						clientSocket2 = new Socket(address2,PORT+1);
						out = new PrintWriter(clientSocket2.getOutputStream(), true);
						out.println("Too many users");
						clientSocket2.close();
						errorMsg = "Listening on: " + PORT;
					} catch (UnknownHostException e) {
						mErrorMsg=errorMsg = "Couldn't Send Chat Full Message!";
						mError = true;
					} catch (IOException e) {
						mErrorMsg=errorMsg = "Couldn't Send Chat Full Message!";
						mError = true;
					}
					maxusers = true;
				} else if(newAddr) {
					addresses[addrCnt] = address2;
					if(!address2.equals("127.0.0.1")) {
						PrintWriter out = null;
						try {
							mError = false;
							clientSocket2 = new Socket(address2,PORT+1);
							out = new PrintWriter(clientSocket2.getOutputStream(), true);
							out.println(WELCOME_MSG);
							clientSocket2.close();
							errorMsg = "Listening on: " + PORT;
							clientSocket2.close();
						} catch (UnknownHostException e) {
							mErrorMsg=errorMsg = "Couldn't Send Welcome Message!";
							mError = true;
						} catch (IOException e) {
							mErrorMsg=errorMsg = "Couldn't Send Welcome Message!";
							mError = true;
						}
					}
					addrCnt++;
				}
				
				if(!maxusers && !kickedUsr) {
					if(count >= 9) count=0;
					BufferedReader incoming = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
					for(int i=9; i>0; i--) Received[i] = Received[i-1];
					
					Received[0] = incoming.readLine();
					int addrLgth = address2.length();
					if(Received[0].equals("User Signed off...")) {
						Received[0] = "Signed off...";
						for(int k=0; k<addrCnt-1; k++) if(address2.equals(addresses[k])) for(int l=k;l<addrCnt-1; l++) addresses[l] = addresses[l+1];
						addrCnt--;
					} else if(Received[0].equals("User is online...")) Received[0] = "Signed on...";
					else if(Received[0].equals("\\users")) {
						userSend = true;
						users();
						PrintWriter out = null;
						try {
							mError = false;
							clientSocket2 = new Socket(address2,PORT+1);
							out = new PrintWriter(clientSocket2.getOutputStream(), true);
							out.println(userList);
							clientSocket2.close();
							errorMsg = "Listening on: " + PORT;
							clientSocket2.close();
						} catch (UnknownHostException e) {
							mErrorMsg=errorMsg = "Couldn't Send User List!";
							mError = true;
						} catch (IOException e) {
							mErrorMsg=errorMsg = "Couldn't Send User List!";
							mError = true;
						}
						Received[0] = "Sent user list to: " + address2 + "\n";
					} else if(Received[0].equals("Error Sending File!")) {
						Socket socket = new Socket(address2,PORT+1);
						PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
						out.println("Error Sending File!");
						Received[0] += "\n";
						userSend=fileOut = true;
						fileIn = false;
						socket.close();
					} else if(Received[0].equals("File Transfer Successful!")) {
						userSend=fileOut = true;
						Received[0] += "\n";
					} else if(Received[0].equals("File Complete!")) {
						Socket socket = new Socket(address2,PORT+1);
						PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
						out.println("File Transfer Successful!");
						userSend=fileOut = true;
						Received[0] += "\n";
						socket.close();
					} else {
						try {
							if(Received[0].substring(0,17).equals(" is sending you: ")) {
								userSend=fileIn = true;
								Received[0] = address2 + Received[0] + "\n";
							}
							else if(Received[0].substring(0,addrLgth).equals(address2)) {
								userSend = true;
								Received[0] += "\n";
							}
						} catch (StringIndexOutOfBoundsException e) {
						}
					}
					Date time = new Date();
					int hour = time.getHours();
					int min = time.getMinutes();
					int sec = time.getSeconds();
					String hourS = hour + ":";
					String minS = min + ":";
					String secS = sec + "] ";
					if(hour < 10) hourS = "0" + hourS;
					if(min < 10) minS = "0" + minS;
					if(sec < 10) secS = "0" + secS;
					String TimeStamp = "[" + hourS + minS + secS;
					if(!userSend) {
						Received[0] = TimeStamp + address.getHostName() + ": " + Received[0];
						
						for(int i=0; i<addrCnt; i++) {
							mError = false;
							try {
								clientSocket2 = new Socket(addresses[i],PORT+1);
								PrintWriter out = new PrintWriter(clientSocket2.getOutputStream(), true);
								out.println(Received[0]);
								clientSocket2.close();
								errorMsg = "Listening on: " + PORT;
							} catch (UnknownHostException e) {
								mErrorMsg=errorMsg = "Error Relaying Message";
								mError = true;
							} catch (IOException e) {
								for(int k=0; k<addrCnt; k++) {
									if(!addresses[i].equals("127.0.0.1")) {
										mErrorMsg=errorMsg = "Error Relaying Message";
										mError = true;
									}
								}
							}
						}
						if(mError) Received[0] = mErrorMsg + "\n";			
						else Received[0] += "\n";
						
						count++;
					} else Received[0] = TimeStamp + Received[0];
					
					dispMsg();
					clientSocket.close();
					userSend = false;
					input.grabFocus();
				}
			} catch (SocketException e) {
				start();
			} catch (NullPointerException e) {
				start();
			}
		}
	}
	
	public void msgOut() {
		boolean sending = false;
		try {
			if(in.equals("\\h") || in.equals("\\help")) {
				help();
			}
			else if(in.equals("\\kicked")) {
				kicked();
			}
			else if(in.equals("\\users")) {
				users();
			}
			else if(in.equals("\\exit")) {
				System.exit(0);
			}
			else if(in.equals("\\about")) {
				about();
			}
			else if(in.equals("\\y") && fileIn || in.equals("\\yes") && fileIn) {
				fileIN();
			}
			else if((in.substring(0,3)).equals("\\w ")) {
				whisper();
			}
			else if((in.substring(0,4)).equals("\\ip ")) {
				IP();
			}
			else if((in.substring(0,5)).equals("\\max ")) {
				max();
			}
			else if((in.substring(0,5)).equals("\\log ")) {
				log();
			}
			else if((in.substring(0,6)).equals("\\port ")) {
				port();
			}
			else if((in.substring(0,6)).equals("\\file ")) {
				file();
			}
			else if((in.substring(0,6)).equals("\\kick ") && (in.charAt(6) != '-')) {
				ban=false;
				kick();
			}
			else if((in.substring(0,8)).equals("\\unkick ") && (in.charAt(8) != '-')) {
				unkick();
			}
			else if((in.substring(0,8)).equals("\\kick -a")) {
				addrCnt = 0;
				in = "All users have been kicked!\n";
				send();
			}
			else if((in.substring(0,8)).equals("\\kick -h")) {
				kickHelp();
			}
			else if((in.substring(0,9)).equals("\\kick -b ")) {
				ban=true;
				kick();
			}
			else if((in.substring(0,9)).equals("\\welcome ")) {
				welcome();
			}
			else if((in.substring(0,10)).equals("\\unkick -a")) {
				kickCnt=0;
				for(int i=9; i>0; i--) Received[i] = Received[i-1];
				Received[0] = "All kicked users have been allowed back\n";
			}
			else {
				send();
				sending=true;
			}
		} catch (StringIndexOutOfBoundsException e) {
			send();
			sending=true;
		}
		
		in="";
		action = true;
		if(!sending) dispMsg();
	}
	
	public void send() {
		if(!in.equals("")) {
			try {
				clientSocket2 = new Socket("127.0.0.1",PORT);
				PrintWriter out = new PrintWriter(clientSocket2.getOutputStream(), true);
				out.println(in);
				clientSocket2.close();
			} catch (UnknownHostException err) {
				errorMsg = "Error Sending Message!";
			} catch (IOException err) {
				errorMsg = "Error Sending Message!";
			}
		}
	}	
	
	public void help() {
		Received[9] = "Help for " + WINDOW_NAME + ".\n";
		Received[8] = "\\welcome <Welcome Message> - Changes the message sent when users sign on.\n";
		Received[7] = "\\port <Port Number> - Changes the port.\n";
		Received[6] = "\\max <Maximum Users> - Changes the number of users who can connect.\n";
		Received[5] = "\\kick -h - brings up the kick user help\n";
		Received[4] = "\\ip <Host Name> - Finds an IP address.\n";
		Received[3] = "\\users - lists all users.\t\t\t\\exit - exits the program.\n";
		Received[2] = "\\file <IP of Host> - Sends a file to a user.\t\t\\about - Program Info\n";
		Received[1] = "\\w <IP or Host> <Message> - Whispers a message to a user.\n";
		Received[0] = "\\log <file> - Changes the location and name of log file.\n";
	}
	
	public void kickHelp() {
		for(int i=9; i>6; i--) Received[i] = Received[i-7];
		Received[6] = "Help for kicking users.\n";
		Received[5] = "\\kick -a - Kicks all users\n";
		Received[4] = "\\kick -b <IP or Host> - kicks and bans a user\n";
		Received[3] = "\\kick <IP or Host> - kicks the user (doesn't ban)\n";
		Received[2] = "\\unkick <IP> - allows kicked user to sign back on(IP only).\n";
		Received[1] = "\\unkick -a - clears the kicked list.\n";
		Received[0] = "\\kicked - lists all kicked users.\n";
	}
	
	public void welcome() {
		WELCOME_MSG = in.substring(9);
		for(int i=9; i>0; i--) Received[i] = Received[i-1];
		Received[0] = "Welcome Message changed to \"" + WELCOME_MSG + "\"\n";
	}
	
	public void port() {
		try {
			serverSocket.close();
		} catch (IOException e) {
		}
		addrCnt = 0;
		PORT = Integer.parseInt(in.substring(6));
		start();
		for(int i=9; i>0; i--) Received[i] = Received[i-1];
		Received[0] = "Port changed to " + PORT + "\n";
	}
	
	public void max() {
		String inT= in;
		in = "Max users changed to " + Integer.parseInt(inT.substring(5)) + ". Kicking off users.\n";
		send();
		MAX_USERS = Integer.parseInt(inT.substring(5));
		addrCnt = 0;
	}
	
	public void kick() {
		PrintWriter out = null;
		int addrBrk = 0;
		int line=6;
		if(ban) line = 9;
		try {
			Socket clientSocket3 = new Socket(in.substring(line),PORT+1);
			InetAddress address = clientSocket3.getInetAddress();
			out = new PrintWriter(clientSocket3.getOutputStream(), true);
			out.println("You have been kicked off!");
			clientSocket3.close();
			for(int i=0; i<address.toString().length(); i++) if(address.toString().charAt(i) == '/') addrBrk = i;
			if(ban) {
				kicked[kickCnt] = address.toString().substring(addrBrk+1);
				kickCnt++;
			}
			for(int k=0; k<addrCnt-1; k++) if(address.toString().substring(addrBrk+1).equals(addresses[k])) for(int l=k;l<addrCnt-1; l++) addresses[l] = addresses[l+1];
			addrCnt--;
			in = in.substring(line) + " has been kicked out.\n";
			send();
		} catch (UnknownHostException e) {
			Received[0] = "Couldn't Send Kicked Message!\n";
		} catch (IOException e) {
			Received[0] = "Couldn't Send Kicked Message!\n";
		}
	}
	
	public void unkick() {
		boolean found = false;
		PrintWriter out = null;
		int addrBrk = 0;
		for(int i=9; i>0; i--) Received[i] = Received[i-1];
		for(int k=0; k<kickCnt; k++) {
			if(in.substring(8).equals(kicked[k])) {
				found = true;
				for(int l=k;l<kickCnt; l++) kicked[l] = kicked[l+1];
			}
		}
		kickCnt--;
		if(found) Received[0] = in.substring(8) + " has been allowed back.\n";
		else Received[0] = in.substring(8) + " wasn't in the kicked list. Make sure you entered an IP address.\n";
	}
	
	public void IP() {
		try {
			for(int i=9; i>0; i--) Received[i] = Received[i-1];
			clientSocket2 = new Socket(in.substring(4),PORT+1);
			InetAddress address = clientSocket.getInetAddress();
			Received[0] = address.toString() + "\n";
			clientSocket2.close();
		} catch (UnknownHostException e) {
			Received[0] = "Couldn't Resolve IP\n";
		} catch (IOException e) {
			Received[0] = "Couldn't Resolve IP\n";
		}
	}
	
	public void kicked() {
		for(int i=9; i>0; i--) Received[i] = Received[i-1];
		Received[0] = "";
		if(kickCnt == 0) Received[0] = "No users kicked";
		else for(int i=0; i<kickCnt; i++) Received[0] += kicked[i] + ", ";
		Received[0] += "\n";
	}
	
	public void users() {
		if(!userSend) for(int i=9; i>0; i--) Received[i] = Received[i-1];
		userList = "";
		if(addrCnt == 0) userList = "No users online";
		else for(int i=0; i<addrCnt; i++) userList += addresses[i] + ", ";
		userList += "\n";
		if(!userSend) Received[0] = userList;
	}
	
	public void file() {
		for(int i=9; i>0; i--) Received[i] = Received[i-1];
		Received[0] = "Sending file to " + in.substring(6) + ", Please wait\n";
		FileTrans filetrans = new FileTrans((in.substring(6)),(PORT+2),false);
	}
	
	public void fileIN() {
		for(int i=9; i>0; i--) Received[i] = Received[i-1];
		Received[0] = "Receiving file, Please wait\n";
		FileTrans filetrans = new FileTrans(PORT+2);
		fileIn = false;
	}
	
	public void log() {
		LOG_PATH = new File(in.substring(5));
		for(int i=9; i>0; i--) Received[i] = Received[i-1];
		Received[0] = "Log path changed to " + LOG_PATH + "\n";
	}
	
	public void whisper() {
		int line = in.substring(3).indexOf(' ');
		String ipAddr = in.substring(3,3+line);
		for(int i=9; i>0; i--) Received[i] = Received[i-1];
		try {
			Socket whisp = new Socket(ipAddr, PORT+1);
			PrintWriter out = new PrintWriter(whisp.getOutputStream(), true);
			out.println("Admin whispers: " + in.substring(3+line));
			whisp.close();
			Received[0] = "Whispering to " + ipAddr + ": " + in.substring(3+line) + "\n";
		} catch (UnknownHostException e) {
			Received[0] = "Couldn't Whisper to " + ipAddr + "!\n";
		} catch (IOException e) {
			Received[0] = "Couldn't Whisper to " + ipAddr + "!\n";
		}
	}
	
	public void about() {
		JOptionPane.showMessageDialog(null,"About " + WINDOW_NAME + ":\nVersion 1.0b\nWritten by Benjamin Zastovnik\nMarch 9, 2004", "About " + WINDOW_NAME, JOptionPane.PLAIN_MESSAGE);
	}
		
	public void actionPerformed(ActionEvent e) {
		if(e.getSource() == exit) {
			System.exit(0);
		}
		if(e.getSource() == send) {
			in = input.getText();
			if(in.equals(""));
			else msgOut();
		}
		if(e.getSource() == input) {
			in = input.getText();
			if(in.equals(""));
			else msgOut();
		}
	}
	public static void main(String args[])
	throws IOException {
		Server window = new Server();
	}
}