package eu.dnetlib.data.collective.transformation.engine.functions;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class IdentifierExtract extends AbstractTransformationFunction{
	public static final Log log = LogFactory.getLog(IdentifierExtract.class);
	public static final String paramXpathExprJson = "xpathExprJson";
	public static final String paramXpathExprInSource = "xpathExprInputSource";
	public static final String paramRegExpr = "regExpr";
	
	@Override
	String execute() throws ProcessingException {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * extract content matched by a regular expression pattern from a given node and return matched content as a node-list
	 * @param aXpathExprList
	 * @param aInput
	 * @param aRegExpression
	 * @param aDocument
	 * @param aXpath
	 * @return nodeList
	 * @throws ProcessingException
	 */
	public NodeList extract(List<String> aXpathExprList, Node aInput,
			String aRegExpression, Document aDocument, XPath aXpath) throws ProcessingException {
		
		log.debug("xpathExprList: " + aXpathExprList);
		log.debug("regExpr: " + aRegExpression);
		Set<String> identifierSet = new HashSet<String>();
		
//		log.debug("node: length: " + aInput.getChildNodes().getLength());
		log.debug("regular expression : " + aRegExpression);
		Pattern p = Pattern.compile(aRegExpression);
		try {
			List<String> textList = extractText(aXpathExprList, aInput, aXpath);
			for (String text: textList){
				log.debug("text as input : " + text);
				Matcher m = p.matcher(text);
				while (m.find()){
					log.debug("extracted identifier: " + m.group());
					identifierSet.add(m.group());
				}
			}
			return toNodeList(identifierSet, aDocument);
		} catch (XPathExpressionException e) {
			e.printStackTrace();
			throw new ProcessingException(e);
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
			throw new ProcessingException(e);
		}
	}
	
	/**
	 * create a list of nodes from a list of string values
	 * @param aValueSet, set of unique values
	 * @param aDocument
	 * @return nodeList
	 */
	private NodeList toNodeList(Set<String> aValueSet, Document aDocument){
		DocumentFragment dFrag = aDocument.createDocumentFragment();
		Element root = aDocument.createElement("root");
		dFrag.appendChild(root);
		for (String value: aValueSet){
			Element eVal = aDocument.createElement("value");
			eVal.setTextContent(value);
			root.appendChild(eVal);
		}
		return dFrag.getChildNodes();
	}
	
	/**
	 * extract text from a given node using a list of given xpath expressions
	 * @param aXpathExprList
	 * @param aInput
	 * @param aXpath
	 * @return list of strings
	 * @throws XPathExpressionException
	 * @throws ParserConfigurationException 
	 */
	private List<String> extractText(List<String> aXpathExprList, Node aInput, XPath aXpath) throws XPathExpressionException, ParserConfigurationException{
		
		List<String> resultList = new LinkedList<String>();
		for (String xpathExpr: aXpathExprList){
			NodeList nodeList = (NodeList)aXpath.evaluate(xpathExpr, aInput, XPathConstants.NODESET);
			log.debug("extract text: nodelist length: " + nodeList.getLength()); 
			for (int i = 0; i < nodeList.getLength(); i++){
				resultList.add(nodeList.item(i).getTextContent());
			}
		}
		return resultList;
	}
}
