package org.seasar.jsf.runtime;

import java.util.Stack;

import org.seasar.jsf.JsfConfig;
import org.seasar.jsf.TagProcessor;
import org.seasar.jsf.TagSelector;
import org.seasar.jsf.ViewTemplateFactory;
import org.seasar.jsf.processor.TextProcessor;
import org.seasar.jsf.processor.ViewProcessor;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

public class TagProcessorHandler extends DefaultHandler {
	
	private TagSelectors tagSelectors;
	
	private JsfConfig jsfConfig;
	
	private ViewTemplateFactory viewTemplateFactory;

	private Stack processorStack = new Stack();

	private TagProcessor root;

	public TagProcessorHandler(TagSelectors tagSelectors, JsfConfig jsfConfig,
			ViewTemplateFactory viewTemplateFactory) {
	
		this.tagSelectors = tagSelectors;
		this.jsfConfig = jsfConfig;
		this.viewTemplateFactory = viewTemplateFactory;
	}

	public TagProcessor getRoot() {
		return root;
	}

	public void startElement(String namespaceURI, String localName,
			String qName, Attributes attributes) {

		TagSelector selector = tagSelectors.getTagSelector(namespaceURI,
				localName, qName, attributes);
		TagProcessor processor = null;
		if (selector != null) {
			processor = selector.createProcessor();
		}
		if (!processorStack.isEmpty()) {
			TagProcessor parentProcessor = peekProcessor();
			if (parentProcessor != null) {
				parentProcessor.addChild(processor);
			}
		} else {
			root = new ViewProcessor(jsfConfig, viewTemplateFactory);
			root.addChild(processor);
		}
		processor.setup(namespaceURI, localName, qName, attributes, jsfConfig);
		processorStack.push(processor);
	}

	protected TagProcessor peekProcessor() {
		return (TagProcessor) processorStack.peek();
	}

	protected TagProcessor popProcessor() {
		return (TagProcessor) processorStack.pop();
	}

	public void characters(char[] buffer, int start, int length) {
		if (!processorStack.isEmpty()) {
			String content = new String(buffer, start, length);
			TagProcessor processor = peekProcessor();
			if (processor == null) {
				return;
			}
			processor.addChild(new TextProcessor(content));
		}
	}

	public void endElement(String namespaceURI, String localName, String qName) {
		popProcessor();
	}

	public void error(SAXParseException e) throws SAXException {
		throw e;
	}

	public void warning(SAXParseException e) throws SAXException {
		System.err.println(e);
	}
}