package org.seasar.jsf.template.impl;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContext;

import org.cyberneko.html.parsers.SAXParser;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.exception.IORuntimeException;
import org.seasar.framework.exception.SAXRuntimeException;
import org.seasar.framework.util.ResourceUtil;
import org.seasar.jsf.template.TagSelector;
import org.seasar.jsf.template.ViewTemplate;
import org.seasar.jsf.template.ViewTemplateFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * @author higa
 *  
 */
public class ViewTemplateFactoryImpl implements ViewTemplateFactory {

	private S2Container container_;

	private String viewExtension_ = "html";

	private String encoding_ = "Windows-31j";
	
	private String contentType_ = "text/html;charset=" + encoding_;

	private TagSelectors tagSelectors_ = new TagSelectors();
	
	private Map viewTemplates_ = new HashMap();

	public ViewTemplateFactoryImpl() {
	}

	public String getViewExtension() {
		return viewExtension_;
	}

	public void setViewExtension(String viewExtension) {
		viewExtension_ = viewExtension;
	}

	public String getEncoding() {
		return encoding_;
	}

	public void setEncoding(String encoding) {
		encoding_ = encoding;
	}
	
	public String getContentType() {
		return contentType_;
	}

	public void setContentType(String contentType) {
		contentType_ = contentType;
	}

	/**
	 * @see org.seasar.jsf.template.ViewTemplateFactory#createViewTemplate(java.lang.String)
	 */
	public ViewTemplate getViewTemplate(String viewId) {
		ViewTemplate template = (ViewTemplate) viewTemplates_.get(viewId);
		if (template != null && !template.isModified()) {
			return template;
		}
		ServletContext ctx = container_.getRoot().getServletContext();
		SAXParser parser = createParser();
		String realPath = ctx.getRealPath(viewId);
		ViewTemplateHandler handler = new ViewTemplateHandler(tagSelectors_);
		parser.setContentHandler(handler);
		try {
			parser.parse(new InputSource(ctx.getResourceAsStream(viewId)));
		} catch (SAXException ex) {
			throw new SAXRuntimeException(ex);
		} catch (IOException ex) {
			throw new IORuntimeException(ex);
		}
		template = new ViewTemplateImpl(viewId, handler.getRoot(), new File(realPath));
		viewTemplates_.put(viewId, template);
		return template;
	}
	
	public String calculateViewId(String viewId) {
		return ResourceUtil.removeExtension(viewId) + "." + viewExtension_;
	}

	protected TagSelector getTagSelector(String namespaceURI, String localName,
			String qName, Attributes attributes) {
		
		return tagSelectors_.getTagSelector(namespaceURI, localName, qName, attributes);
	}

	/**
	 * @see org.seasar.jsf.template.ViewTemplateFactory#setContainer(org.seasar.framework.container.S2Container)
	 */
	public void setContainer(S2Container container) {
		container_ = container;
	}

	/**
	 * @see org.seasar.jsf.template.ViewTemplateFactory#addTagSelector(org.seasar.jsf.template.NodeHandler)
	 */
	public void addTagSelector(TagSelector tagSelector) {
		tagSelectors_.addTagSelector(tagSelector);
	}

	protected SAXParser createParser() {
		SAXParser parser = new SAXParser();
		try {
			parser.setProperty(
					"http://cyberneko.org/html/properties/default-encoding",
					encoding_);
			parser
					.setProperty(
							"http://cyberneko.org/html/properties/names/attrs",
							"default");
			parser
					.setProperty(
							"http://cyberneko.org/html/properties/names/elems",
							"match");
		} catch (SAXException ex) {
			throw new SAXRuntimeException(ex);
		}
		return parser;
	}
}