package eu.dnetlib.msro.workflows.nodes;

import java.util.Map;
import javax.annotation.Resource;

import com.google.common.collect.Maps;
import com.googlecode.sarasvati.Arc;
import com.googlecode.sarasvati.NodeToken;
import eu.dnetlib.common.logging.DnetLogger;
import eu.dnetlib.common.logging.LogMessage;
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryService;
import eu.dnetlib.enabling.locators.UniqueServiceLocator;
import eu.dnetlib.miscutils.datetime.DateUtils;
import eu.dnetlib.msro.workflows.util.WorkflowsConstants;
import org.antlr.stringtemplate.StringTemplate;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Required;

/**
 * The success node sets the "isCompletedSuccessfully" env var.
 * 
 */
public class SuccessFailureNode extends SimpleJobNode {

	private static final Log log = LogFactory.getLog(SuccessFailureNode.class);
	/**
	 * is completed successfully.
	 */
	private boolean success;
	@Resource
	private UniqueServiceLocator serviceLocator;
	@Resource(name = "msroWorkflowLogger")
	private DnetLogger dnetLogger;

	@Override
	protected String execute(final NodeToken token) {
		final String profileId = token.getFullEnv().getAttribute(WorkflowsConstants.SYSTEM_WF_PROFILE_ID).trim();

		final long now = DateUtils.now();
		final String date = DateUtils.calculate_ISO8601(now);

		token.getProcess().getEnv().setAttribute(WorkflowsConstants.SYSTEM_END_DATE, now);
		token.getProcess().getEnv().setAttribute(WorkflowsConstants.SYSTEM_END_HUMAN_DATE, date);

		final Map<String, String> params = mergeEnvAttributes(token);
		final LogMessage logMessage = dnetLogger.newLogMessage().addDetails(params);

		try {
			final String template = IOUtils.toString(getClass().getResourceAsStream("/eu/dnetlib/msro/workflows/templates/workflow_status.xml.st"));
			final StringTemplate st = new StringTemplate(template);
			st.setAttribute("procId", StringEscapeUtils.escapeXml(params.get(WorkflowsConstants.SYSTEM_WF_PROCESS_ID)));
			st.setAttribute("date", StringEscapeUtils.escapeXml(date));
			st.setAttribute("params", filterOutputParams(params));
			if (!isSuccess()) {
				st.setAttribute("error", escape(params.get(WorkflowsConstants.SYSTEM_ERROR)));
			}

			serviceLocator.getService(ISRegistryService.class).updateProfileNode(profileId, "//STATUS", st.toString());

			token.getProcess().getEnv().setAttribute(WorkflowsConstants.SYSTEM_COMPLETED_SUCCESSFULLY, isSuccess());

			logMessage.addDetail(WorkflowsConstants.SYSTEM_COMPLETED_SUCCESSFULLY, Boolean.toString(isSuccess()));
		} catch (Exception e) {
			log.error("Error updating workflow profile: " + profileId, e);
			token.getProcess().getEnv().setAttribute(WorkflowsConstants.SYSTEM_COMPLETED_SUCCESSFULLY, false);
			logMessage.addDetail(WorkflowsConstants.SYSTEM_COMPLETED_SUCCESSFULLY, Boolean.toString(false));
		}

		logMessage.flush();

		return Arc.DEFAULT_ARC;
	}

	private Map<String, String> filterOutputParams(final Map<String, String> map) {
		final Map<String, String> res = Maps.newHashMap();

		if (map != null) {
			for (String k : map.keySet()) {
				if (!StringUtils.isBlank(k) && (k.startsWith(WorkflowsConstants.DATAPROVIDER_PREFIX) || k.startsWith(WorkflowsConstants.MAIN_LOG_PREFIX))) {
					final String key = escape(k);
					final String v = map.get(k);
					res.put(key, v != null ? escapeAttribute(escape(v)) : "null");
				}
			}
		}

		return res;
	}

	private String escapeAttribute(String s) {
		return s.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&apos;").replaceAll("\\{", "{{").replaceAll("\\}", "}}");
	}

	private Map<String, String> mergeEnvAttributes(final NodeToken token) {
		final Map<String, String> map = Maps.newHashMap();

		for (String s : token.getEnv().getAttributeNames()) {
			map.put(s, token.getEnv().getAttribute(s));
		}
		for (String s : token.getFullEnv().getAttributeNames()) {
			map.put(s, token.getFullEnv().getAttribute(s));
		}
		return map;
	}

	protected String escape(final String value){
		return StringUtils.isNotBlank(value) ? StringEscapeUtils.escapeXml(value).replaceAll("\\{", "-").replaceAll("}","-") : "";
	}

	public boolean isSuccess() {
		return success;
	}

	@Required
	public void setSuccess(final boolean success) {
		this.success = success;
	}

}
