package eu.dnetlib.msro.dispatcher;

import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.Node;
import org.springframework.core.io.ClassPathResource;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import eu.dnetlib.enabling.datastructures.Workflow;
import eu.dnetlib.miscutils.ApplyXslt;
import eu.dnetlib.rmi.soap.exceptions.ManagerServiceException;

public class SarasvatiUtils {

	private final static ClassPathResource xslt = new ClassPathResource("/eu/dnetlib/msro/xslt/wf_profile2sarasvati.xslt");
	private static final Log log = LogFactory.getLog(SarasvatiUtils.class);
	private static final String WITH_NODE_TYPES_AND_PARAMS = "COMPLETED";
	private static final String WITHOUT_NODE_TYPES_AND_PARAMS = "SIMPLE";

	public static synchronized String convertToSarasvatiProfile(final Workflow wf) {
		final Map<String, String> map = Maps.newHashMap();
		map.put("wfName", wf.getName());
		map.put("mode", WITHOUT_NODE_TYPES_AND_PARAMS);
		return new ApplyXslt(xslt, map).apply(wf.asXML());
	}

	public static synchronized String convertToSarasvatiProfile(final Workflow wf, final Map<String, String> params)
			throws ManagerServiceException {
		try {
			final Document doc = wf.asDocument();

			if (params != null) {
				final Set<String> required = Sets.newHashSet();
				for (Object o : doc.selectNodes("//CONFIGURATION/PARAM")) {
					required.add(((Node) o).valueOf("@name"));
				}

				if (!Sets.symmetricDifference(required, params.keySet()).isEmpty()) {
					log.error("Problem with params, required: " + required + ", provided:" + params);
					throw new RuntimeException("Problem with params, required: " + required + ", provided: " + params);
				}

				final Pattern r = Pattern.compile("^\\$\\{(.+)\\}$");
				for (Object o : doc.selectNodes("//NODE/PARAMETERS/PARAM")) {
					final Node n = (Node) o;
					final Matcher m = r.matcher(n.getText().trim());
					if (m.find()) {
						final String p = m.group(1);
						if (StringUtils.isNotBlank(p) && params.containsKey(p)) {
							n.setText(params.get(p));
						} else {
							log.error("Invalid parameter: " + p);
							throw new ManagerServiceException("Invalid parameter: " + p);
						}
					}
				}
			}

			final Map<String, String> map = Maps.newHashMap();
			map.put("wfName", wf.getName());
			map.put("mode", WITH_NODE_TYPES_AND_PARAMS);

			return new ApplyXslt(xslt, map).apply(doc.asXML());
		} catch (Throwable e) {
			log.error("Error generating sarasvati profile", e);
			throw new ManagerServiceException("Error generating sarasvati profile", e);
		}
	}

}
