package renderfarm;

import java.nio.file.Files;
import java.io.*;
import java.net.*;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

import java.util.Map;
import java.util.List;
import java.util.HashMap;
import java.util.ArrayList;

import raytracer.*;

public class LoadBalancer {

  public static final Integer PORT = 80;

  public static void main(String[] args) throws Exception {
    // Let's bind to all the supported ipv4 interfaces
    HttpServer server = HttpServer.create(new InetSocketAddress("0.0.0.0", PORT), 0);
    // Set routes
    server.createContext(WebUtils.RENDER_PATH, new RenderHandler());
    server.createContext(WebUtils.HEALTHCHECK_PATH, new HealthcheckHandler());
    // Multi thread support
    server.setExecutor(java.util.concurrent.Executors.newCachedThreadPool());
    server.start();
    System.out.println("Server running on port: " + PORT);
  }

  static String getInstance() {
    List<String> availableInstances = AWSUtils.getAvailableInstances();
    return availableInstances.get(0);
  }

  static class HealthcheckHandler implements HttpHandler {
    @Override
    public void handle(HttpExchange req) throws IOException {
      String outResponse = "OK";
      OutputStream os = req.getResponseBody();
      Integer responseCode = 200;
      req.sendResponseHeaders(responseCode, outResponse.length());
      os.write(outResponse.getBytes());
      os.close();
    }
  }


  static class RenderHandler implements HttpHandler {
    @Override
    public void handle(HttpExchange req) throws IOException {
      // Get the instance hostname to use
      String hostName = getInstance();
      // Assemble the URL
      String urlString = "http://" + hostName + req.getRequestURI();
      URL url = new URL(urlString);
      // Make the request
      HttpURLConnection conn = (HttpURLConnection) url.openConnection();
      conn.setRequestMethod("GET");
      conn.setConnectTimeout(50000); //set the timeout
      conn.connect();

      InputStream is = conn.getInputStream();
      int contentLength = conn.getContentLength();
      int responseCode = conn.getResponseCode();

      OutputStream os = req.getResponseBody();
      req.sendResponseHeaders(responseCode, contentLength);
      try {
        WebUtils.pipe(is, os);
      }
      catch (Exception e) {
        String outError = "Internal Server Error: " + e.getMessage();
        int response = 500;
        req.sendResponseHeaders(response, outError.length());
        os.write(outError.getBytes());
      } finally {
        is.close();
        os.close();
      }
    }
  }

}

@@ -359,29 +359,30 @@
 ancer %7B%0A%0A  p
-ublic
+rivate
  static fina
@@ -403,16 +403,85 @@
  = 80;%0A%0A
+  private static final Logger logger = new Logger(%22load-balancer%22);%0A%0A
   public
@@ -973,26 +973,18 @@
     
-System.out.println
+logger.log
 (%22Se
@@ -1680,24 +1680,128 @@
 Exception %7B%0A
+      Timer requestTimer = new Timer();%0A      Logger requestLogger = logger.getChild(%22render-handler%22);%0A
       // Get
@@ -1865,24 +1865,83 @@
 Instance();%0A
+      requestLogger.debug(%22Selected worker: %22 + hostName);%0A
       // Ass
@@ -2085,16 +2085,115 @@
 request%0A
+      requestLogger.debug(%22Sending request: %22 + urlString);%0A      Timer workerTimer = new Timer();%0A
       Ht
@@ -2516,16 +2516,106 @@
 eCode();
+%0A      requestLogger.debug(%22Worker processed request in %22 + workerTimer.getTime() + %22ms%22);
 %0A%0A      
@@ -2860,24 +2860,63 @@
 tMessage();%0A
+        requestLogger.error(outError);%0A
         int 
@@ -3066,24 +3066,24 @@
 is.close();%0A
-
         os.c
@@ -3086,24 +3086,105 @@
 os.close();%0A
+        requestLogger.debug(%22Request done in %22 + requestTimer.getTime() + %22ms%22);%0A
       %7D%0A    

Add proper logging and time monitoring to the load balancer class