package org.seasar.jsf.runtime;

import java.io.IOException;

import javax.faces.FactoryFinder;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;

import org.seasar.framework.container.servlet.S2ContainerServlet;
import org.seasar.jsf.JsfConfig;
import org.seasar.jsf.JsfContext;
import org.seasar.jsf.TagPool;
import org.seasar.jsf.ViewRenderer;
import org.seasar.jsf.ViewTemplate;
import org.seasar.jsf.ViewTemplateFactory;
import org.seasar.jsf.exception.JspRuntimeException;
import org.seasar.jsf.jsp.PageContextImpl;
import org.seasar.jsf.processor.ViewProcessor;

/**
 * @author higa
 *  
 */
public class ViewRendererImpl implements ViewRenderer {

	private JsfConfig jsfConfig;

	private ViewTemplateFactory viewTemplateFactory;

	private TagPool tagPool;

	public ViewRendererImpl(JsfConfig jsfConfig,
			ViewTemplateFactory viewTemplateFactory, TagPool tagPool) {

		this.jsfConfig = jsfConfig;
		this.viewTemplateFactory = viewTemplateFactory;
		this.tagPool = tagPool;
	}

	public void renderView(String path, HttpServletRequest request,
			HttpServletResponse response) throws IOException {

		String realPath = getServletContext().getRealPath(path);
		ViewTemplate template = viewTemplateFactory.getViewTemplate(realPath);
		ViewProcessor viewProcessor = (ViewProcessor) template.getRootTagProcessor();
		response.setCharacterEncoding(viewProcessor.getEncoding());
		response.setContentType(viewProcessor.getContentType());
		JsfContext jsfContext = createJsfContext(request, response);
		setupResponseWriter(jsfContext.getPageContext());
		try {
			viewProcessor.process(jsfContext, null);
		} catch (JspException ex) {
			throw new JspRuntimeException(ex);
		}
		jsfContext.getPageContext().getOut().flush();
	}

	protected Servlet getServlet() {
		return S2ContainerServlet.getInstance();
	}

	protected ServletConfig getServletConfig() {
		return getServlet().getServletConfig();
	}

	protected ServletContext getServletContext() {
		return getServletConfig().getServletContext();
	}

	protected JsfContext createJsfContext(HttpServletRequest request,
			HttpServletResponse response) throws IOException {

		PageContextImpl pageContext = new PageContextImpl();
		pageContext.initialize(getServlet(), request, response, null);
		return new JsfContextImpl(pageContext, jsfConfig, tagPool);
	}

	protected void setupResponseWriter(PageContext pageContext) {
		FacesContext context = FacesContext.getCurrentInstance();
		RenderKitFactory renderFactory = getRenderKitFactory();
		RenderKit renderKit = renderFactory.getRenderKit(context, context
				.getViewRoot().getRenderKitId());
		ServletResponse response = pageContext.getResponse();
		ResponseWriter writer = renderKit.createResponseWriter(
				pageContext.getOut(), 
				response.getContentType(),
				response.getCharacterEncoding());
		context.setResponseWriter(writer);
	}

	protected RenderKitFactory getRenderKitFactory() {
		return (RenderKitFactory) FactoryFinder
				.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
	}
}