package eu.dnetlib.workflow;

import java.util.Date;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.googlecode.sarasvati.Engine;
import com.googlecode.sarasvati.NodeToken;
import com.googlecode.sarasvati.mem.MemNode;

import eu.dnetlib.enabling.inspector.msro.progress.ProgressProvider;
import eu.dnetlib.miscutils.datetime.DateUtils;

/**
 * common job.
 * 
 * @author marko
 * 
 */
public abstract class AbstractJobNode extends MemNode {

	/**
	 * logger.
	 */
	private static final Log log = LogFactory.getLog(AbstractJobNode.class); // NOPMD by marko on 11/24/08 5:02 PM

	/**
	 * Progress Provider
	 */
	private ProgressProvider progressProvider;

	/**
	 * description.
	 */
	private String description;

	/**
	 * extra description, which normally shows as a tooltip.
	 */
	private String extraDescription;

	public String getDescription() {
		return description;
	}

	public void setDescription(final String description) {
		this.description = description;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see com.googlecode.sarasvati.mem.MemNode#getAdaptor(java.lang.Class)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public <T> T getAdaptor(final Class<T> clazz) {
		if (clazz == String.class) {
			if (getDescription() == null)
				return (T) getName();
			else
				return (T) getDescription();
		} else {
			return super.getAdaptor(clazz);
		}
	}

	/**
	 * helper method to be invoked when an exception causes the process node to fail.
	 * 
	 * @param engine
	 *            process engine
	 * @param token
	 *            process token
	 * @param exception
	 *            exception
	 */
	protected void failed(final Engine engine, final NodeToken token, final Throwable exception) {
		log.fatal("got exception while executing workflow node", exception);

		token.getEnv().setAttribute("hasFailed", true);
		token.getEnv().setAttribute("errorMessage", exception.getMessage());
		engine.complete(token, "failed");
	}

	public String getExtraDescription() {
		return extraDescription;
	}

	public void setExtraDescription(String extraDescription) {
		this.extraDescription = extraDescription;
	}

	public String getProgressDescription(NodeToken token) {
		if (progressProvider == null)
			return null;

		String totS = "???";
		String percentS = "";

		int currValue = progressProvider.getCurrentValue(this, token);
		int totValue = progressProvider.getTotalValue(this, token);

		if (currValue <= totValue) {
			totS = "" + totValue;
			if (totValue > 0) {
				percentS = " (" + Math.round(currValue * 100 / totValue) + "%)";
			}
		}

		return "Progress: " + currValue + "/" + totS + percentS + " RPS: " + rps(currValue, token.getCreateDate()) + " ETA: "
				+ eta(currValue, totValue, token.getCreateDate());
	}

	private String rps(int currValue, Date createDate) {
		if (createDate == null)
			return "??";
		long delta = (DateUtils.now() - createDate.getTime()) / 1000;

		if (delta == 0)
			return "??";

		return "" + (currValue / delta);
	}

	private String eta(int currValue, int totValue, Date createDate) {
		if (createDate == null)
			return "??";
		long delta = (DateUtils.now() - createDate.getTime()) / 1000;

		if (currValue == 0)
			return "??";

		return formatElapsed((totValue - currValue) * delta / currValue);
	}

	private String formatElapsed(long delta) {
		long hours = delta / (60 * 60);
		long minutes = (delta % (60 * 60)) / 60;
		long seconds = ((delta % (60 * 60)) % 60);

		String elapsed = "";
		if (hours < 10)
			elapsed += "0";
		elapsed += hours + ":";
		if (minutes < 10)
			elapsed += "0";
		elapsed += minutes + ":";
		if (seconds < 10)
			elapsed += "0";
		elapsed += seconds;
		return elapsed;
	}

	public void setProgressProvider(ProgressProvider progressProvider) {
		this.progressProvider = progressProvider;
	}

	public ProgressProvider getProgressProvider() {
		return progressProvider;
	}

}
