package ciir.jfoley.chai.web.json;

import ciir.jfoley.chai.collections.util.ListFns;
import ciir.jfoley.chai.io.IO;
import ciir.jfoley.chai.web.Handler;
import ciir.jfoley.chai.web.ServerErr;
import ciir.jfoley.chai.web.WebServer;
import org.lemurproject.galago.utility.Parameters;
import org.lemurproject.galago.utility.json.JSONUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.util.List;
import java.util.Map;

/**
 * Needs the utility package from org.lemurproject.galago in order to parse JSON.
 * Super-simple JSON server.
 * @author jfoley
 */
public class JSONAPI {
  public static boolean appendRequestTime = true;

  public static WebServer start(int port, Map<String, JSONMethod> methods) {
    // check for silly mistakes.
    for (String s : methods.keySet()) {
      if(!s.startsWith("/")) {
        throw new IllegalArgumentException("API method that will never match on a path: <<"+s+">> does not start with /");
      }
    }
    return WebServer.create(port, new JSONHandler(methods)).start();
  }
  public static WebServer start(Parameters argp, Map<String, JSONMethod> methods) {
    // check for silly mistakes.
    for (String s : methods.keySet()) {
      if(!s.startsWith("/")) {
        throw new IllegalArgumentException("API method that will never match on a path: <<"+s+">> does not start with /");
      }
    }
    return WebServer.create(argp, new JSONHandler(methods)).start();
  }

  public static class JSONHandler implements Handler {
    public final Map<String, JSONMethod> methods;

    public JSONHandler(Map<String, JSONMethod> methods) {
      this.methods = methods;
    }

    @Override
    public void handle(HttpServletRequest req, HttpServletResponse resp) throws Exception {
      long startTime = System.currentTimeMillis();

      String method = req.getMethod();
      switch (method) {
        case "POST":
        case "GET":
          break;
        default:
          WebServer.sendErrorMsg(resp, "Bad method="+method, 400);
          return;
      }

      String path = req.getPathInfo();

      JSONMethod m = methods.get(path);
      if(m == null) {
        WebServer.sendErrorMsg(resp, "No such API method="+method, 404);
        return;
      }

      Parameters jreq = Parameters.create();
      if("POST".equals(method)) {
        String contentType = WebServer.getContentType(req);
        String encoding = req.getCharacterEncoding();
        if(encoding == null) {
          encoding = "UTF-8";
        }
        switch (contentType) {
          case "application/json":
          case "text/json":
            String jsonText = null;
            try (BufferedReader reader = req.getReader()) {
              jsonText = IO.readAll(reader);
              jreq = Parameters.parseString(jsonText);
            } catch (Throwable jsonParseError) {
              System.err.println("Can't parse:\t" + jsonText); // for debugging
              throw new ServerErr(400, "Bad Request - JSON Parse Error!");
            }
            break;
          default:
            throw new ServerErr(400, "Bad Request!");
        }
      }

      // allow any GET parameters to override body parameters
      jreq.copyFrom(parseGetParameters(req));

      Parameters jresp = m.process(jreq);
      if(jresp == null) {
        jresp = Parameters.create();
      }

      long endTime = System.currentTimeMillis();
      if(appendRequestTime) {
        jresp.put("requestTime", (endTime - startTime));
      }

      resp.setContentType("application/json");

      try (PrintWriter out = resp.getWriter()) {
        out.println(jresp.toString());
        resp.setStatus(200);
      }
    }
  }

  public static Parameters parseGetParameters(HttpServletRequest req) {
    Parameters out = Parameters.create();
    Map<String, List<String>> getP = WebServer.parseGetParameters(req);
    for (Map.Entry<String, List<String>> kv : getP.entrySet()) {
      List<String> vals = kv.getValue();
      if(vals.size() == 0) continue;
      if(vals.size() == 1) {
        out.put(kv.getKey(), JSONUtil.parseString(vals.get(0)));
      } else {
        out.put(kv.getKey(), ListFns.map(vals, JSONUtil::parseString));
      }
    }
    return out;
  }

}

@@ -107,13 +107,22 @@
 hai.
-io.IO
+string.StrUtil
 ;%0Aim
@@ -536,16 +536,52 @@
 til.Map;
+%0Aimport java.util.stream.Collectors;
 %0A%0A/**%0A *
@@ -2776,17 +2776,32 @@
     try 
-(
+%7B%0A              
 Buffered
@@ -2827,27 +2827,25 @@
 .getReader()
-) %7B
+;
 %0A           
@@ -2862,25 +2862,70 @@
 t = 
-IO.readAll(reader
+StrUtil.join(reader.lines().collect(Collectors.toList()), %22%5Cn%22
 );%0A 

use java 8 method of reading all with .lines() instead, in case mine is buggy wrt jetty's