package org.etsi.mts.tdl.execution.java.rt.core;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Future;

import org.etsi.mts.tdl.execution.java.rt.core.TestControl.ExecutionCallable;
import org.etsi.mts.tdl.execution.java.rt.core.TestControl.ExecutionResult;

public class ExceptionalBehaviour {
	/**
	 * The behaviour that is executed when the callable provides a result.
	 */
	public Behaviour behaviour;
	
	/**
	 * The triggering behaviour in callable format that is submitted for execution when activated.
	 */
	public ExecutionCallable callable;
	
	/**
	 * Whether the behaviour is an interrupt or default as specified by TDL.
	 */
	public boolean isInterrupt;
	
	/**
	 * <p>The futures for the triggering behaviour (callable). Several futures may exist
	 * simultaneously due to alternatives. Several threads may have their own set of
	 * futures due to parallel behaviours.
	 * <p>Should be cleaned up when behaviour is deactivated.
	 */
	private ThreadLocal<Set<Future<ExecutionResult>>> currentFutures = new ThreadLocal<Set<Future<ExecutionResult>>>() {
		protected java.util.Set<java.util.concurrent.Future<ExecutionResult>> initialValue() {
			return Collections.synchronizedSet(new HashSet<Future<ExecutionResult>>());
		};
	};
	
	public ExceptionalBehaviour(boolean isInterrupt) {
		this.isInterrupt = isInterrupt;
	}
	
	/**
	 * Sets the callable if not set already.
	 */
	public void setCallable(ExecutionCallable callable) {
		if (this.callable == null)
			this.callable = callable;
	}
	
	/**
	 * Submits the triggering behaviour (callable) for execution and stores the resulting future.
	 * @return The new future for the triggering behaviour.
	 */
	public Future<ExecutionResult> execute() {
		Future<ExecutionResult> future = callable.execute();
		currentFutures.get().add(future);
		return future;
	}
	
	/**
	 * 
	 * @return True if the future is created by this behaviour.
	 */
	public boolean isFuture(Future<ExecutionResult> future) {
		return currentFutures.get().contains(future);
	}
	
	/**
	 * Clear the futures and return them for cancellation.
	 * @return The set of futures that existed before clean-up.
	 */
	public Set<Future<ExecutionResult>> purgeFutures() {
		Set<Future<ExecutionResult>> futures = new HashSet<Future<ExecutionResult>>(currentFutures.get());
		currentFutures.get().clear();
		return futures;
	}
}
