package eu.dnetlib.data.collective.transformation.utils;

import java.io.StringReader;
import java.util.List;

import org.apache.commons.lang3.StringEscapeUtils;

import eu.dnetlib.common.profile.ProfileNotFoundException;
import eu.dnetlib.data.collective.transformation.rulelanguage.RuleLanguageParser;
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
import eu.dnetlib.enabling.tools.ServiceLocator;

/**
 * 
 * @author jochen
 * @since 1.2
 */
public class TransformationRulesImportTool {
	private ServiceLocator<ISLookUpService> lookupServiceLocator;
	
	/**
	 * retrieves the transformation rule script of a transformation rule profile identified by a profile id
	 * @param aProfileId
	 * @return list of the transformation rule script and optionally profile id's of subscripts
	 * @throws ProfileNotFoundException
	 */
	protected List<String> getScript(String aProfileId) throws ProfileNotFoundException{
 		String xquery =  "collection('/db/DRIVER/TransformationRuleDSResources')//RESOURCE_PROFILE[.//RESOURCE_IDENTIFIER/@value ='" +
 			aProfileId + "']//CODE/child::node(), " +
 			"for $id in (collection('/db/DRIVER/TransformationRuleDSResources')//RESOURCE_PROFILE[.//RESOURCE_IDENTIFIER/@value ='" +
 			aProfileId + "']//IMPORTED/SCRIPT_REFERENCE/@id) return string($id)";
		List<String> queryResult;
		try {
			queryResult = lookupServiceLocator.getService().quickSearchProfile(xquery);
			if (!queryResult.isEmpty()){
				return queryResult;
			}else{
				throw new ProfileNotFoundException("no script found in profile for profileId: " + aProfileId);
			}
		} catch (ISLookUpException e) {
			throw new ProfileNotFoundException(e);
		}
	}
	
	protected void importRules(RuleLanguageParser aParser, String aProfileId) throws ProfileNotFoundException{
		List<String> profileQueryResult = getScript(aProfileId);
		String script = StringEscapeUtils.unescapeXml(profileQueryResult.get(0)); // the first entry contains the script
		if (script.trim().startsWith("<xsl:stylesheet")){
			aParser.setXslStylesheet(script.trim());
		}else{
			StringReader reader = new StringReader(script);
			aParser.parse(reader);
			if (aParser.getImportedScripts().size() != (profileQueryResult.size() - 1) ) throw new IllegalStateException(
					"invalid number of scripts to import: " + aParser.getImportedScripts().size() + " != " + profileQueryResult.size());
			// recursiv
			if (!aParser.getImportedScripts().isEmpty()){
				for (String importScriptProfileId: profileQueryResult.subList(1, profileQueryResult.size())){
					RuleLanguageParser childParser = new RuleLanguageParser();
					importRules(childParser, importScriptProfileId);
					aParser.addRulesFromParser(childParser);
				}
			}
		}
	}
	
	/**
	 * gets the rule language parser, which creates the mapping of rules which is defined in a transformation rule script identified by the transformation rule profile id
	 * @param aProfileId - id of the transformation rules profile
	 * @return the rule language parser
	 * @throws ProfileNotFoundException
	 */
	public RuleLanguageParser getRuleLanguageParser(String aProfileId) throws ProfileNotFoundException{
		RuleLanguageParser parser = new RuleLanguageParser();
		importRules(parser, aProfileId);
		return parser;
	}

	public ServiceLocator<ISLookUpService> getLookupServiceLocator() {
		return lookupServiceLocator;
	}

	public void setLookupServiceLocator(
			ServiceLocator<ISLookUpService> lookupServiceLocator) {
		this.lookupServiceLocator = lookupServiceLocator;
	}
	
}
