package org.apache.slide.projector.processor.xml;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.contract.Context;
import org.apache.commons.contract.constraints.StringConstraints;
import org.apache.commons.contract.descriptor.ParameterDescriptor;
import org.apache.commons.contract.descriptor.ResultEntryDescriptor;
import org.apache.commons.contract.i18n.ParameterMessage;
import org.apache.commons.i18n.LocalizedError;
import org.apache.commons.i18n.LocalizedMessage;
import org.apache.slide.projector.constraints.AnyConstraints;
import org.apache.slide.projector.processor.ConfigurableProcessor;
import org.apache.slide.projector.processor.ConfigurationException;
import org.apache.slide.projector.processor.ProcessException;
import org.apache.slide.projector.processor.SimpleProcessor;
import org.apache.slide.projector.value.ElementValue;
import org.apache.slide.projector.value.Streamable;
import org.apache.slide.projector.value.XMLValue;
import org.jdom.Attribute;
import org.jdom.CDATA;
import org.jdom.Comment;
import org.jdom.Element;
import org.jdom.ProcessingInstruction;
import org.jdom.Text;
import org.jdom.xpath.XPath;

/**
 * @version $Revision: 1.5 $
 */

public class XPathQuery extends SimpleProcessor implements ConfigurableProcessor {
    private Element rootElement;

    public Object process(Object input, Context context) throws Exception {
        XPath xPath = XPath.newInstance((String)input);
        List nodeList = xPath.selectNodes(rootElement);
        return createValueFromNodeList(nodeList);
    }

    public ParameterDescriptor getParameterDescriptor() {
        return new ParameterDescriptor(INPUT, new ParameterMessage("xPathQuery/parameter/input"), new StringConstraints());
    }

    public ResultEntryDescriptor getResultEntryDescriptor() {
        return new ResultEntryDescriptor(OUTPUT, new LocalizedMessage("xPathQuery/result/output"), AnyConstraints.UNCONSTRAINED);
    }

    public void configure(Streamable config) throws ConfigurationException {
        if ( config instanceof XMLValue ) {
            rootElement = ((XMLValue)config).getRootElement();
        } else {
            throw new ConfigurationException(new LocalizedError("xpathQuery/xmlResourceRequired"));
        }
    }

    public static Object createValueFromNodeList(List nodeList) throws ProcessException {
    	if ( nodeList.size() > 1 ) {
    		List resources = new ArrayList();
    		for ( Iterator i = nodeList.iterator(); i.hasNext(); ) {
    			resources.add(createValueFromNode(i.next()));
    		}
    		return resources.toArray();
    	} else {
    		return createValueFromNode(nodeList.get(0));
    	}
    }
    
    public static Object createValueFromNode(Object node) throws ProcessException {
    	if ( node instanceof Element ) {
    		return new ElementValue((Element)node);
    	} else if ( node instanceof Attribute ) {
    		return ((Attribute)node).getValue();
    	} else if ( node instanceof Text ) {
    		return ((Text)node).getText();
    	} else if ( node instanceof Comment ) {
    		return ((Comment)node).getText();
    	} else if ( node instanceof CDATA ) {
    		return ((CDATA)node).toString();
    	} else if ( node instanceof ProcessingInstruction ) {
    		return ((ProcessingInstruction)node).getData();
        }
        throw new ProcessException(new LocalizedError("unconvertableJDomNode"));
    }
}