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

import java.io.StringReader;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.xml.namespace.NamespaceContext;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.InputSource;

import eu.dnetlib.common.profile.Resource;
import eu.dnetlib.common.profile.ResourceDao;
import eu.dnetlib.data.collective.transformation.rulelanguage.Argument;

/**
 * @author jochen
 *
 */
public class RetrieveValue extends AbstractTransformationFunction {

	public static final Log log = LogFactory.getLog(RetrieveValue.class);
	public static final String paramFunctionName = "functionName";
	public static final String paramFunctionProfileId = "functionParameterProfileId";
	public static final String paramFunctionExpr = "functionParameterExpr";
	
	public enum FUNCTION {PROFILEFIELD, CURRENTDATE};
	
	@javax.annotation.Resource
	private ResourceDao resourceDao;
		
	/* (non-Javadoc)
	 * @see eu.dnetlib.data.collective.transformation.engine.functions.AbstractTransformationFunction#execute()
	 */
	@Override
	String execute() throws ProcessingException {
		// TODO Auto-generated method stub
		return null;
	}
	
	public String executeSingleValue(String functionName, List<Argument> arguments, String objRecord, Map<String, String> namespaceMap) throws ProcessingException{
		String result = "";
		FUNCTION function = FUNCTION.valueOf(functionName);
		
		switch(function){
		case PROFILEFIELD:
			if (arguments.size() != 2){
				throw new ProcessingException("invalid number of arguments - required 2 but found :" + arguments.size());
			}
			String arg = "";
			Resource resource = null;
			try{
				if (arguments.get(0).isValue()){
					arg = arguments.get(0).getArgument();
					log.debug("retrieve value arg isValue: " + arg);
					if (arg.startsWith("collection(")) { // xquery
						arg = StringEscapeUtils.unescapeXml(arg);
						resource = resourceDao.getResourceByQuery(arg); // query
					}else
						resource = resourceDao.getResource(arg); // profile id
				}else if (arguments.get(0).isInputField()){
					arg = evaluateXpath(objRecord, arguments.get(0).getArgument(), namespaceMap);
					log.debug("retrieve value arg isInputField: " + arg);
					if (arg.startsWith("collection(")) { // xquery
						arg = StringEscapeUtils.unescapeXml(arg);
						resource = resourceDao.getResourceByQuery(arg); // query
					}else
						resource = resourceDao.getResource(arg); // profile id
				}else if (arguments.get(0).isJobConst()){
					// TODO
				}else if (arguments.get(0).isVariable()){
					// TODO				
					log.warn("RETRIEVEVALUE: support for variables not yet implemented.");
				}				
			}catch(Exception e){
				throw new ProcessingException(e);
			}
			
			if (resource == null){
				throw new ProcessingException("invalid profileId: " + arg + "; functionName: " + functionName + ", arg1: " + arguments.get(0).getArgument() + ", arg2: " + arguments.get(1).getArgument());
			}
			result = resource.getValue(arguments.get(1).getArgument());  // xpath expr
			break;
		case CURRENTDATE:
			SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); // TODO format string
			result = dateFormat.format(new Date());
			default:
				// unsupported
				break;
		}
		return result;
	}

	/**
	 * @return the resourceDao
	 */
	public ResourceDao getResourceDao() {
		return resourceDao;
	}

	/**
	 * @param resourceDao the resourceDao to set
	 */
	public void setResourceDao(ResourceDao resourceDao) {
		this.resourceDao = resourceDao;
	}

	private String evaluateXpath(String record, String xpathExpr, Map<String, String> nsMap){
		XPath xpath = XPathFactory.newInstance().newXPath();
		xpath.setNamespaceContext(new NamespaceContext() {
			
			@Override
			public Iterator getPrefixes(String namespaceURI) {
				return null;
			}
			
			@Override
			public String getPrefix(String namespaceURI) {
				// TODO Auto-generated method stub
				return null;
			}
			
			@Override
			public String getNamespaceURI(String prefix) {
				if ("dri".equals(prefix)){
                    return "http://www.driver-repository.eu/namespace/dri";                      
                }else if ("dr".equals(prefix)){
                        return "http://www.driver-repository.eu/namespace/dr";
                }else if ("dc".equals(prefix)){
                        return "http://purl.org/dc/elements/1.1/";
                }else if ("oaf".equals(prefix)){
                    return "http://namespace.openaire.eu/oaf";
                }else if ("prov".equals(prefix)){
                    return "http://www.openarchives.org/OAI/2.0/provenance";
                }
                return "";
			}
		});
		try {
			return xpath.evaluate(xpathExpr, new InputSource(new StringReader(record)));
		} catch (XPathExpressionException e) {
			log.fatal("cannot evaluate xpath");
			throw new IllegalStateException(e);
		}
	}
}
