package eu.dnetlib.contract.spring.beans;

import java.util.List;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;

import eu.dnetlib.contract.node.RANDDefinitionNode;
import eu.dnetlib.contract.node.SEQDefinitionNode;



/**
 * Contract definition namespace handler.
 * @author mhorst
 *
 */
public class ContractDefinitionNamespaceHandler extends NamespaceHandlerSupport {
	
	public static final String SEQ_ELEMENT_NAME			= "seq";
	public static final String RAND_ELEMENT_NAME		= "rand";
	
	public static final String ENTRY_CP_ELEMENT_NAME	= "entry-cp";
	public static final String RESULT_CP_ELEMENT_NAME	= "result-cp";
	public static final String EXC_CP_ELEMENT_NAME		= "exception-cp";
	public static final String COMPLEX_CP_ELEMENT_NAME	= "complex-cp";
	public static final String DUMMY_CP_ELEMENT_NAME	= "dummy-cp";
	
	public static final String INVOKER_DATA_ELEMENT_NAME		= "invoker-data";
	public static final String TEST_RUNNER_CONF_ELEMENT_NAME	= "test-runner-config";
	
	public static final String COMPLEX_OBJ_BUILDER_ELEMENT_NAME	= "xstream-builder";
	
	public ContractDefinitionNamespaceHandler() {
//		contract nodes
		registerBeanDefinitionParser(SEQ_ELEMENT_NAME,
				new SEQDefinitionNodeBeanDefinitionParser());
		registerBeanDefinitionParser(RAND_ELEMENT_NAME,
				new RANDDefinitionNodeBeanDefinitionParser());
//		check points
		registerBeanDefinitionParser(ENTRY_CP_ELEMENT_NAME,
				new EntryCheckPointBeanDefinitionParser());
		registerBeanDefinitionParser(RESULT_CP_ELEMENT_NAME,
				new ResultCheckPointBeanDefinitionParser());
		registerBeanDefinitionParser(EXC_CP_ELEMENT_NAME,
				new ExceptionCheckPointBeanDefinitionParser());
		registerBeanDefinitionParser(COMPLEX_CP_ELEMENT_NAME,
				new ComplexCheckPointBeanDefinitionParser());
		registerBeanDefinitionParser(DUMMY_CP_ELEMENT_NAME,
				new DummyCheckPointBeanDefinitionParser());
//		runner configuration
		registerBeanDefinitionParser(INVOKER_DATA_ELEMENT_NAME,
				new InvokerDataBeanDefinitionParser());
		registerBeanDefinitionParser(TEST_RUNNER_CONF_ELEMENT_NAME,
				new TestRunnerConfigBeanDefinitionParser());
//		complex object builder
		registerBeanDefinitionParser(COMPLEX_OBJ_BUILDER_ELEMENT_NAME,
				new ComplexObjectBeanDefinitionParser());
		
	}

	/* (non-Javadoc)
	 * @see org.springframework.beans.factory.xml.NamespaceHandler#init()
	 */
	public void init() {
	}

	/**
	 * {@link SEQDefinitionNode} bean definition parser.
	 * @author mhorst
	 *
	 */
	private static class SEQDefinitionNodeBeanDefinitionParser extends
		AbstractContractDefinitionNodeBeanDefinitionParser {

		/* (non-Javadoc)
		 * @see eu.dnetlib.contract.spring.beans.AbstractContractDefinitionNodeBeanDefinitionParser#doParse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext, org.springframework.beans.factory.support.BeanDefinitionBuilder)
		 */
		@Override
		protected void doParse(Element element, ParserContext parserContext,
				BeanDefinitionBuilder builder) {
			super.doParse(element, parserContext, builder);
			List<?> list = parserContext.getDelegate()
					.parseListElement((Element) element,
							builder.getBeanDefinition());
			builder.addPropertyValue("sequence", list);
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#getBeanClass(org.w3c.dom.Element)
		 */
		@SuppressWarnings("unchecked")
		@Override
		protected Class getBeanClass(Element element) {
			return SEQDefinitionNode.class;
		}
	}
	
	/**
	 * {@link RANDDefinitionNode} bean definition parser.
	 * @author mhorst
	 *
	 */
	private static class RANDDefinitionNodeBeanDefinitionParser extends
		AbstractContractDefinitionNodeBeanDefinitionParser {
	

		/* (non-Javadoc)
		 * @see eu.dnetlib.contract.spring.beans.AbstractContractDefinitionNodeBeanDefinitionParser#doParse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext, org.springframework.beans.factory.support.BeanDefinitionBuilder)
		 */
		@Override
		protected void doParse(Element element, ParserContext parserContext,
				BeanDefinitionBuilder builder) {
			super.doParse(element, parserContext, builder);
			List<?> list = parserContext.getDelegate()
					.parseListElement((Element) element,
							builder.getBeanDefinition());
			builder.addPropertyValue("nodes", list);
		}

		/* (non-Javadoc)
		 * @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#getBeanClass(org.w3c.dom.Element)
		 */
		@SuppressWarnings("unchecked")
		@Override
		protected Class getBeanClass(Element element) {
			return RANDDefinitionNode.class;
		}
	}
}
