import java.io.*;
import java.net.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.nio.file.*;

class HttpServer implements Runnable {

    private ServerSocket serverSocket;
    private ExecutorService pool;
    private final int port;

    public static void main(String[] args) throws IOException {
        System.out.println("Starting http server...");
        int port = 80;
        if(args.length == 1) {
            port = Integer.parseInt(args[0]);
        }
        Thread httpServer = new Thread(new HttpServer(port));
        httpServer.start();
    }

    HttpServer(int port) {
        this.port = port;
    }

    public void run() {

        try {
            serverSocket = new ServerSocket(this.port);
            pool = Executors.newCachedThreadPool();

            while(true) {
                Socket socket = serverSocket.accept();
                pool.execute(new Handler(socket));
            }
        } catch(IOException ex) {
        } finally {
        }
    }
}

class Handler implements Runnable {

    private final Socket client;

    Handler(Socket client) {
        this.client = client;
    }

    public void run() {


        try {
            char[] buffer = new char[1024];
            BufferedReader bufferedReader = new BufferedReader(
                    new InputStreamReader(client.getInputStream())
                    );
            BufferedOutputStream output = new BufferedOutputStream(this.client.getOutputStream());

            int count = bufferedReader.read(buffer, 0, 1024);
            String requestString = new String(buffer, 0, count);

            String[] lines = requestString.split("\n");

            if(lines.length < 1) {
                output.write("HTTP/1.1 400 Bad Request".getBytes());
                return;
            }

            String[] firstLine = lines[0].split("\\s");

            if(firstLine.length != 3 ||
                    firstLine[0].compareTo("GET") != 0 ||
                    firstLine[2].compareTo("HTTP/1.1") != 0
                    ) {
                        output.write("HTTP/1.1 400 Bad Request".getBytes());
                        return;
                    }

            String DOCUMENT_ROOT = "./testpage/";

            Path path = Paths.get(DOCUMENT_ROOT + firstLine[1]);

            System.out.println("Requested path: " + path);

            if(Files.exists(path) && Files.isDirectory(path)) {
                path = Paths.get(DOCUMENT_ROOT + firstLine[1] + "/index.html");
            }

            if(!Files.exists(path)) {

                output.write("HTTP/1.1 404 Not Found\n".getBytes());
                //output.write(("Content-Length: " + Files.size(path) + "\n").getBytes());
                output.write("\n".getBytes());

                BufferedInputStream bufferedInputStream = new BufferedInputStream(
                        getClass()
                            .getResourceAsStream("/404.html")
                        );
                int n;
                byte[] byteBuffer = new byte[1024];

                while((n = bufferedInputStream.read(byteBuffer)) > -1) {
                    output.write(byteBuffer, 0, n);
                }
                output.flush();
                return;
            }

            output.write("HTTP/1.1 200 OK\n".getBytes());
            output.write(("Content-Length: " + Files.size(path) + "\n").getBytes());
            output.write("\n".getBytes());

            BufferedInputStream bufferedInputStream = new BufferedInputStream(Files.newInputStream(path));
            int n;
            byte[] byteBuffer = new byte[1024];

            while((n = bufferedInputStream.read(byteBuffer)) > -1) {
                output.write(byteBuffer, 0, n);
            }
            output.flush();


        } catch(IOException ex) {
        } finally {
            if(!this.client.isClosed()) {
                try {
                    this.client.close();
                } catch(IOException ex) {
                }
            }
        }
    }

}

@@ -399,16 +399,57 @@
 er...%22);
+%0A%0A        //handle optional argument port
 %0A       
@@ -542,32 +542,96 @@
 s%5B0%5D);%0A        %7D
+%0A%0A        //start main thread that handles incomming connections
 %0A        Thread 
@@ -942,24 +942,148 @@
 ile(true) %7B%0A
+                //accept incomming connections and pass the socket to the new%0A                //thread from the thread pool%0A
             
@@ -1734,24 +1734,63 @@
 Stream());%0A%0A
+            //read request from client%0A
             
@@ -1901,24 +1901,58 @@
 0, count);%0A%0A
+            //get line base input%0A
             
@@ -1992,24 +1992,77 @@
 lit(%22%5Cn%22);%0A%0A
+            //return bad request if there is no line%0A
             
@@ -2184,32 +2184,86 @@
 %0A            %7D%0A%0A
+            //split first line to get path and method%0A
             Stri
@@ -2299,24 +2299,85 @@
 it(%22%5C%5Cs%22);%0A%0A
+            //only handle get requests and HTTP/1.1 requests%0A
             
@@ -2670,32 +2670,72 @@
              %7D%0A%0A
+            //place your documents here%0A
             Stri
@@ -2891,24 +2891,123 @@
 %22 + path);%0A%0A
+            //if directory is requested change path to default document in this%0A            //path%0A
             
@@ -3188,24 +3188,86 @@
 s(path)) %7B%0A%0A
+                //if file does not exist return 404 Not Found%0A
             
@@ -3339,18 +3339,16 @@
         
-//
 output.w
@@ -3356,54 +3356,12 @@
 ite(
-(%22Content-Length: %22 + Files.size(path) + 
 %22%5Cn%22
-)
 .get
@@ -3390,39 +3390,51 @@
     
-output.write(%22%5Cn%22.getBytes());%0A
+//load animated 404.html page from jar file
 %0A   
@@ -3919,32 +3919,102 @@
 %0A            %7D%0A%0A
+            //return requested file with Content-Length in the header%0A
             outp
@@ -4546,32 +4546,71 @@
 Exception ex) %7B%0A
+            //do not handle execptions%0A
         %7D finall

add documentation