package eu.dnetlib.saxon.ext;

import java.util.List;
import com.google.common.collect.Lists;
import eu.dnetlib.data.collective.transformation.engine.functions.ProcessingException;
import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.om.Item;
import net.sf.saxon.om.Sequence;
import net.sf.saxon.om.SequenceIterator;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.value.SequenceType;
import net.sf.saxon.value.StringValue;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * Created by alessia on 24/02/17.
 */
@Component
public class ConvertFunction extends AbstractTransformatorExtFunction {

	private static final Log log = LogFactory.getLog(ConvertFunction.class);

	@Autowired
	private eu.dnetlib.data.collective.transformation.engine.functions.Convert convert;

	@Override
	public String getName() {
		return "convert";
	}

	@Override
	public Sequence doCall(XPathContext context, Sequence[] arguments) throws XPathException {
		Sequence inputNodeList = arguments[0];
		String vocabularyName = arguments[1].head().getStringValue();
		List<String> values = getTextFromNodeList(inputNodeList);
		switch(arguments.length){
		case 2:
			//2-args call
			try {
				return new StringValue(convert.executeSingleValue(vocabularyName, values));
			} catch (ProcessingException e) {
				throw new IllegalStateException(e);
			}
		case 4:
			//4-args call
			String pattern = arguments[2].head().getStringValue();
			String function = arguments[3].head().getStringValue();
			try {
				List<String> results = convert.executeFilterByParams(vocabularyName, values, pattern, function);
				if (results.size() > 0)
					return new StringValue(results.get(0));
				else
					return new StringValue("");
			} catch (ProcessingException e) {
				throw new IllegalStateException(e);
			}
		default:
			//throw exception
			throw new IllegalArgumentException("Allowed number of parameters is 2 or 4: nodeList, vocabularyName [, pattern, function]");
		}
	}

	@Override
	public int getMinimumNumberOfArguments() {
		return 2;
	}

	@Override
	public int getMaximumNumberOfArguments() {
		return 4;
	}

	@Override
	public SequenceType[] getArgumentTypes() {
		return new SequenceType[] { SequenceType.NODE_SEQUENCE, SequenceType.SINGLE_STRING };
	}

	@Override
	public SequenceType getResultType(SequenceType[] suppliedArgumentTypes) {
		return SequenceType.SINGLE_STRING;
	}


	private List<String> getTextFromNodeList(Sequence aNodeList) throws XPathException {
		//According to the saxon documentation, the string value is compliant to XPath 2.0 model https://www.w3.org/TR/xpath-datamodel/#ElementNode
		//hence: "The string-value property of an Element Node must be the concatenation of the string-values of all its Text Node descendants in document order or,
		//if the element has no such descendants, the zero-length string."
		SequenceIterator items = aNodeList.iterate();
		Item item;
		List<String> values = Lists.newArrayList();
		while(((item = items.next()) != null)){
			values.add(item.getStringValue());
		}
		return values;
	}
}