package org.pillowsky.securehttp;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.IOException;
import java.net.Socket;
import java.net.ServerSocket;
import java.net.InetAddress;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;

public class Peer implements Runnable {
	private String localAddr;
	private int localPort;
	private String remoteAddr;
	private int remotePort;
    private ServerSocket serverSocket;
    private ExecutorService pool;

    public Peer(String localAddr, int localPort, String remoteAddr, int remotePort) throws IOException {
    	this.localAddr = localAddr;
        this.localPort = localPort;
        this.remoteAddr = remoteAddr;
        this.remotePort = remotePort;
        this.serverSocket = new ServerSocket(localPort, 50, InetAddress.getByName(localAddr));
        this.pool = Executors.newCachedThreadPool();
    }

    @Override
    public void run() {
        while (true) {
            try {
                pool.execute(new RequestHandler(serverSocket.accept()));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public class RequestHandler implements Runnable {
        private Socket clientSocket;
        
        RequestHandler(Socket socket) {
            this.clientSocket = socket;
        }

        @Override
        public void run() {
            try {
                System.out.println("Received a connection");

                BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                PrintWriter out = new PrintWriter(clientSocket.getOutputStream());

                String response;
                String line = in.readLine();
                String[] words = line.split(" ");
                while (in.readLine().length() > 0) {};

                switch (words[0]) {
                	case "GET":
                		switch (words[1]) {
                			case "/":
                				response = local();
                				break;
                			default:
                				response = notFound();
                		}
                		break;
                	case "POST":
                		switch (words[1]) {
	                		case "/remote":
	                			response = remote();
	                			break;
	                		case "/portal":
	                			response = portal();
	                			break;
	                		default:
	                			response = notFound();
                		}
                		break;
                	default:
                		response = notFound();
                }

                out.print(response);
                out.flush();
                clientSocket.close();
            } catch(IOException e) {
                e.printStackTrace();
            }
        }

        private String local() {
        	StringBuilder body = new StringBuilder();
        	body.append("<form action='/remote' method='post'>");
        	body.append(String.format("<p>Local Page on %s:%d</p>", localAddr, localPort));
        	body.append("<input type='submit' value='Visit Remote Page' />");
        	body.append("</form>");
        	return buildResponse(body, "200 OK");
        }
        
        private String remote() {
        	try {
        		Socket proxySocket = new Socket(remoteAddr, remotePort);

                PrintStream out = new PrintStream(proxySocket.getOutputStream());
                InputStreamReader in = new InputStreamReader(proxySocket.getInputStream());

                out.println("POST /portal HTTP/1.1");
                out.println();
                out.flush();

                StringBuilder body = new StringBuilder();
                char[] buffer = new char[8192];

                while (in.read(buffer) > 0) {
                	body.append(buffer);
                }

                proxySocket.close();
            	return body.toString();
        	} catch(IOException e) {
                e.printStackTrace();
                return e.toString();
            }
        }
        
        private String portal() {
        	StringBuilder body = new StringBuilder();
        	body.append("<form action='/'>");
        	body.append(String.format("<p>Remote Page on %s:%d</p>", localAddr, localPort));
        	body.append("<input type='submit' value='Visit Local Page' />");
        	body.append("</form>");
        	return buildResponse(body, "200 OK");
        }

        private String notFound() {
        	return buildResponse("404 Not Found", "404 Not Found");
        }
        
        private String buildResponse(CharSequence body, String textStatus) {
        	StringBuilder response = new StringBuilder();
        	response.append(String.format("HTTP/1.1 %s%n", textStatus));
        	response.append("Server: SecureHTTP\n");
        	response.append("Connection: close\n");
        	response.append("Content-Type: text/html; charset=UTF-8\n");
        	response.append(String.format("Content-Length: %d%n%n", body.length()));
        	response.append(body);
        	response.append("\n\n");
        	return response.toString();
        }
    }
}

@@ -260,16 +260,80 @@
 ddress;%0A
+import java.text.DateFormat;%0Aimport java.text.SimpleDateFormat;%0A
 import j
@@ -407,16 +407,43 @@
 Service;
+%0Aimport java.util.Calendar;
 %0A%0Apublic
@@ -652,16 +652,50 @@
 ce pool;
+%0A    private DateFormat logFormat;
 %0A%0A    pu
@@ -1082,24 +1082,94 @@
 readPool();%0A
+        this.logFormat = new SimpleDateFormat(%22yyyy-MM-dd HH:mm:ss%22);%0A
     %7D%0A%0A    @
@@ -1508,24 +1508,91 @@
 ientSocket;%0A
+        private String clientAddr;%0A        private int clientPort;%0A
         %0A   
@@ -1664,24 +1664,144 @@
 t = socket;%0A
+            this.clientAddr = socket.getInetAddress().getHostAddress();%0A            this.clientPort = socket.getPort();%0A
         %7D%0A%0A 
@@ -1879,74 +1879,9 @@
     
-    System.out.println(%22Received a connection%22);%0A%0A                
+%09
 Buff
@@ -1978,28 +1978,25 @@
             
-    
+%09
 PrintWriter 
@@ -2235,16 +2235,150 @@
 0) %7B%7D;%0A%0A
+            %09System.out.format(%22%5B%25s%5D %25s:%25d %25s%25n%22, logFormat.format(Calendar.getInstance().getTime()), clientAddr, clientPort, line);%0A%0A
         
@@ -3591,32 +3591,121 @@
 r, localPort));%0A
+        %09body.append(String.format(%22%3Cp%3EAccess From %25s:%25d%3C/p%3E%22, clientAddr, clientPort));%0A
         %09body.ap
@@ -4904,32 +4904,121 @@
 r, localPort));%0A
+        %09body.append(String.format(%22%3Cp%3EAccess From %25s:%25d%3C/p%3E%22, clientAddr, clientPort));%0A
         %09body.ap

add log and access from