/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

package foam.nanos.http;

import foam.box.Box;
import foam.box.SessionServerBox;
import foam.core.FObject;
import foam.core.ProxyX;
import foam.core.X;
import foam.lib.json.ExprParser;
import foam.lib.json.JSONParser;
import foam.lib.parse.*;
import foam.nanos.jetty.HttpServer;
import foam.nanos.logger.Logger;
import foam.nanos.servlet.VirtualHostRoutingServlet;

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

@SuppressWarnings("serial")
public class ServiceWebAgent
    implements WebAgent
{
  public static final int BUFFER_SIZE = 4096;

  protected static ThreadLocal<StringBuilder> sb = new ThreadLocal<StringBuilder>() {
    @Override
    protected StringBuilder initialValue() {
      return new StringBuilder();
    }

    @Override
    public StringBuilder get() {
      StringBuilder b = super.get();
      b.setLength(0);
      return b;
    }
  };

  protected Box     skeleton_;
  protected boolean authenticate_;

  public ServiceWebAgent(Box skeleton, boolean authenticate) {
    skeleton_     = skeleton;
    authenticate_ = authenticate;
  }

/*
  public X    getX() { return x_; }
  public void setX(X x) {
    x_ = x;
    if ( skeleton_ instanceof ContextAware )
      ((ContextAware) skeleton_).setX(x);
  }
*/

/*
  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    resp.setHeader("Access-Control-Allow-Origin", "*");
    resp.setStatus(resp.SC_OK);
    resp.flushBuffer();
  }
*/

  public void execute(X x) {
    try {
      HttpServletRequest  req            = x.get(HttpServletRequest.class);
      HttpServletResponse resp           = x.get(HttpServletResponse.class);
      PrintWriter         out            = x.get(PrintWriter.class);
      BufferedReader      reader         = req.getReader();
      X                   requestContext = x.put("httpRequest", req).put("httpResponse", resp);
      Logger              logger         = (Logger) x.get("logger");
      HttpServer          http           = (HttpServer) x.get("http");

      ((VirtualHostRoutingServlet) http.getServletMappings()[0].getServletObject()).getHostMapping().forEach((k,v) -> {
        if ( req.getHeader("Origin").equals(String.format("http://%s:%d", k, http.getPort())) )
          resp.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
      });

      int read = 0;
      int count = 0;
      int length = req.getContentLength();

      StringBuilder builder = sb.get();
      char[] cbuffer = new char[BUFFER_SIZE];
      while ( ( read = reader.read(cbuffer, 0, BUFFER_SIZE)) != -1 && count < length ) {
        builder.append(cbuffer, 0, read);
        count += read;
      }

      FObject result;
      try {
        result = requestContext.create(JSONParser.class).parseString(builder.toString());
      } catch (Throwable t) {
        System.err.println("Unable to parse: " + builder.toString());
        throw t;
      }

      if ( result == null ) {
        resp.setStatus(resp.SC_BAD_REQUEST);
        String message = getParsingError(x, builder.toString());
        logger.error("JSON parse error: " + message + ", input: " + builder.toString());
        out.flush();
        return;
      }

      if ( ! ( result instanceof foam.box.Message ) ) {
        resp.setStatus(resp.SC_BAD_REQUEST);
        logger.error("Expected instance of foam.box.Message");
        out.print("Expected instance of foam.box.Message");
        out.flush();
        return;
      }

      foam.box.Message msg = (foam.box.Message) result;
      new SessionServerBox(x, skeleton_, authenticate_).send(msg);
    } catch (Throwable t) {
      throw new RuntimeException(t);
    }
  }

  /**
   * Gets the result of a failing parsing of a buffer
   * @param buffer the buffer that failed to be parsed
   * @return the error message
   */
  protected String getParsingError(X x, String buffer) {
    Parser        parser = ExprParser.instance();
    PStream       ps     = new StringPStream();
    ParserContext psx    = new ParserContextImpl();

    ((StringPStream) ps).setString(buffer);
    psx.set("X", x == null ? new ProxyX() : x);

    ErrorReportingPStream eps = new ErrorReportingPStream(ps);
    ps = eps.apply(parser, psx);
    return eps.getMessage();
  }

/*
  public void doOptions(HttpServletRequest req, HttpServletResponse resp)
    throws IOException, ServletException
  {
    resp.setHeader("Access-Control-Allow-Origins", "*");
    resp.setHeader("Access-Control-Allow-Methods", "GET POST");
    resp.setHeader("Access-Control-Allow-Headers", "Content-Type");
    super.doOptions(req, resp);
  }
  */
}

@@ -143,16 +143,44 @@
 .http;%0A%0A
+import foam.nanos.app.Mode;%0A
 import f
@@ -188,24 +188,24 @@
 am.box.Box;%0A
-
 import foam.
@@ -388,16 +388,85 @@
 arse.*;%0A
+import foam.nanos.app.AppConfig;%0Aimport foam.nanos.jetty.HttpServer;%0A
 import f
@@ -700,24 +700,24 @@
 eredReader;%0A
-
 import java.
@@ -731,16 +731,37 @@
 tWriter;
+%0Aimport java.net.URL;
 %0A%0A@Suppr
@@ -2369,215 +2369,387 @@
     
-((VirtualHostRoutingServlet) http.getServletMappings()%5B0%5D.getServletObject()).getHostMapping().forEach((k,v) -%3E %7B%0A        if ( req.getHeader(%22Origin%22).equals(String.format(%22http://%25s:%25d%22, k, http
+if ( ((AppConfig) x.get(%22appConfig%22)).getMode() != Mode.PRODUCTION ) %7B%0A        resp.setHeader(%22Access-Control-Allow-Origin%22, %22*%22);%0A      %7D else if ( ! req.getHeader(%22Origin%22).equals(%22null%22) )%7B%0A        URL url = new URL(req.getHeader(%22Origin%22));%0A        if ( ((VirtualHostRoutingServlet) http.getServletMappings()%5B0%5D.getServletObject()).getHostMapping().containsKey(url
 .get
-Por
+Hos
 t())
-)
  )%0A 
@@ -2833,17 +2833,15 @@
 ));%0A
+
       %7D
-);
 %0A%0A  

Add Joel's changes and change lookup for host name key