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

import java.io.StringReader;
import java.util.ArrayList;
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 WebappHandler extends DefaultHandler {

	static final String SERVLET_MAPPING_ELEMENT = "servlet-mapping";

	static final String SERVLET_ELEMENT = "servlet";

	static final String SERVLET_NAME_ELEMENT = "servlet-name";

	static final String SERVLET_CLASS_ELEMENT = "servlet-class";

	static final String FILTER_MAPPING_ELEMENT = "filter-mapping";

	static final String FILTER_ELEMENT = "filter";

	static final String FILTER_NAME_ELEMENT = "filter-name";

	static final String FILTER_CLASS_ELEMENT = "filter-class";

	private List<ServletBean> servlets = new ArrayList<ServletBean>();
	
	private List<FilterBean> filters = new ArrayList<FilterBean>();

	private List<ServletMapping> servletMappings = new ArrayList<ServletMapping>();
	
	private List<FilterMapping> filterMappings = new ArrayList<FilterMapping>();

	private ServletBean facesServlet;

	private XMLReader xmlReader;

	static final String URL_PATTERN_ELEMENT = "url-pattern";


	public WebappHandler(XMLReader reader) {
		this.xmlReader = reader;
	}

	public List<FilterBean> getFilters() {
		return filters;
	}

	public List<FilterMapping> getFilterMappings() {
		return filterMappings;
	}

	public List<ServletBean> getServlets() {
		return servlets;
	}

	public List<ServletMapping> getServletMappings() {
		return servletMappings;
	}

	@Override
	public void startElement(String uri, String localName, String name,
			Attributes attributes) throws SAXException {
		if (SERVLET_ELEMENT.equals(localName)) {
			xmlReader.setContentHandler(new ServletHandler());
		} else if (SERVLET_MAPPING_ELEMENT.equals(localName)) {
			xmlReader.setContentHandler(new ServletMappingHandler());
		} else if (FILTER_ELEMENT.equals(localName)) {
			xmlReader.setContentHandler(new FilterHandler());
		} else if (FILTER_MAPPING_ELEMENT.equals(localName)) {
			xmlReader.setContentHandler(new FilterMappingHandler());
		}
	}

	@Override
    public InputSource resolveEntity(String publicId, String systemId) throws SAXException
    {
      // Do nothing, to avoid network requests for external DTD/Schema
      return new InputSource(new StringReader(""));
    }
    
    
    private abstract class WebappElementHandler extends StateHandler {
    	
    	
    	public WebappElementHandler(ContentHandler parentHandler) {
			super(parentHandler);
		}

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


	final class ServletHandler extends WebappElementHandler {

		private StringBuilder servletName = new StringBuilder();
		private StringBuilder servletClass = new StringBuilder();

		public ServletHandler() {
			super(WebappHandler.this);
		}

		@Override
		protected ContentHandler getNextHandler(String uri, String localName,
				Attributes attributes) {
			ContentHandler nextHandler = null;
			if (SERVLET_NAME_ELEMENT.equals(localName)) {
				nextHandler = new StringContentHandler(getReader(), this,
						servletName);
			} else if (SERVLET_CLASS_ELEMENT.equals(localName)) {
				nextHandler = new StringContentHandler(getReader(), this,
						servletClass);
			}
			return nextHandler;
		}

		@Override
		protected void endLastElement() {
			servlets.add(new ServletBean(servletName.toString().trim(),
					servletClass.toString().trim()));
		}
	}

	final class ServletMappingHandler extends WebappElementHandler {
	
		private StringBuilder servletName = new StringBuilder();
		private StringBuilder urlPattern = new StringBuilder();
	
		public ServletMappingHandler() {
			super(WebappHandler.this);
		}
	
		@Override
		protected ContentHandler getNextHandler(String uri, String localName,
				Attributes attributes) {
			ContentHandler nextHandler = null;
			if (SERVLET_NAME_ELEMENT.equals(localName)) {
				nextHandler = new StringContentHandler(getReader(), this,
						servletName);
			} else if (URL_PATTERN_ELEMENT.equals(localName)) {
				nextHandler = new StringContentHandler(getReader(), this,
						urlPattern);
			}
			return nextHandler;
		}
	
		@Override
		protected void endLastElement() {
			servletMappings.add(new ServletMapping(servletName.toString().trim(),
					urlPattern.toString().trim()));
		}
	}


	/**
	 * @author asmirnov
	 *
	 */
	public class FilterHandler extends WebappElementHandler {
		
		private StringBuilder filterName = new StringBuilder();
		private StringBuilder filterClass = new StringBuilder();


		public FilterHandler() {
			super(WebappHandler.this);
		}
		
		@Override
		protected ContentHandler getNextHandler(String uri, String localName,
				Attributes attributes) {
			// TODO Auto-generated method stub
			ContentHandler handler = null;
			if(FILTER_CLASS_ELEMENT.equals(localName)){
				handler = new StringContentHandler(getReader(),this,filterClass);
			} else if (FILTER_NAME_ELEMENT.equals(localName)) {
				handler = new StringContentHandler(getReader(),this,filterName);
			}
			return handler;
		}
		
		@Override
		protected void endLastElement() {
			filters.add(new FilterBean(filterName.toString().trim(),filterClass.toString().trim()));
		}
	
	}


	/**
	 * @author asmirnov
	 *
	 */
	public class FilterMappingHandler extends WebappElementHandler {

		private StringBuilder servletName = new StringBuilder();
		private StringBuilder urlPattern = new StringBuilder();
		private StringBuilder filterName = new StringBuilder();

		public FilterMappingHandler() {
			super(WebappHandler.this);
		}
		
		@Override
		protected ContentHandler getNextHandler(String uri, String localName,
				Attributes attributes) {
			ContentHandler nextHandler = null;
			if (SERVLET_NAME_ELEMENT.equals(localName)) {
				nextHandler = new StringContentHandler(getReader(), this,
						servletName);
			} else if (URL_PATTERN_ELEMENT.equals(localName)) {
				nextHandler = new StringContentHandler(getReader(), this,
						urlPattern);
			} else if (FILTER_NAME_ELEMENT.equals(localName)) {
				nextHandler = new StringContentHandler(getReader(), this,
						filterName);
				
			}
			return nextHandler;
		}
		
		@Override
		protected void endLastElement() {
			filterMappings.add(new FilterMapping(filterName.toString().trim(),servletName.toString().trim(),urlPattern.toString().trim()));
		}
	
	}

}
