import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;
import java.util.StringTokenizer;

/**
 * Serves Hangman for HTTP (the browser version of the Hangman game). All
 * methods and fields are static.
 */
public final class WebServer {
	// TODO TCP-Server-Socket definition.
	private static ServerSocket welcomeSocket;



	/** HTTP EOL sequence. */
	private static final String EOL = "\r\n";// TODO

	/**
	 * Session ID to distinguish between the current and previous game sessions.
	 */
	private static int session;

	/** Session ID cookie of the currently handled request. */
	private static int sessionCookie;

	/** Player number of the currently handled request. */
	private static int playerCookie;

	/** Hangman game object. */
	private static Hangman hangman;

	/** Used to save the result message of the previous action. */
	private static String prevMsg;

	/** Number of players. */
	private static final int NUM_PLAYERS = 2;

	/** Currently active player (0 - n-1). */
	private static int curPlayer;

	/**
	 * Indicates whether we are already in-game or still waiting for some
	 * players.
	 */
	private static boolean gameStarted = false;

	/** Indicates whether the game has ended. */
	private static boolean gameEnded = false;

	/**
	 * Initializes the game. Loops until solution is found or hangman is dead.
	 * 
	 * @param argv
	 *            Optional command line arguments.
	 * @throws Exception
	 */
	public static void main(String[] argv) throws Exception {
		// TODO Initialize socket, global variables and hangman.
		welcomeSocket = new ServerSocket(2345);
		hangman = new Hangman();
		curPlayer = 0;
		session = 0;


		while (true) {
			// TODO Accept client request.
			Socket clientSocket = welcomeSocket.accept();

			BufferedReader br = new BufferedReader(
				new InputStreamReader(clientSocket.getInputStream(), "UTF-8")); // TODO
			BufferedWriter bw = new BufferedWriter(
				new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8")); // TODO

			if (!gameStarted && !gameEnded) {
				processInitRequest(br, bw);
			} else if (gameStarted && !gameEnded) {
				processGameRequest(br, bw);
			} else {
				processEndRequest(br, bw);
				if (curPlayer == NUM_PLAYERS)
					break;
			}
			br.close();
			bw.close();

		}
		welcomeSocket.close();

	}

	/**
	 * Handles HTTP conversation when game has not yet started. Waits for number
	 * of players {@link #NUM_PLAYERS NUM_PLAYERS} to be present.
	 * 
	 * @param br
	 *            The BufferedReader used to read the request.
	 * @param bw
	 *            The BufferedWriter used to write the HTTP response.
	 * @throws Exception
	 */
	private static void processInitRequest(BufferedReader br, BufferedWriter bw)
			throws Exception {
		// TODO Process request and header lines.
		String request = processHeaderLines(br, bw);
		if(request == null)
				return;


		String cookieLines = null;
		String content = "<HTML><HEAD><META http-equiv=\"refresh\" content=\"2\"><TITLE>Hangman</TITLE></HEAD><BODY>"
				+ "<PRE>[ ] [ ]-[ ]<BR>         |<BR>[ ]     [ ]<BR> |     /<BR>[ ]-[ ]<BR>____________</PRE>"
				+ "Willkommen zu I7Hangman!<BR>Du bist Spieler ";
		// TODO If the player is unknown: set cookies and increment curPlayer.
		// Add player number to content.
		if(playerCookie == -1) {
			cookieLines = "sessionCookie="
			+Integer.toString(sessionCookie)+", playerCookie="+
			Integer.toString(curPlayer);
			content += Integer.toString(curPlayer);
			curPlayer++;
			System.out.println("\n new player\n");
		} else {
			content += Integer.toString(playerCookie);
		}


		content += ".<BR>Es darf reihum ein Buchstabe geraten werden.<BR>Die Seite lädt automatisch neu.<BR>"
				+ "Warte auf alle Spieler...</BODY></HTML>";

		// TODO Send response to player.
		sendOkResponse(bw, cookieLines, content);


		if (curPlayer == NUM_PLAYERS) {
			System.out.println("\n Goooooo\n");
			gameStarted = true;
			curPlayer = 0;
		}
	}

	/**
	 * Handles HTTP conversation when game is running. Differentiates between
	 * current player and other players.
	 * 
	 * @param br
	 *            The BufferedReader used to read the request.
	 * @param bw
	 *            The BufferedWriter used to write the HTTP response.
	 * @throws Exception
	 */
	private static void processGameRequest(BufferedReader br, BufferedWriter bw)
			throws Exception {
		// TODO Process request and header lines.
		String requestLine = processHeaderLines(br, bw);
		if(requestLine == null)
			return;
		requestLine = requestLine.replace("/?", "");
		requestLine = requestLine.replace(" ", "=");
		String[] requestLineArray = requestLine.split("=");




		// Construct the response message.
		String content = "<HTML><HEAD><TITLE>Hangman</TITLE>";

		if (session == 1 && curPlayer == playerCookie)// TODO Player is current player and form was submitted.
		{
			session = 0;
			System.out.println("\n\n\n"+requestLineArray[0]+"-");
			System.out.println(""+requestLineArray[1]+"\n\n\n");
			if (requestLineArray[1].equals("letter"))// TODO Handle single character guess.
			{

				String answer = hangman.checkCharHtml(requestLineArray[2].charAt(0));
				prevMsg = answer;

			} else if (requestLineArray[1].equals("solution"))// TODO Handle word guess.
			{

				String answer = hangman.checkWordHtml(requestLineArray[2]);
				prevMsg = answer;



			}
			// TODO Set curPlayer to next player.
			curPlayer++;
			if(curPlayer == NUM_PLAYERS)
				curPlayer = 0;

			content += "<META http-equiv=\"refresh\" content=\"0;url=/\"></HEAD><BODY>"
					+ "<PRE>[ ] [ ]-[ ]<BR>         |<BR>[ ]     [ ]<BR> |     /<BR>[ ]-[ ]<BR>____________</PRE>"
					+ prevMsg
					+ hangman.getHangmanHtml()
					+ "Spieler "
					+ curPlayer + " ist an der Reihe.";

		} else if (curPlayer == playerCookie)// TODO Player is current player.
		{
			content += "</HEAD><BODY>"
					+ "<PRE>[ ] [ ]-[ ]<BR>         |<BR>[ ]     [ ]<BR> |     /<BR>[ ]-[ ]<BR>____________</PRE>"
					+ prevMsg + hangman.getHangmanHtml()
					+ "Du bist an der Reihe, Spieler " + curPlayer + "!"
					+ "<FORM action=\"/\" method=\"get\">";
			for (char i = 'a'; i <= 'z'; ++i) {
				content += "<INPUT type=\"submit\" name=\"letter\" value=\""
						+ i + "\">";
			}
			content += "</FORM><BR><FORM action=\"/\" method=\"get\">"
					+ "<LABEL>Suchbegriff <INPUT name=\"solution\"></LABEL>"
					+ "<BUTTON>Lösen</BUTTON></FORM>";
			session = 1;
		} else {
			content += "<META http-equiv=\"refresh\" content=\"2;url=/\"></HEAD><BODY>"
					+ "<PRE>[ ] [ ]-[ ]<BR>         |<BR>[ ]     [ ]<BR> |     /<BR>[ ]-[ ]<BR>____________</PRE>"
					+ prevMsg
					+ hangman.getHangmanHtml()
					+ "Spieler "
					+ curPlayer + " ist an der Reihe.";
		}
		content += "</BODY></HTML>";

		// TODO Send response to player.
		sendOkResponse(bw, null, content);


		if (hangman.win() || hangman.dead()) {
			gameStarted = false;
			gameEnded = true;
			curPlayer = 0;
		}
	}

	/**
	 * Handles HTTP conversation when game ended.
	 * 
	 * @param br
	 *            The BufferedReader used to read the request.
	 * @param bw
	 *            The BufferedWriter used to write the HTTP response.
	 * @throws Exception
	 */
	private static void processEndRequest(BufferedReader br, BufferedWriter bw)
			throws Exception {
		// TODO Process request and header lines.
		String requestLine = processHeaderLines(br, bw);
		if(requestLine == null)
			return;


		String content = "<HTML><HEAD><TITLE>Hangman</TITLE></HEAD><BODY>"
				+ "<PRE>[ ] [ ]-[ ]<BR>         |<BR>[ ]     [ ]<BR> |     /<BR>[ ]-[ ]<BR>____________</PRE>"
				+ prevMsg + hangman.getHangmanHtml();

		// TODO Add success/fail line with solution word.


		content += "</BODY></HTML>";

		++curPlayer;
		// TODO Send response to player.
		String cookieLine = "sessionCookie="
		+Integer.toString(-1)+"; playerCookie="+
		Integer.toString(-1);
		sendOkResponse(bw, cookieLine, content);

	}

	/**
	 * Processes the HTTP request and its header lines.
	 * 
	 * @param br
	 *            The BufferedReader used to read the request.
	 * @param bw
	 *            The BufferedWriter used to write the HTTP response.
	 * @return The request line of the HTTP request if it is a valid game
	 *         related request, otherwise null.
	 * @throws Exception
	 */
	private static String processHeaderLines(BufferedReader br,
			BufferedWriter bw) throws Exception {
		/*
		 * TODO Get the request line of the HTTP request message. Return null if
		 * its length is zero or if end of stream is reached. Print out the
		 * request line to the console. If the request is for "/favicon.ico",
		 * send a 404 response and return null.
		 */
		String request = br.readLine();
		if(request == null) {
			sendNotFoundResponse(bw);
			return null;
		}
		if(request.isEmpty()) {
			sendNotFoundResponse(bw);
			return null;
		}
		String[] rqst_array = request.split(" ");

		if(rqst_array[1].equals("/favicon.ico")) {
			sendNotFoundResponse(bw);
			return null;
		}
		System.out.println(request);



		sessionCookie = -1;
		playerCookie = -1;

		// TODO Step through all remaining header lines and extract cookies if
		// present (yamyam). Optionally print the header lines to the console.
		String r;
		while(!(r = br.readLine()).isEmpty()) {
			System.out.println(r);
			if(r.startsWith("Cookie")) {
				r = r.replace(",", "");
				String[] cookieArray = r.split(" ");
				sessionCookie = Integer.parseInt(cookieArray[1].split("=")[1]);
				playerCookie = Integer.parseInt(cookieArray[2].split("=")[1]);
			}
		}


		// TODO Return
		return request;
	}

	/**
	 * Sends a 404 HTTP response.
	 * 
	 * @param bw
	 *            The BufferedWriter used to write the HTTP response.
	 * @throws Exception
	 */
	private static void sendNotFoundResponse(BufferedWriter bw)
			throws Exception {
		// TODO Construct and send a valid HTTP/1.0 404-response.
		bw.write("HTTP/1.1 404 Not Found"+EOL);
		bw.write("Content-Length: 0"+EOL);
		bw.write(EOL);
		bw.flush();

	}

	/**
	 * Sends a HTTP response with cookies (if set) and HTML content.
	 * 
	 * @param bw
	 *            The BufferedWriter used to write the HTTP response.
	 * @param cookieLines
	 *            Optional header lines to set cookies.
	 * @param content
	 *            The actual HTML content to be sent to the browser.
	 * @throws Exception
	 */
	private static void sendOkResponse(BufferedWriter bw, String cookieLines,
			String content) throws Exception {
		// TODO Construct and send a valid HTTP/1.0 200-response with the given
		// cookies (if not null) and the given content.

		bw.write("HTTP/1.1 200 OK"+ EOL);
		bw.write("Connection: close"+ EOL);
		bw.write("Date: " + new java.util.Date() + EOL);
		bw.write("Server: Java HTTP Server 1.0" + EOL);
		bw.write("Content-Length: "+Integer.toString(content.length())+EOL);
		bw.write("Content-Type: text/html; charset=utf8"+ EOL);
		if(cookieLines != null && !cookieLines.isEmpty()) {
			bw.write("Set-Cookie: "+cookieLines+EOL);
		}
		bw.write(EOL);
		bw.write(content);
		bw.flush();
	}
}