package eu.dnetlib.msro.notification;

import java.io.StringReader;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

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

import eu.dnetlib.enabling.actions.AbstractSubscriptionAction;
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
import eu.dnetlib.enabling.locators.UniqueServiceLocator;
import eu.dnetlib.msro.workflows.metawf.WorkflowStartModeEnum;
import eu.dnetlib.msro.workflows.sarasvati.loader.WorkflowExecutor;

public class WfDependencyLauncherNotificationHandler extends AbstractSubscriptionAction {

	@Resource
	private UniqueServiceLocator serviceLocator;

	@Resource
	private WorkflowExecutor workflowExecutor;

	@Resource
	private EmailDispatcher emailDispatcher;

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

	@Override
	public void notified(final String subscrId, final String topic, final String rsId, final String profile) {

		final SAXReader reader = new SAXReader();
		try {
			final Document doc = reader.read(new StringReader(profile));

			final Set<String> emails = calculateEmails(rsId);
			final String procId = doc.valueOf("//LAST_EXECUTION_ID");
			final String wfName = doc.valueOf("//WORKFLOW_NAME");
			final boolean success = doc.valueOf("//LAST_EXECUTION_STATUS").equals("SUCCESS");
			final Map<String, String> responses = Maps.newHashMap();

			for (Object o : doc.selectNodes("//LAST_EXECUTION_OUTPUT")) {
				Node n = (Node) o;
				responses.put(n.valueOf("@name"), n.getText());
			}

			if (!success) {
				log.info("Last execution of " + rsId + " failed, dependencies NOT STARTED");
			}

			final String query = "for $x in collection('/db/DRIVER/MetaWorkflowDSResources/MetaWorkflowDSResourceType')//WORKFLOW[@id='" + rsId
					+ "']/WORKFLOW let $y := /RESOURCE_PROFILE[.//RESOURCE_IDENTIFIER/@value = $x/@id] "
					+ "where $y//CONFIGURATION/@start != 'disabled' return concat ($x/@id , ' @@@ ', $x/@name , ' @@@ ', $y//CONFIGURATION/@start)";

			try {
				final Map<String, String> pendingWfs = Maps.newHashMap();

				for (String s : serviceLocator.getService(ISLookUpService.class).quickSearchProfile(query)) {
					final String[] arr = s.split("@@@");
					final String id = arr[0].trim();
					final String name = arr[1].trim();
					final boolean manual = arr[2].trim().equalsIgnoreCase(WorkflowStartModeEnum.manual.toString());
					if (success && !manual) {
						try {
							String pid = workflowExecutor.startProcess(id);
							log.info("PROC " + pid + " of WF " + id + " STARTED AS CHILD OF " + rsId);
						} catch (Exception e) {
							log.error("Error starting wf: " + id);
						}
					} else {
						pendingWfs.put(id, name);
					}
				}

				if (!emails.isEmpty()) {
					if (success) {
						emailDispatcher.sendSuccessMail(emails, rsId, procId, wfName, pendingWfs, responses);
					} else {
						final String error = doc.valueOf("//LAST_EXECUTION_ERROR");
						emailDispatcher.sendFailedMail(emails, rsId, procId, wfName, pendingWfs, responses, error);
					}
				}
			} catch (ISLookUpException e) {
				log.error("Error executing xquery: " + query, e);
			}
		} catch (DocumentException e) {
			log.error("Error parsing profile with id " + rsId + ": " + profile);
		}
	}

	private Set<String> calculateEmails(final String id) {
		final Set<String> list = Sets.newHashSet();
		try {
			for (String val : serviceLocator.getService(ISLookUpService.class).quickSearchProfile("//ADMIN_EMAIL[..//WORKFLOW/@id='" + id + "']/text()")) {
				for (String s : Splitter.on(",").trimResults().omitEmptyStrings().split(val)) {
					list.add(s);
				}
			}
		} catch (Exception e) {
			log.error("Error searching email adresses", e);
		}
		return list;
	}
}
