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

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.SAXException;

/**
 * @author asmirnov
 * 
 */
public class WebXMLParser {

	public static final String WEB_XML = "/WEB-INF/web.xml";

	private String _facesFilterPrefix = null;
	/**
	 * Suffix for Resource-Ajax filter , in common must be same as for
	 * {@link javax.faces.webapp.FacesServlet}
	 */
	private String _facesFilterSuffix = null;
	private String _facesServletPrefix = null;
	private String _facesServletSuffix = null;

	private List<String> facesServletMappings;
	private List<String> filterMappings;
	static final String FACES_SERVLET_CLASS = "javax.faces.webapp.FacesServlet";

	public void init(InputStream webXml, String filterName)
			throws ParsingException {
		try {
			// Prepare SAX parser for a web-xml.
			SAXParserFactory factory = SAXParserFactory.newInstance();
			factory.setValidating(false);
			factory.setNamespaceAware(true);
			SAXParser parser = factory.newSAXParser();
			// Parse web.xml with state-avare content handler.
			WebappHandler webappHandler = new WebappHandler(parser
					.getXMLReader());
			parser.parse(webXml, webappHandler);
			// Calculate Faces Servlet and filter mappings.
			for (ServletBean servlet : webappHandler.getServlets()) {
				if (FACES_SERVLET_CLASS.equals(servlet.getClassName())) {
					facesServletMappings = new ArrayList<String>();
					for (ServletMapping mapping : webappHandler
							.getServletMappings()) {
						if (servlet.getName().equals(mapping.getServletName())) {
							facesServletMappings.add(mapping.getUrlPattern());
							String asPrefix = getAsPrefix(mapping
									.getUrlPattern());
							if (null != asPrefix) {
								_facesServletPrefix = asPrefix;

							}
							String asSuffix = getAsSuffix(mapping
									.getUrlPattern());
							if (null != asSuffix) {
								_facesServletSuffix = asSuffix;

							}
						}
					}
				}
			}
			// Find named filter configuration.
			// Got filter, check it's mapping.
			filterMappings = new ArrayList<String>();
			for (FilterMapping mapping : webappHandler.getFilterMappings()) {
				if (mapping.getFilterName().equals(filterName)) {
					if (null != mapping.getUrlPattern()
							&& !"".equals(mapping.getUrlPattern())) {
						filterMappings.add(mapping.getUrlPattern());
						String asPrefix = getAsPrefix(mapping.getUrlPattern());
						if (null != asPrefix) {
							_facesFilterPrefix = asPrefix;

						}
						String asSuffix = getAsSuffix(mapping.getUrlPattern());
						if (null != asSuffix) {
							_facesFilterSuffix = asSuffix;

						}
					} else if (null != mapping.getServletName()
							&& !"".equals(mapping.getServletName())) {
						for (ServletMapping servletMapping : webappHandler
								.getServletMappings()) {
							if (mapping.getServletName().equals(
									servletMapping.getServletName())) {
								filterMappings.add(servletMapping
										.getUrlPattern());
								String asPrefix = getAsPrefix(servletMapping
										.getUrlPattern());
								if (null != asPrefix) {
									_facesFilterPrefix = asPrefix;

								}
								String asSuffix = getAsSuffix(servletMapping
										.getUrlPattern());
								if (null != asSuffix) {
									_facesFilterSuffix = asSuffix;

								}
							}
						}
					}
				}
			}
			if (0 == filterMappings.size()) {
				throw new ParsingException(
						"No filter mapping set for a filter " + filterName);
			}

		} catch (IOException e) {
			throw new ParsingException("Error read web application config", e);
		} catch (ParserConfigurationException e) {
			throw new ParsingException("SAX Parser configuration error", e);
		} catch (SAXException e) {
			throw new ParsingException(
					"Error parsing XML for the web application config", e);
		}
	}

	private String getAsSuffix(String urlPattern) {
		String suffix = null;
		if (urlPattern.startsWith("*")) {
			suffix = urlPattern.substring(1);
		}
		return suffix;
	}

	private String getAsPrefix(String urlPattern) {
		String preffix = null;
		if (urlPattern.endsWith("*")) {
			int cut = urlPattern.endsWith("/*") ? 2 : 1;
			preffix = urlPattern.substring(0, urlPattern.length() - cut);
		}
		return preffix;
	}

	public List<String> getFacesServletMappings() {
		return facesServletMappings;
	}

	/**
	 * @return the facesFilterPrefix
	 */
	public String getFacesFilterPrefix() {
		return _facesFilterPrefix;
	}

	/**
	 * @return the facesFilterSuffix
	 */
	public String getFacesFilterSuffix() {
		return _facesFilterSuffix;
	}

	/**
	 * @return the facesServletPrefix
	 */
	public String getFacesServletPrefix() {
		return _facesServletPrefix;
	}

	/**
	 * @return the facesServletSuffix
	 */
	public String getFacesServletSuffix() {
		return _facesServletSuffix;
	}

	public void init(ServletContext portletContext, String filterName)
			throws ServletException {
		InputStream inputStream = portletContext.getResourceAsStream(WEB_XML);
		if (null != inputStream) {
			try {
				init(inputStream, filterName);
			} catch (ParsingException e1) {
				throw new ServletException(
						"Error parse web application config", e1);
			}
			try {
				inputStream.close();
			} catch (IOException e) {
				// Do nothing, ignore
			}

		}
	}
}
