package de.fuberlin.wiwiss.d2rs;

import java.util.regex.Pattern;

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

import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.context.Context;

import de.fuberlin.wiwiss.pubby.negotiation.ContentTypeNegotiator;
import de.fuberlin.wiwiss.pubby.negotiation.MediaRangeSpec;

public class VelocityWrapper {
	private final static String VELOCITY_ENGINE_INSTANCE = 
			"de.fuberlin.wiwiss.d2rs.VelocityHelper.VELOCITY_ENGINE_INSTANCE";
	private final static String VELOCITY_DEFAULT_CONTEXT = 
			"de.fuberlin.wiwiss.d2rs.VelocityHelper.VELOCITY_DEFAULT_CONTEXT";
	
	private final static String TEXTHTML_CONTENTTYPE = "text/html; charset=utf-8";
	private final static String APPLICATIONXML_CONTENTTYPE = "application/xhtml+xml; charset=utf-8";

	private final static ContentTypeNegotiator xhtmlNegotiator;
	
	static {
		xhtmlNegotiator = new ContentTypeNegotiator();

		// for clients that send nothing
		xhtmlNegotiator.setDefaultAccept(TEXTHTML_CONTENTTYPE);
		
		// for MSIE that sends */* without q
		xhtmlNegotiator.addUserAgentOverride(Pattern.compile("MSIE"), null, TEXTHTML_CONTENTTYPE);
		
		xhtmlNegotiator.addVariant(APPLICATIONXML_CONTENTTYPE + "; q=0.9");
		xhtmlNegotiator.addVariant(TEXTHTML_CONTENTTYPE + "; q=0.8");
	}
	
	
	public static synchronized void initEngine(D2RServer d2r, ServletContext servletContext) {
		try {
			VelocityEngine engine = new VelocityEngine(servletContext.getRealPath("/WEB-INF/velocity.properties"));
			engine.init();
			servletContext.setAttribute(VELOCITY_ENGINE_INSTANCE, engine);
			servletContext.setAttribute(VELOCITY_DEFAULT_CONTEXT, initDefaultContext(d2r));
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}

	private static Context initDefaultContext(D2RServer server) {
		Context context = new VelocityContext();
		context.put("truncated_results", new Boolean(server.hasTruncatedResults()));
		context.put("server_name", server.serverName());
		context.put("home_link", server.baseURI());
		return context;
	}
	
	private final VelocityEngine engine;
	private final Context context;
	private final HttpServletRequest request;
	private final HttpServletResponse response;
	
	public VelocityWrapper(HttpServlet servlet, HttpServletRequest request, HttpServletResponse response) {
		engine = (VelocityEngine) servlet.getServletContext().getAttribute(VELOCITY_ENGINE_INSTANCE);
		// TODO: Init context with default variables shared by all/many servlets
		Context defaultContext = (Context) servlet.getServletContext().getAttribute(VELOCITY_DEFAULT_CONTEXT);
		context = new VelocityContext(defaultContext);
		this.request = request;
		this.response = response;
	}
	
	public Context getContext() {
		return context;
	}
	
	public VelocityEngine getEngine() {
		return engine;
	}

	public void mergeTemplateXHTML(String templateName) {
		MediaRangeSpec bestMatch = xhtmlNegotiator.getBestMatch(
				request.getHeader("Accept"), request.getHeader("User-Agent"));
		response.addHeader("Content-Type", bestMatch != null ? bestMatch.getMediaType() : TEXTHTML_CONTENTTYPE);
		response.addHeader("Vary", "Accept, User-Agent");

		response.addHeader("Cache-Control", "no-cache");
		response.addHeader("Pragma", "no-cache");
		try {
			engine.mergeTemplate(templateName, context, response.getWriter());
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}
}
