/**
 * 
 */
package org.ajax4jsf.config;

import java.io.StringReader;
import java.util.List;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

/**
 * @author asmirnov
 *
 */
public class FacesConfigHandler extends DefaultHandler {


	private static final String JEE_NS = "http://java.sun.com/xml/ns/javaee";
	private static final String BRIDGE_NS = "http://www.apache.org/myfaces/xml/ns/bridge/bridge-extension";
	private static final String APPLICATION_ELEMENT          = "application";
    private static final String APP_EXTENSION_ELEMENT     = "application-extension";
    private static final String EXCLUDED_ATTRIBUTES_ELEMENT    = "excluded-attributes";
    private static final String EXCLUDED_ATTRIBUTE_ELEMENT  = "excluded-attribute";

    private List<String> excludedAttributes;
	private XMLReader reader;

	public FacesConfigHandler(XMLReader reader, List<String> excludedAttributes) {
		this.reader = reader;
		this.excludedAttributes = excludedAttributes;
	}

	@Override
	public void startElement(String uri, String localName, String name,
			Attributes attributes) throws SAXException {
		if (APPLICATION_ELEMENT.equals(localName) && JEE_NS.equals(uri)) {
			reader.setContentHandler(new ApplicationHandler());
		}
	}
	
    @Override
    public InputSource resolveEntity(String publicId, String systemId) throws SAXException
    {
      // Do nothing, to avoid network requests to external DTD/Schema
      return new InputSource(new StringReader(""));
    }

    private abstract class FacesConfigElementHandler extends StateHandler {
    	
    	
    	public FacesConfigElementHandler(ContentHandler parentHandler) {
			super(parentHandler);
		}

		@Override
    	protected XMLReader getReader() {
    		return reader;
    	}
    }

    /**
	 * @author asmirnov
	 *
	 */
	private class ApplicationHandler extends FacesConfigElementHandler {
		public ApplicationHandler() {
			super(FacesConfigHandler.this);
		}
		
		@Override
		protected ContentHandler getNextHandler(String uri, String localName,
				Attributes attributes) {
			if(APP_EXTENSION_ELEMENT.equals(localName) && JEE_NS.equals(uri)){
				return new ApplicationExtensionHandler(this);
			} else {
				return null;
			}
		}
	
	}

    /**
	 * @author asmirnov
	 *
	 */
	private class ApplicationExtensionHandler extends FacesConfigElementHandler {
		public ApplicationExtensionHandler(ContentHandler parent) {
			super(parent);
		}
		
		@Override
		protected ContentHandler getNextHandler(String uri, String localName,
				Attributes attributes) {
			if(EXCLUDED_ATTRIBUTES_ELEMENT.equals(localName) && BRIDGE_NS.equals(uri)){
				return new ExcludedAttributesHandler(this);
			} else {
				return null;
			}
		}
	
	}
	
    /**
	 * @author asmirnov
	 *
	 */
	private class ExcludedAttributesHandler extends FacesConfigElementHandler {

		public ExcludedAttributesHandler(ContentHandler parent) {
			super(parent);
		}
		
		@Override
		protected ContentHandler getNextHandler(String uri, String localName,
				Attributes attributes) {
			if(EXCLUDED_ATTRIBUTE_ELEMENT.equals(localName) && BRIDGE_NS.equals(uri)){
				return new ExcludedAttributeHandler(this);
			} else {
				return null;
			}
		}
	
	}
	/**
	 * @author asmirnov
	 *
	 */
	private class ExcludedAttributeHandler extends StringContentHandler {

		public ExcludedAttributeHandler(ContentHandler parent) {
			super(reader, parent, new StringBuilder());
		}

		@Override
		protected void endLastElement() {
			excludedAttributes.add(getResult().toString());
		}
	}

}
