package eu.dnetlib.springutils.condbean;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;

import eu.dnetlib.springutils.condbean.parser.RunccExpressionParser;

/**
 * Taken from http://robertmaldon.blogspot.com/2007/04/conditionally-defining-spring-beans.html .
 * 
 * modified to fix a problem caused by http://jira.springframework.org/browse/SPR-2955 improved expression parsing
 * 
 * @author marko
 * 
 */
public class ConditionalBeanDefinitionParser implements BeanDefinitionParser {

	/**
	 * logger.
	 */
	@SuppressWarnings("unused") 	// NOPMD by marko on 11/24/08 5:02 PM
	private static final Log log = LogFactory.getLog(ConditionalBeanDefinitionParser.class);

	/**
	 * expression parser.
	 */
	private transient RunccExpressionParser expressionParser = new RunccExpressionParser();

	/**
	 * Parse the "cond" element and check the mandatory "test" attribute. If the system property named by test is null
	 * or empty (i.e. not defined) then return null, which is the same as not defining the bean.
	 * 
	 * @param element element to parse
	 * @param parserContext spring parser context
	 * @return registered bean or null.
	 */
	public BeanDefinition parse(final Element element, final ParserContext parserContext) {
		if (DomUtils.nodeNameEquals(element, "cond")) {
			final String test = element.getAttribute("test");
			if (expressionParser.expressionValue(test)) {
				final Element beanElement = DomUtils.getChildElementByTagName(element, "bean");
				return parseAndRegisterBean(beanElement, parserContext);
			}
		}

		return null;
	}

	/**
	 * the real job of registering the child element of this conditional bean is performed here.
	 * 
	 * @param element element
	 * @param parserContext spring parser context
	 * @return registered bean.
	 */
	private BeanDefinition parseAndRegisterBean(final Element element, final ParserContext parserContext) {
		if (element == null)
			throw new IllegalStateException("trying to register a null bean");

		final BeanDefinitionParserDelegate delegate = parserContext.getDelegate();
		BeanDefinitionHolder holder = delegate.parseBeanDefinitionElement(element);
		BeanDefinitionReaderUtils.registerBeanDefinition(holder, parserContext.getRegistry());

		// necessary because of http://jira.springframework.org/browse/SPR-2955
		holder = delegate.decorateBeanDefinitionIfRequired(element, holder);
		return holder.getBeanDefinition();
	}
}
