package org.latte;

import java.io.IOException;
import java.io.Serializable;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.BufferedReader;

import java.util.Set;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Enumeration;
import java.util.logging.Logger;
import java.util.logging.Level;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.Cookie;

import java.io.InputStreamReader;
import java.io.IOException;

import org.latte.scripting.PrimitiveWrapFactory;
import org.mozilla.javascript.Callable;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextFactory;
import org.mozilla.javascript.JavaScriptException;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.JSON;

import org.latte.scripting.Javascript;
import org.latte.scripting.ScriptLoader;

import org.apache.commons.codec.binary.Base64;

public class LatteServlet extends HttpServlet {
	private static final Logger LOG = Logger.getLogger(LatteServlet.class.getName());
	final private Scriptable parent;
	private Callable fn;

	public LatteServlet() throws Exception {
		ScriptLoader loader = new ScriptLoader();
		this.parent = loader.getRoot();

		loader.register("httpserver", new Callable() {
			public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] params) {
				fn = (Callable)params[1];	
				return null;
			}
		});

		((Javascript)loader.get("init.js")).eval(null);
	}
	
	public LatteServlet(Scriptable parent, Callable fn) {
		this.parent = parent;
		this.fn = fn;
	}

	/**
	 * 
	 */
	private static final long serialVersionUID = 5876743891237403945L;

	@Override
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {			
		try {
			Context cx = ContextFactory.getGlobal().enterContext();
			cx.setWrapFactory(new PrimitiveWrapFactory());
		
			Scriptable requestProxy = cx.newObject(parent);
			ScriptableObject.putProperty(requestProxy, "address", request.getRemoteAddr());
			ScriptableObject.putProperty(requestProxy, "remoteaddr", request.getRemoteAddr());
			ScriptableObject.putProperty(requestProxy, "url", request.getServletPath());
			Scriptable session;
			String sessionSource;
			if((sessionSource = (String)request.getSession().getAttribute("latte.session")) == null) {
				session = cx.newObject(parent);
			} else {
				session = (Scriptable)JSON.fromString(cx, parent, sessionSource);
			}

			String authorization = (String)request.getHeader("Authorization");
			if(authorization != null && authorization.startsWith("Basic"))  {
				ScriptableObject.putProperty(requestProxy, "authorization", new String(new Base64().decode(authorization.split(" ")[1].getBytes())));
			}

			if(request.getContentType() != null && request.getContentType().contains("message")) {
 				MimeMessage message = new MimeMessage(Session.getDefaultInstance(new Properties(), null), request.getInputStream());
				ScriptableObject.putProperty(requestProxy, "mail", message);	
			} else if(request.getContentType() != null && request.getContentType().contains("application/json")) {
				StringBuffer sb = new StringBuffer();
				BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
				String line;
				while((line = br.readLine()) != null) {
					sb.append(line);
				}
				
				ScriptableObject.putProperty(requestProxy, "content", sb.toString());
			} else {
				Scriptable params = cx.newObject(parent);

				for(Cookie cookie : request.getCookies()) {
					ScriptableObject.putProperty(params, cookie.getName(), cookie.getValue());
				}

				Enumeration paramNames = request.getParameterNames();
				while(paramNames.hasMoreElements()) {
					String key = (String)paramNames.nextElement();
					String[] values = request.getParameterValues(key);
					if(values.length == 1) {
						ScriptableObject.putProperty(params, key, values[0]);
					} else {
						ScriptableObject.putProperty(params, key, values);
					}
				}
				ScriptableObject.putProperty(requestProxy, "params", params);
			}
			
			fn.call(cx, parent, parent, new Object[] {
				requestProxy,
				response,
				session
			});

			sessionSource = JSON.stringify(cx, parent, session);
			request.getSession().setAttribute("latte.session", sessionSource);
		} catch(Exception e) {
			LOG.log(Level.SEVERE, "", e);
			response.sendError(500);
		} finally {
			Context.exit();
		}
	}
	
	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doPost(request, response);
	}
}

@@ -3868,16 +3868,56 @@
 rent);%0A%0A
+%09%09%09%09if(request.getCookies() != null) %7B%0A%09
 %09%09%09%09for(
@@ -3952,24 +3952,25 @@
 ookies()) %7B%0A
+%09
 %09%09%09%09%09Scripta
@@ -4033,24 +4033,31 @@
 etValue());%0A
+%09%09%09%09%09%7D%0A
 %09%09%09%09%7D%0A%0A%09%09%09%09E

add guard for NPE