package lu.tudor.santec.gecamed.core.gui.launcher;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.Iterator;
import java.util.LinkedHashMap;

import org.apache.log4j.Logger;


/**
 * @author Thorsten Roth thorsten.roth(at)tudor.lu
 *
 * @version
 * <br>$Log: ManagementServer.java,v $
 * <br>Revision 1.5  2013-12-27 18:09:27  donak
 * <br>Cleanup of imports
 * <br>
 * <br>Revision 1.4  2013-07-15 06:18:37  ferring
 * <br>logging changed
 * <br>
 * <br>Revision 1.3  2012-11-28 16:41:04  troth
 * <br>Version 1.3 of GECAMedLauncher and GECAMedLauncherServer 1.5.
 * <br>Some fixings in the LoginScreen.
 * <br>
 * <br>Revision 1.2  2012-10-31 16:40:47  troth
 * <br>Version 1.1 of GECAMed launcher.
 * <br>
 * <br>Revision 1.1  2012-10-19 16:24:42  troth
 * <br>First version of GECAMed launcher.
 * <br>
 */
public class ManagementServer {

	/**
	 * static logger for this class
	 */
	private static Logger logger = Logger.getLogger(ManagementServer.class.getName());
	
	private LinkedHashMap<String, ServerCommand> commands = new LinkedHashMap<String, ServerCommand>();
	
	private Thread 			serverRunningThread;
	private boolean 		running;
	private String 			serverName;
	private ServerSocket 	serverSocket;
	private int 			telnetPort;
	private int 			timeOut;
	

	public ManagementServer(String serverName, int telnetPort, int timeOutSec)
	{
		this.serverName = serverName;
		this.telnetPort = telnetPort;
		this.timeOut = timeOutSec;
	}
	
	/**
	 * opens a manage port that allows to start/stop/reload the server
	 */
	public void start()
	{
		running = true;
		serverRunningThread = new Thread()
		{
			public void run()
			{
				try {
					serverSocket = new ServerSocket(telnetPort);
					logger.info("openend new ManagementConnection at: "
							+ serverSocket.getLocalPort());
					while (running) {
						Socket incoming = serverSocket.accept();
						handleSocket(incoming);
						incoming.close();
					}
				} catch (Exception e) {
					logger.warn("Error: Can not openend new ManagementConnection at: " + serverSocket.getLocalPort(), e);
				}
			}

			public void handleSocket(Socket incoming) {
				try {
				    	running = true;
					incoming.setSoTimeout(timeOut * 1000); 
					BufferedReader reader = new BufferedReader(
							new InputStreamReader(incoming.getInputStream()));
					OutputStreamWriter writer = new OutputStreamWriter(incoming
							.getOutputStream());
					
					logger.info("openend new ServerManagementConnection at: "	+ incoming.getPort());
					System.out.println("openend new ServerManagementConnection at: "+ incoming.getPort());
					
					// accept connection and hold it as long the message have been received
					while (!incoming.isClosed())
					{
						if(!incoming.isClosed()) 
							writer = new OutputStreamWriter(incoming.getOutputStream());
						String serverCommandStr = reader.readLine();
						System.out.println("s: " +serverCommandStr);

						int splitPos = serverCommandStr.indexOf("=");
						// get command
						String cmd = null;
						try {
							cmd = serverCommandStr.substring(0, splitPos);
						} catch (Exception e) {
						}
						System.out.println("command: " + cmd);
						// get parameters
						String params = "";
						try {
							params = serverCommandStr.substring(splitPos+1);							
						} catch (Exception e) {
						}
						System.out.println("params: " + params);
						logger.info("received: " + serverCommandStr + "| on "
								+ incoming.getLocalAddress() + " from "
								+ incoming.getInetAddress());

						// handle commands
						if (cmd.toLowerCase().equals("info")) {
							writer.write("The following server commands are supported\n");
							for (Iterator<String> iter = commands.keySet().iterator(); iter
									.hasNext();) {
								String cmdName = (String) iter.next();
								ServerCommand serverCommand = commands.get(cmdName);
								writer.write("\t" + serverCommand.toString() + "\n");
							}
						} else {
							ServerCommand sc = commands.get(cmd);
							if (sc != null) {
								writer.write(sc.runCommand(params) + "\n");
							} else {
								writer.write("command '" + cmd + "=" + params + "' not supported\n");
							}
						}

						writer.flush();
						writer.close();
					}
				} catch (SocketTimeoutException e) {
					logger.info(serverName + " closing manage connection (SocketTimeOut)");
				} catch (ArrayIndexOutOfBoundsException e) {
					logger.info(serverName + " closing manage connection (wrong command send)");
				} catch (Exception e) {
					logger.warn("Error: Can not openend new ServerManagementConnection at: "	+ incoming.getPort(), e);
				}
			}

		};
		serverRunningThread.start();
	}
	
	public void registerCommand(ServerCommand serverCommand) {
		this.commands.put(serverCommand.getCommand(), serverCommand);
	}

	public void stop()
	{
		running = false;
		try {
			serverSocket.close();
		} catch (Exception e) {
			System.out.println("Error: Can not stop server thread.");
			logger.warn("Error: Can not stop server thread.\n" + e.getStackTrace());
			e.printStackTrace();
		}
	}	
}