import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.TimeUnit;

import static spark.Spark.*;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.philihp.weblabora.model.*;
import org.apache.commons.codec.binary.Hex;

public class Main {

  private static ObjectMapper objectMapper = new ObjectMapper();

  private static Cache<String, String> cache =
      CacheBuilder.newBuilder()
          .maximumSize(100000)
          .expireAfterAccess(7, TimeUnit.DAYS)
          .build();

  public static void main(String[] args) {

    port(Integer.valueOf(System.getenv("PORT")));

    get("/:hash", "application/json", (request, response) -> {
      String hash = request.params(":hash");
      return cache.get(hash, () -> {
        response.status(404);
        return "{\"error\":\"Forgot state of board. Please retry.\"}";
      });
    });

    get("/", "application/json", (request, response) -> {;
      return Boolean.FALSE;
    });

    put("/", "application/json", (request, response) -> {
      String hash = hash(request.body());
      Board board = new Board();
      String[] tokens = request.body().split("\n+");
      for (String token : tokens) {
        MoveProcessor.processMove(board, token);
      }
      cache.put(hash, objectMapper.valueToTree(board).toString());
      response.redirect("/" + hash, 303); // very important to use 303
      return null;
    });

    options("/*", (request, response) -> {
      String accessControlRequestHeaders = request.headers("Access-Control-Request-Headers");
      if (accessControlRequestHeaders != null) {
        response.header("Access-Control-Allow-Headers", accessControlRequestHeaders);
      }

      String accessControlRequestMethod = request.headers("Access-Control-Request-Method");
      if (accessControlRequestMethod != null) {
        response.header("Access-Control-Allow-Methods", accessControlRequestMethod);
      }

      return "OK";
    });

    before((request,response)-> {
        response.header("Access-Control-Allow-Origin", "*");
    });

  }

  private static String hash(String contents) {
    try {
      MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
      messageDigest.update(contents.getBytes());
      return new String(Hex.encodeHex(messageDigest.digest())).substring(0, 8);
    } catch (NoSuchAlgorithmException e) {
      return Integer.toString(contents.hashCode());
    }
  }


}

@@ -1582,133 +1582,128 @@
     
-String accessControlRequestHeaders = request.headers(%22Access-Control-Request-Headers%22);%0A      if (accessControlRequestHeaders
+return %22OK%22;%0A    %7D);%0A%0A    before((request,response)-%3E %7B%0A      String origin = request.headers(%22Origin%22);%0A      if(origin
  != 
@@ -1760,45 +1760,23 @@
 low-
-Headers%22, accessControlRequestHeaders
+Origin%22, origin
 );%0A 
@@ -1778,25 +1778,24 @@
 n);%0A      %7D%0A
-%0A
       String
@@ -1799,34 +1799,15 @@
 ing 
-accessControlRequestMethod
+headers
  = r
@@ -1845,22 +1845,23 @@
 Request-
-Method
+Headers
 %22);%0A    
@@ -1870,34 +1870,15 @@
 if (
-accessControlRequestMethod
+headers
  != 
@@ -1935,44 +1935,25 @@
 low-
-Methods%22, accessControlRequestMethod
+Headers%22, headers
 );%0A 
@@ -1963,68 +1963,105 @@
   %7D%0A
-%0A
       
-return %22OK%22;%0A    %7D);%0A%0A    before((request,response)-%3E
+String method = request.headers(%22Access-Control-Request-Method%22);%0A      if (method != null)
  %7B%0A 
@@ -2109,22 +2109,34 @@
 low-
-Origin%22, %22*%22);
+Methods%22, method);%0A      %7D
 %0A   

Simplify CORS