diff --git a/AMAKFX/src/fr/irit/smac/amak/Agent.java b/AMAKFX/src/fr/irit/smac/amak/Agent.java
index 9685e065123e3ae277e7482e37e39789ce88c9f1..5166056c042ff55d44110d5d52733cc3cc798a0f 100644
--- a/AMAKFX/src/fr/irit/smac/amak/Agent.java
+++ b/AMAKFX/src/fr/irit/smac/amak/Agent.java
@@ -1,496 +1,518 @@
-package fr.irit.smac.amak;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import fr.irit.smac.amak.Amas.ExecutionPolicy;
-import fr.irit.smac.amak.tools.Log;
-
-/**
- * This class must be overridden by all agents
- * 
- * @author Alexandre Perles
- *
- * @param <A>
- *            The kind of Amas the agent refers to
- * @param <E>
- *            The kind of Environment the agent AND the Amas refer to
- */
-public abstract class Agent<A extends Amas<E>, E extends Environment> implements Runnable {
-	/**
-	 * Neighborhood of the agent (must refer to the same couple amas, environment
-	 */
-	protected final List<Agent<A, E>> neighborhood;
-	/**
-	 * Criticalities of the neighbors (and it self) as perceived at the beginning of
-	 * the agent's cycle
-	 */
-	protected final Map<Agent<A, E>, Double> criticalities = new HashMap<>();
-	/**
-	 * Last calculated criticality of the agent
-	 */
-	private double criticality;
-	/**
-	 * Amas the agent belongs to
-	 */
-	protected final A amas;
-	/**
-	 * Unique index to give unique id to each agent
-	 */
-	private static int uniqueIndex;
-
-	/**
-	 * The id of the agent
-	 */
-	private final int id;
-	/**
-	 * The order of execution of the agent as computed by
-	 * {@link Agent#_computeExecutionOrder()}
-	 */
-	private int executionOrder;
-	/**
-	 * The parameters that can be user in the initialization process
-	 * {@link Agent#onInitialization()}
-	 */
-	protected Object[] params;
-
-	/**
-	 * These phases are used to synchronize agents on phase
-	 * 
-	 * @see fr.irit.smac.amak.Amas.ExecutionPolicy
-	 * @author perles
-	 *
-	 */
-	public enum Phase {
-		/**
-		 * Agent is perceiving
-		 */
-		PERCEPTION,
-		/**
-		 * Agent is deciding and acting
-		 */
-		DECISION_AND_ACTION,
-		/**
-		 * Agent haven't started to perceive, decide or act
-		 */
-		INITIALIZING,
-		/**
-		 * Agent is ready to decide
-		 */
-		PERCEPTION_DONE,
-		/**
-		 * Agent is ready to perceive or die
-		 */
-		DECISION_AND_ACTION_DONE
-	}
-
-	/**
-	 * The current phase of the agent {@link Phase}
-	 */
-	protected Phase currentPhase = Phase.INITIALIZING;
-	
-	private boolean synchronous = true;
-
-	/**
-	 * The constructor automatically add the agent to the corresponding amas and
-	 * initialize the agent
-	 * 
-	 * @param amas
-	 *            Amas the agent belongs to
-	 * @param params
-	 *            The params to initialize the agent
-	 */
-	public Agent(A amas, Object... params) {
-		this.id = uniqueIndex++;
-		this.params = params;
-		this.amas = amas;
-		neighborhood = new ArrayList<>();
-		neighborhood.add(this);
-		onInitialization();
-		if (!Configuration.commandLineMode)
-			onRenderingInitialization();
-		
-
-		if (amas != null) {
-			this.amas._addAgent(this);
-		}
-	}
-
-	/**
-	 * Add neighbors to the agent
-	 * 
-	 * @param agents
-	 *            The list of agent that should be considered as neighbor
-	 */
-	@SafeVarargs
-	public final void addNeighbor(Agent<A, E>... agents) {
-		for (Agent<A, E> agent : agents) {
-			if (agent != null) {
-				neighborhood.add(agent);
-				criticalities.put(agent, Double.NEGATIVE_INFINITY);
-			}
-		}
-	}
-
-	/**
-	 * This method must be overridden by the agents. This method shouldn't make any
-	 * calls to internal representation an agent has on its environment because
-	 * these information maybe outdated.
-	 * 
-	 * @return the criticality at a given moment
-	 */
-	protected double computeCriticality() {
-		return Double.NEGATIVE_INFINITY;
-	}
-
-	protected void setAsynchronous() {
-		if (currentPhase != Phase.INITIALIZING)
-			Log.defaultLog.fatal("AMAK", "Asynchronous mode must be set during the initialization");
-		this.synchronous = false;
-	}
-	/**
-	 * This method must be overriden if you need to specify an execution order layer
-	 * 
-	 * @return the execution order layer
-	 */
-	protected int computeExecutionOrderLayer() {
-		return 0;
-	}
-
-	/**
-	 * This method is called at the beginning of an agent's cycle
-	 */
-	protected void onAgentCycleBegin() {
-
-	}
-
-	/**
-	 * This method is called at the end of an agent's cycle
-	 */
-	protected void onAgentCycleEnd() {
-
-	}
-
-	/**
-	 * This method corresponds to the perception phase of the agents and must be
-	 * overridden
-	 */
-	protected void onPerceive() {
-
-	}
-
-	/**
-	 * This method corresponds to the decision phase of the agents and must be
-	 * overridden
-	 */
-	protected void onDecide() {
-
-	}
-
-	/**
-	 * This method corresponds to the action phase of the agents and must be
-	 * overridden
-	 */
-	protected void onAct() {
-
-	}
-
-	/**
-	 * In this method the agent should expose some variables with its neighbor
-	 */
-	protected void onExpose() {
-
-	}
-
-	/**
-	 * This method should be used to update the representation of the agent for
-	 * example in a VUI
-	 */
-	public void onUpdateRender() {
-
-	}
-
-	/**
-	 * This method is now deprecated and should be replaced by onUpdateRender
-	 * 
-	 * @deprecated Must be replaced by {@link #onUpdateRender()}
-	 */
-	@Deprecated
-	protected final void onDraw() {
-
-	}
-
-	/**
-	 * Called when all initial agents have been created and are ready to be started
-	 */
-	protected void onReady() {
-
-	}
-
-	/**
-	 * Called by the framework when all initial agents have been created and are
-	 * almost ready to be started
-	 */
-	protected final void _onBeforeReady() {
-		criticality = computeCriticality();
-		executionOrder = _computeExecutionOrder();
-	}
-
-	/**
-	 * Called before all agents are created
-	 */
-	protected void onInitialization() {
-
-	}
-
-	/**
-	 * Replaced by onInitialization
-	 * 
-	 * @deprecated Must be replaced by {@link #onInitialization()}
-	 */
-	@Deprecated
-	protected final void onInitialize() {
-
-	}
-
-	/**
-	 * Called to initialize the rendering of the agent
-	 */
-	protected void onRenderingInitialization() {
-
-	}
-
-	/**
-	 * @deprecated This method is useless because the state of the agent is not
-	 *             supposed to evolve before or after its cycle. Use
-	 *             OnAgentCycleBegin/End instead.
-	 * 
-	 *             This method is final because it must not be implemented.
-	 *             Implement it will have no effect.
-	 */
-	@Deprecated
-	protected final void onSystemCycleBegin() {
-
-	}
-
-	/**
-	 * @deprecated This method is useless because the state of the agent is not
-	 *             supposed to evolve before or after its cycle. Use
-	 *             OnAgentCycleBegin/End instead.
-	 * 
-	 *             This method is final because it must not be implemented.
-	 *             Implement it will have no effect.
-	 */
-	@Deprecated
-	protected final void onSystemCycleEnd() {
-
-	}
-
-	/**
-	 * This method is called automatically and corresponds to a full cycle of an
-	 * agent
-	 */
-	@Override
-	public void run() {
-		ExecutionPolicy executionPolicy = amas.getExecutionPolicy();
-		if (executionPolicy == ExecutionPolicy.TWO_PHASES) {
-
-			currentPhase = nextPhase();
-			switch (currentPhase) {
-			case PERCEPTION:
-				phase1();
-				amas.informThatAgentPerceptionIsFinished();
-				break;
-			case DECISION_AND_ACTION:
-				phase2();
-				amas.informThatAgentDecisionAndActionAreFinished();
-				break;
-			default:
-				Log.defaultLog.fatal("AMAK", "An agent is being run in an invalid phase (%s)", currentPhase);
-			}
-		} else if (executionPolicy == ExecutionPolicy.ONE_PHASE) {
-			onePhaseCycle();
-			amas.informThatAgentPerceptionIsFinished();
-			amas.informThatAgentDecisionAndActionAreFinished();
-		}
-	}
-	public void onePhaseCycle() {
-		currentPhase = Phase.PERCEPTION;
-		phase1();
-		currentPhase = Phase.DECISION_AND_ACTION;
-		phase2();
-	}
-	/**
-	 * This method represents the perception phase of the agent
-	 */
-	protected final void phase1() {
-		onAgentCycleBegin();
-		perceive();
-		currentPhase = Phase.PERCEPTION_DONE;
-	}
-
-	/**
-	 * This method represents the decisionAndAction phase of the agent
-	 */
-	protected final void phase2() {
-		decideAndAct();
-		executionOrder = _computeExecutionOrder();
-		onExpose();
-		if (!Configuration.commandLineMode)
-			onUpdateRender();
-		onAgentCycleEnd();
-		currentPhase = Phase.DECISION_AND_ACTION_DONE;
-	}
-
-	/**
-	 * Determine which phase comes after another
-	 * 
-	 * @return the next phase
-	 */
-	private Phase nextPhase() {
-		switch (currentPhase) {
-		case PERCEPTION_DONE:
-			return Phase.DECISION_AND_ACTION;
-		case INITIALIZING:
-		case DECISION_AND_ACTION_DONE:
-		default:
-			return Phase.PERCEPTION;
-		}
-	}
-
-	/**
-	 * Compute the execution order from the layer and a random value. This method
-	 * shouldn't be overridden.
-	 * 
-	 * @return A number used by amak to determine which agent executes first
-	 */
-	protected int _computeExecutionOrder() {
-		return computeExecutionOrderLayer() * 10000 + amas.getEnvironment().getRandom().nextInt(10000);
-	}
-
-	/**
-	 * Perceive, decide and act
-	 */
-	void perceive() {
-		for (Agent<A, E> agent : neighborhood) {
-			criticalities.put(agent, agent.criticality);
-		}
-		onPerceive();
-		// Criticality of agent should be updated after perception AND after action
-		criticality = computeCriticality();
-		criticalities.put(this, criticality);
-	}
-
-	/**
-	 * A combination of decision and action as called by the framework
-	 */
-	private final void decideAndAct() {
-		onDecideAndAct();
-
-		criticality = computeCriticality();
-	}
-
-	/**
-	 * Decide and act These two phases can often be grouped
-	 */
-	protected void onDecideAndAct() {
-		onDecide();
-		onAct();
-	}
-
-	/**
-	 * Convenient method giving the most critical neighbor at a given moment
-	 * 
-	 * @param includingMe
-	 *            Should the agent also consider its own criticality
-	 * @return the most critical agent
-	 */
-	protected final Agent<A, E> getMostCriticalNeighbor(boolean includingMe) {
-		List<Agent<A, E>> criticalest = new ArrayList<>();
-		double maxCriticality = Double.NEGATIVE_INFINITY;
-
-		if (includingMe) {
-			criticalest.add(this);
-			maxCriticality = criticalities.getOrDefault(criticalest, Double.NEGATIVE_INFINITY);
-		}
-		for (Entry<Agent<A, E>, Double> e : criticalities.entrySet()) {
-			if (e.getValue() > maxCriticality) {
-				criticalest.clear();
-				maxCriticality = e.getValue();
-				criticalest.add(e.getKey());
-			} else if (e.getValue() == maxCriticality) {
-				criticalest.add(e.getKey());
-			}
-		}
-		if (criticalest.isEmpty())
-			return null;
-		return criticalest.get(getEnvironment().getRandom().nextInt(criticalest.size()));
-	}
-
-	/**
-	 * Get the latest computed execution order
-	 * 
-	 * @return the execution order
-	 */
-	public int getExecutionOrder() {
-		return executionOrder;
-	}
-
-	/**
-	 * Getter for the AMAS
-	 * 
-	 * @return the amas
-	 */
-	public A getAmas() {
-		return amas;
-	}
-
-	/**
-	 * Remove the agent from the system
-	 */
-	public void destroy() {
-		getAmas()._removeAgent(this);
-	}
-
-	/**
-	 * Agent toString
-	 */
-	@Override
-	public String toString() {
-		return String.format("Agent #%d", id);
-	}
-
-	/**
-	 * Getter for the current phase of the agent
-	 * 
-	 * @return the current phase
-	 */
-	public Phase getCurrentPhase() {
-		return currentPhase;
-	}
-
-	/**
-	 * Return the id of the agent
-	 * 
-	 * @return the id of the agent
-	 */
-	public int getId() {
-		return id;
-	}
-
-	/**
-	 * Getter for the environment
-	 * 
-	 * @return the environment
-	 */
-	public E getEnvironment() {
-		return getAmas().getEnvironment();
-	}
-
-	public boolean isSynchronous() {
-		return synchronous ;
-	}
-}
+package fr.irit.smac.amak;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import fr.irit.smac.amak.Amas.ExecutionPolicy;
+import fr.irit.smac.amak.tools.Log;
+import fr.irit.smac.amak.ui.AmasMultiUIWindow;
+
+/**
+ * This class must be overridden by all agents
+ * 
+ * @author Alexandre Perles
+ *
+ * @param <A>
+ *            The kind of Amas the agent refers to
+ * @param <E>
+ *            The kind of Environment the agent AND the Amas refer to
+ */
+public abstract class Agent<A extends Amas<E>, E extends Environment> implements Runnable {
+	
+	public AmasMultiUIWindow amasMultiUIWindow;
+	
+	/**
+	 * Neighborhood of the agent (must refer to the same couple amas, environment
+	 */
+	protected final List<Agent<A, E>> neighborhood;
+	/**
+	 * Criticalities of the neighbors (and it self) as perceived at the beginning of
+	 * the agent's cycle
+	 */
+	protected final Map<Agent<A, E>, Double> criticalities = new HashMap<>();
+	/**
+	 * Last calculated criticality of the agent
+	 */
+	private double criticality;
+	/**
+	 * Amas the agent belongs to
+	 */
+	protected final A amas;
+	/**
+	 * Unique index to give unique id to each agent
+	 */
+	private static int uniqueIndex;
+
+	/**
+	 * The id of the agent
+	 */
+	private final int id;
+	/**
+	 * The order of execution of the agent as computed by
+	 * {@link Agent#_computeExecutionOrder()}
+	 */
+	private int executionOrder;
+	/**
+	 * The parameters that can be user in the initialization process
+	 * {@link Agent#onInitialization()}
+	 */
+	protected Object[] params;
+
+	/**
+	 * These phases are used to synchronize agents on phase
+	 * 
+	 * @see fr.irit.smac.amak.Amas.ExecutionPolicy
+	 * @author perles
+	 *
+	 */
+	public enum Phase {
+		/**
+		 * Agent is perceiving
+		 */
+		PERCEPTION,
+		/**
+		 * Agent is deciding and acting
+		 */
+		DECISION_AND_ACTION,
+		/**
+		 * Agent haven't started to perceive, decide or act
+		 */
+		INITIALIZING,
+		/**
+		 * Agent is ready to decide
+		 */
+		PERCEPTION_DONE,
+		/**
+		 * Agent is ready to perceive or die
+		 */
+		DECISION_AND_ACTION_DONE
+	}
+
+	/**
+	 * The current phase of the agent {@link Phase}
+	 */
+	protected Phase currentPhase = Phase.INITIALIZING;
+	
+	private boolean synchronous = true;
+
+	/**
+	 * The constructor automatically add the agent to the corresponding amas and
+	 * initialize the agent
+	 * 
+	 * @param amas
+	 *            Amas the agent belongs to
+	 * @param params
+	 *            The params to initialize the agent
+	 */
+	public Agent(A amas, Object... params) {
+		this.id = uniqueIndex++;
+		this.params = params;
+		this.amas = amas;
+		neighborhood = new ArrayList<>();
+		neighborhood.add(this);
+		onInitialization();
+		if (!Configuration.commandLineMode)
+			onRenderingInitialization();
+		
+
+		if (amas != null) {
+			this.amas._addAgent(this);
+		}
+	}
+	
+	public Agent(AmasMultiUIWindow window, A amas, Object... params) {
+		amasMultiUIWindow = window;
+		
+		this.id = uniqueIndex++;
+		this.params = params;
+		this.amas = amas;
+		neighborhood = new ArrayList<>();
+		neighborhood.add(this);
+		onInitialization();
+		if (!Configuration.commandLineMode)
+			onRenderingInitialization();
+		
+
+		if (amas != null) {
+			this.amas._addAgent(this);
+		}
+	}
+
+	/**
+	 * Add neighbors to the agent
+	 * 
+	 * @param agents
+	 *            The list of agent that should be considered as neighbor
+	 */
+	@SafeVarargs
+	public final void addNeighbor(Agent<A, E>... agents) {
+		for (Agent<A, E> agent : agents) {
+			if (agent != null) {
+				neighborhood.add(agent);
+				criticalities.put(agent, Double.NEGATIVE_INFINITY);
+			}
+		}
+	}
+
+	/**
+	 * This method must be overridden by the agents. This method shouldn't make any
+	 * calls to internal representation an agent has on its environment because
+	 * these information maybe outdated.
+	 * 
+	 * @return the criticality at a given moment
+	 */
+	protected double computeCriticality() {
+		return Double.NEGATIVE_INFINITY;
+	}
+
+	protected void setAsynchronous() {
+		if (currentPhase != Phase.INITIALIZING)
+			Log.defaultLog.fatal("AMAK", "Asynchronous mode must be set during the initialization");
+		this.synchronous = false;
+	}
+	/**
+	 * This method must be overriden if you need to specify an execution order layer
+	 * 
+	 * @return the execution order layer
+	 */
+	protected int computeExecutionOrderLayer() {
+		return 0;
+	}
+
+	/**
+	 * This method is called at the beginning of an agent's cycle
+	 */
+	protected void onAgentCycleBegin() {
+
+	}
+
+	/**
+	 * This method is called at the end of an agent's cycle
+	 */
+	protected void onAgentCycleEnd() {
+
+	}
+
+	/**
+	 * This method corresponds to the perception phase of the agents and must be
+	 * overridden
+	 */
+	protected void onPerceive() {
+
+	}
+
+	/**
+	 * This method corresponds to the decision phase of the agents and must be
+	 * overridden
+	 */
+	protected void onDecide() {
+
+	}
+
+	/**
+	 * This method corresponds to the action phase of the agents and must be
+	 * overridden
+	 */
+	protected void onAct() {
+
+	}
+
+	/**
+	 * In this method the agent should expose some variables with its neighbor
+	 */
+	protected void onExpose() {
+
+	}
+
+	/**
+	 * This method should be used to update the representation of the agent for
+	 * example in a VUI
+	 */
+	public void onUpdateRender() {
+
+	}
+
+	/**
+	 * This method is now deprecated and should be replaced by onUpdateRender
+	 * 
+	 * @deprecated Must be replaced by {@link #onUpdateRender()}
+	 */
+	@Deprecated
+	protected final void onDraw() {
+
+	}
+
+	/**
+	 * Called when all initial agents have been created and are ready to be started
+	 */
+	protected void onReady() {
+
+	}
+
+	/**
+	 * Called by the framework when all initial agents have been created and are
+	 * almost ready to be started
+	 */
+	protected final void _onBeforeReady() {
+		criticality = computeCriticality();
+		executionOrder = _computeExecutionOrder();
+	}
+
+	/**
+	 * Called before all agents are created
+	 */
+	protected void onInitialization() {
+
+	}
+
+	/**
+	 * Replaced by onInitialization
+	 * 
+	 * @deprecated Must be replaced by {@link #onInitialization()}
+	 */
+	@Deprecated
+	protected final void onInitialize() {
+
+	}
+
+	/**
+	 * Called to initialize the rendering of the agent
+	 */
+	protected void onRenderingInitialization() {
+
+	}
+
+	/**
+	 * @deprecated This method is useless because the state of the agent is not
+	 *             supposed to evolve before or after its cycle. Use
+	 *             OnAgentCycleBegin/End instead.
+	 * 
+	 *             This method is final because it must not be implemented.
+	 *             Implement it will have no effect.
+	 */
+	@Deprecated
+	protected final void onSystemCycleBegin() {
+
+	}
+
+	/**
+	 * @deprecated This method is useless because the state of the agent is not
+	 *             supposed to evolve before or after its cycle. Use
+	 *             OnAgentCycleBegin/End instead.
+	 * 
+	 *             This method is final because it must not be implemented.
+	 *             Implement it will have no effect.
+	 */
+	@Deprecated
+	protected final void onSystemCycleEnd() {
+
+	}
+
+	/**
+	 * This method is called automatically and corresponds to a full cycle of an
+	 * agent
+	 */
+	@Override
+	public void run() {
+		ExecutionPolicy executionPolicy = amas.getExecutionPolicy();
+		if (executionPolicy == ExecutionPolicy.TWO_PHASES) {
+
+			currentPhase = nextPhase();
+			switch (currentPhase) {
+			case PERCEPTION:
+				phase1();
+				amas.informThatAgentPerceptionIsFinished();
+				break;
+			case DECISION_AND_ACTION:
+				phase2();
+				amas.informThatAgentDecisionAndActionAreFinished();
+				break;
+			default:
+				Log.defaultLog.fatal("AMAK", "An agent is being run in an invalid phase (%s)", currentPhase);
+			}
+		} else if (executionPolicy == ExecutionPolicy.ONE_PHASE) {
+			onePhaseCycle();
+			amas.informThatAgentPerceptionIsFinished();
+			amas.informThatAgentDecisionAndActionAreFinished();
+		}
+	}
+	public void onePhaseCycle() {
+		currentPhase = Phase.PERCEPTION;
+		phase1();
+		currentPhase = Phase.DECISION_AND_ACTION;
+		phase2();
+	}
+	/**
+	 * This method represents the perception phase of the agent
+	 */
+	protected final void phase1() {
+		onAgentCycleBegin();
+		perceive();
+		currentPhase = Phase.PERCEPTION_DONE;
+	}
+
+	/**
+	 * This method represents the decisionAndAction phase of the agent
+	 */
+	protected final void phase2() {
+		decideAndAct();
+		executionOrder = _computeExecutionOrder();
+		onExpose();
+		if (!Configuration.commandLineMode)
+			onUpdateRender();
+		onAgentCycleEnd();
+		currentPhase = Phase.DECISION_AND_ACTION_DONE;
+	}
+
+	/**
+	 * Determine which phase comes after another
+	 * 
+	 * @return the next phase
+	 */
+	private Phase nextPhase() {
+		switch (currentPhase) {
+		case PERCEPTION_DONE:
+			return Phase.DECISION_AND_ACTION;
+		case INITIALIZING:
+		case DECISION_AND_ACTION_DONE:
+		default:
+			return Phase.PERCEPTION;
+		}
+	}
+
+	/**
+	 * Compute the execution order from the layer and a random value. This method
+	 * shouldn't be overridden.
+	 * 
+	 * @return A number used by amak to determine which agent executes first
+	 */
+	protected int _computeExecutionOrder() {
+		return computeExecutionOrderLayer() * 10000 + amas.getEnvironment().getRandom().nextInt(10000);
+	}
+
+	/**
+	 * Perceive, decide and act
+	 */
+	void perceive() {
+		for (Agent<A, E> agent : neighborhood) {
+			criticalities.put(agent, agent.criticality);
+		}
+		onPerceive();
+		// Criticality of agent should be updated after perception AND after action
+		criticality = computeCriticality();
+		criticalities.put(this, criticality);
+	}
+
+	/**
+	 * A combination of decision and action as called by the framework
+	 */
+	private final void decideAndAct() {
+		onDecideAndAct();
+
+		criticality = computeCriticality();
+	}
+
+	/**
+	 * Decide and act These two phases can often be grouped
+	 */
+	protected void onDecideAndAct() {
+		onDecide();
+		onAct();
+	}
+
+	/**
+	 * Convenient method giving the most critical neighbor at a given moment
+	 * 
+	 * @param includingMe
+	 *            Should the agent also consider its own criticality
+	 * @return the most critical agent
+	 */
+	protected final Agent<A, E> getMostCriticalNeighbor(boolean includingMe) {
+		List<Agent<A, E>> criticalest = new ArrayList<>();
+		double maxCriticality = Double.NEGATIVE_INFINITY;
+
+		if (includingMe) {
+			criticalest.add(this);
+			maxCriticality = criticalities.getOrDefault(criticalest, Double.NEGATIVE_INFINITY);
+		}
+		for (Entry<Agent<A, E>, Double> e : criticalities.entrySet()) {
+			if (e.getValue() > maxCriticality) {
+				criticalest.clear();
+				maxCriticality = e.getValue();
+				criticalest.add(e.getKey());
+			} else if (e.getValue() == maxCriticality) {
+				criticalest.add(e.getKey());
+			}
+		}
+		if (criticalest.isEmpty())
+			return null;
+		return criticalest.get(getEnvironment().getRandom().nextInt(criticalest.size()));
+	}
+
+	/**
+	 * Get the latest computed execution order
+	 * 
+	 * @return the execution order
+	 */
+	public int getExecutionOrder() {
+		return executionOrder;
+	}
+
+	/**
+	 * Getter for the AMAS
+	 * 
+	 * @return the amas
+	 */
+	public A getAmas() {
+		return amas;
+	}
+
+	/**
+	 * Remove the agent from the system
+	 */
+	public void destroy() {
+		getAmas()._removeAgent(this);
+	}
+
+	/**
+	 * Agent toString
+	 */
+	@Override
+	public String toString() {
+		return String.format("Agent #%d", id);
+	}
+
+	/**
+	 * Getter for the current phase of the agent
+	 * 
+	 * @return the current phase
+	 */
+	public Phase getCurrentPhase() {
+		return currentPhase;
+	}
+
+	/**
+	 * Return the id of the agent
+	 * 
+	 * @return the id of the agent
+	 */
+	public int getId() {
+		return id;
+	}
+
+	/**
+	 * Getter for the environment
+	 * 
+	 * @return the environment
+	 */
+	public E getEnvironment() {
+		return getAmas().getEnvironment();
+	}
+
+	public boolean isSynchronous() {
+		return synchronous ;
+	}
+}
diff --git a/AMAKFX/src/fr/irit/smac/amak/Amas.java b/AMAKFX/src/fr/irit/smac/amak/Amas.java
index a73d0e5107ef13fc638c7e17037858d93ae44c5d..a92400870625b739704f5ba05350fdf1c119fe35 100644
--- a/AMAKFX/src/fr/irit/smac/amak/Amas.java
+++ b/AMAKFX/src/fr/irit/smac/amak/Amas.java
@@ -13,6 +13,7 @@ import java.util.stream.Collectors;
 
 import fr.irit.smac.amak.tools.Log;
 import fr.irit.smac.amak.tools.RunLaterHelper;
+import fr.irit.smac.amak.ui.AmasMultiUIWindow;
 import fr.irit.smac.amak.ui.MainWindow;
 import fr.irit.smac.amak.ui.SchedulerToolbar;
 import fr.irit.smac.amak.ui.VUI;
@@ -26,6 +27,9 @@ import fr.irit.smac.amak.ui.VUI;
  *            The environment of the MAS
  */
 public class Amas<E extends Environment> implements Schedulable {
+	
+	public AmasMultiUIWindow amasMultiUIWindow;
+	
 	/**
 	 * List of agents present in the system
 	 */
@@ -155,6 +159,36 @@ public class Amas<E extends Environment> implements Schedulable {
 			this.onRenderingInitialization();
 		this.scheduler.unlock();
 	}
+	
+	public Amas(AmasMultiUIWindow window, E environment, Scheduling scheduling, Object... params) {
+		
+		amasMultiUIWindow = window;
+		executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(Configuration.allowedSimultaneousAgentsExecution);
+		if (scheduling == Scheduling.DEFAULT) {
+			//MainWindow.instance();
+			this.scheduler = Scheduler.getDefaultScheduler(window);
+			this.scheduler.add(this);
+		} else {
+			this.scheduler = new Scheduler(this);
+			if (scheduling == Scheduling.UI && !Configuration.commandLineMode) {
+				//MainWindow.instance();
+				amasMultiUIWindow.addToolbar(new SchedulerToolbar("Amas #" + id, getScheduler()));
+			}
+		}
+		
+		this.scheduler.lock();
+		this.params = params;
+		this.environment = environment;
+		this.onInitialConfiguration();
+		executionPolicy = Configuration.executionPolicy;
+		this.onInitialAgentsCreation();
+
+		addPendingAgents();
+		this.onReady();
+		if (!Configuration.commandLineMode)
+			this.onRenderingInitialization();
+		this.scheduler.unlock();
+	}
 
 	/**
 	 * The method in which the rendering initialization should be made. For example,
@@ -371,7 +405,12 @@ public class Amas<E extends Environment> implements Schedulable {
 	 * {@link Amas#onRenderingInitialization}
 	 */
 	protected void onUpdateRender() {
-		VUI.get().updateCanvas();
+		if(Configuration.multiUI) {
+			VUI.get(amasMultiUIWindow).updateCanvas();
+		}else {
+			VUI.get().updateCanvas();
+		}
+		
 	}
 
 	/**
diff --git a/AMAKFX/src/fr/irit/smac/amak/Configuration.java b/AMAKFX/src/fr/irit/smac/amak/Configuration.java
index bc8050f8b87e296f7497acf1932764c02508c4f2..34c301cc8ae3334a7c8f49476db23e17af8a6b65 100644
--- a/AMAKFX/src/fr/irit/smac/amak/Configuration.java
+++ b/AMAKFX/src/fr/irit/smac/amak/Configuration.java
@@ -47,4 +47,6 @@ public class Configuration {
 	 * By default AMAK will wait for 1 sec before updating the plots
 	 */
 	public static double plotMilliSecondsUpdate = 1000;
+	
+	public static boolean multiUI = false;
 }
diff --git a/AMAKFX/src/fr/irit/smac/amak/Environment.java b/AMAKFX/src/fr/irit/smac/amak/Environment.java
index 68433e456f0c7b95e24b646a47e8806d67dd4666..1d87b8eee2a96555e1660c6d1c96462832512f58 100644
--- a/AMAKFX/src/fr/irit/smac/amak/Environment.java
+++ b/AMAKFX/src/fr/irit/smac/amak/Environment.java
@@ -1,145 +1,168 @@
-package fr.irit.smac.amak;
-
-import java.util.Random;
-
-import fr.irit.smac.amak.ui.MainWindow;
-import fr.irit.smac.amak.ui.SchedulerToolbar;
-
-/**
- * This class must be overridden by environments
- * 
- * @author Alexandre Perles
- *
- */
-public abstract class Environment implements Schedulable {
-
-	/**
-	 * Unique index to give unique id to each environment
-	 */
-	private static int uniqueIndex;
-
-	/**
-	 * The id of the environment
-	 */
-	private final int id = uniqueIndex++;
-
-	/**
-	 * The parameters that are passed to {@link Environment#onInitialization()}
-	 */
-	protected Object[] params;
-	/**
-	 * Random object common to the amas
-	 */
-	private Random random = new Random();
-	/**
-	 * The scheduler of the environment
-	 */
-	private Scheduler scheduler;
-
-	/**
-	 * Constructor
-	 * 
-	 * @param _scheduling
-	 *            The scheduling of the environment
-	 * @param params
-	 *            The parameters to initialize the environment
-	 */
-	public Environment(Scheduling _scheduling, Object... params) {
-		if (_scheduling == Scheduling.DEFAULT) {
-			this.scheduler = Scheduler.getDefaultScheduler();
-			this.scheduler.add(this);
-		} else {
-			this.scheduler = new Scheduler(this);
-			if (_scheduling == Scheduling.UI && !Configuration.commandLineMode)
-				MainWindow.addToolbar(new SchedulerToolbar("Environment #" + id, getScheduler()));
-		}
-		this.scheduler.lock();
-		this.params = params;
-		onInitialization();
-		onInitialEntitiesCreation();
-		if (!Configuration.commandLineMode)
-			onRenderingInitialization();
-		this.scheduler.unlock();
-	}
-
-	/**
-	 * Override this method is you wish to render environment. For example, you can
-	 * use this method to create a VUI drawable object.
-	 */
-	private void onRenderingInitialization() {
-	}
-
-	/**
-	 * Getter for the scheduler
-	 * 
-	 * @return the scheduler
-	 */
-	public Scheduler getScheduler() {
-		return scheduler;
-	}
-
-	/**
-	 * Set the seed for the common random object. This method should be called at
-	 * the very beginning of the initialization process
-	 * 
-	 * @param _seed
-	 *            The seed to initialize the random object
-	 */
-	public void setSeed(long _seed) {
-		random = new Random(_seed);
-	}
-
-	/**
-	 * This method is called during the initialization process of the environment
-	 */
-	public void onInitialization() {
-	}
-
-	/**
-	 * This method is called after the initialization process of the environment to
-	 * create entities
-	 */
-	public void onInitialEntitiesCreation() {
-	}
-
-	/**
-	 * This method is called at each cycle of the environment
-	 */
-	public void onCycle() {
-	}
-
-	@Override
-	public boolean stopCondition() {
-		return false;
-	}
-
-	@Override
-	public final void cycle() {
-		onCycle();
-		if (!Configuration.commandLineMode)
-			onUpdateRender();
-	}
-
-	/**
-	 * Override this method to update rendering related to the environment
-	 */
-	protected void onUpdateRender() {
-	}
-
-	/**
-	 * Getter for the random object
-	 * 
-	 * @return the random object
-	 */
-	public Random getRandom() {
-		return random;
-	}
-
-	@Override
-	public void onSchedulingStarts() {
-	}
-
-	@Override
-	public void onSchedulingStops() {
-	}
-}
+package fr.irit.smac.amak;
+
+import java.util.Random;
+
+import fr.irit.smac.amak.ui.AmasMultiUIWindow;
+import fr.irit.smac.amak.ui.MainWindow;
+import fr.irit.smac.amak.ui.SchedulerToolbar;
+
+/**
+ * This class must be overridden by environments
+ * 
+ * @author Alexandre Perles
+ *
+ */
+public abstract class Environment implements Schedulable {
+	
+	public AmasMultiUIWindow amasMultiUIWindow;
+
+	/**
+	 * Unique index to give unique id to each environment
+	 */
+	private static int uniqueIndex;
+
+	/**
+	 * The id of the environment
+	 */
+	private final int id = uniqueIndex++;
+
+	/**
+	 * The parameters that are passed to {@link Environment#onInitialization()}
+	 */
+	protected Object[] params;
+	/**
+	 * Random object common to the amas
+	 */
+	private Random random = new Random();
+	/**
+	 * The scheduler of the environment
+	 */
+	private Scheduler scheduler;
+
+	/**
+	 * Constructor
+	 * 
+	 * @param _scheduling
+	 *            The scheduling of the environment
+	 * @param params
+	 *            The parameters to initialize the environment
+	 */
+	public Environment(Scheduling _scheduling, Object... params) {
+		if (_scheduling == Scheduling.DEFAULT) {
+			this.scheduler = Scheduler.getDefaultScheduler();
+			this.scheduler.add(this);
+		} else {
+			this.scheduler = new Scheduler(this);
+			if (_scheduling == Scheduling.UI && !Configuration.commandLineMode)
+				MainWindow.addToolbar(new SchedulerToolbar("Environment #" + id, getScheduler()));
+		}
+		this.scheduler.lock();
+		this.params = params;
+		onInitialization();
+		onInitialEntitiesCreation();
+		if (!Configuration.commandLineMode)
+			onRenderingInitialization();
+		this.scheduler.unlock();
+	}
+	
+	public Environment(AmasMultiUIWindow window, Scheduling _scheduling, Object... params) {
+		amasMultiUIWindow = window;
+		if (_scheduling == Scheduling.DEFAULT) {
+			this.scheduler = Scheduler.getDefaultScheduler(window);
+			this.scheduler.add(this);
+		} else {
+		this.scheduler = new Scheduler(this);
+		if (_scheduling == Scheduling.UI && !Configuration.commandLineMode)
+			amasMultiUIWindow.addToolbar(new SchedulerToolbar("Environment #" + id, getScheduler()));
+		}
+
+		this.scheduler.lock();
+		this.params = params;
+		onInitialization();
+		onInitialEntitiesCreation();
+		if (!Configuration.commandLineMode)
+			onRenderingInitialization();
+		this.scheduler.unlock();
+	}
+
+	/**
+	 * Override this method is you wish to render environment. For example, you can
+	 * use this method to create a VUI drawable object.
+	 */
+	private void onRenderingInitialization() {
+	}
+
+	/**
+	 * Getter for the scheduler
+	 * 
+	 * @return the scheduler
+	 */
+	public Scheduler getScheduler() {
+		return scheduler;
+	}
+
+	/**
+	 * Set the seed for the common random object. This method should be called at
+	 * the very beginning of the initialization process
+	 * 
+	 * @param _seed
+	 *            The seed to initialize the random object
+	 */
+	public void setSeed(long _seed) {
+		random = new Random(_seed);
+	}
+
+	/**
+	 * This method is called during the initialization process of the environment
+	 */
+	public void onInitialization() {
+	}
+
+	/**
+	 * This method is called after the initialization process of the environment to
+	 * create entities
+	 */
+	public void onInitialEntitiesCreation() {
+	}
+
+	/**
+	 * This method is called at each cycle of the environment
+	 */
+	public void onCycle() {
+	}
+
+	@Override
+	public boolean stopCondition() {
+		return false;
+	}
+
+	@Override
+	public final void cycle() {
+		onCycle();
+		if (!Configuration.commandLineMode)
+			onUpdateRender();
+	}
+
+	/**
+	 * Override this method to update rendering related to the environment
+	 */
+	protected void onUpdateRender() {
+	}
+
+	/**
+	 * Getter for the random object
+	 * 
+	 * @return the random object
+	 */
+	public Random getRandom() {
+		return random;
+	}
+
+	@Override
+	public void onSchedulingStarts() {
+	}
+
+	@Override
+	public void onSchedulingStops() {
+	}
+}
diff --git a/AMAKFX/src/fr/irit/smac/amak/Scheduler.java b/AMAKFX/src/fr/irit/smac/amak/Scheduler.java
index bffeeb2ce6a8d7e7a2422d165b41817e2e8b44c6..f509d7f4d20d69a27f6f49ce719acdd71fe1683c 100644
--- a/AMAKFX/src/fr/irit/smac/amak/Scheduler.java
+++ b/AMAKFX/src/fr/irit/smac/amak/Scheduler.java
@@ -1,341 +1,354 @@
-package fr.irit.smac.amak;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.ConcurrentModificationException;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Queue;
-import java.util.Set;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.function.Consumer;
-
-import fr.irit.smac.amak.ui.MainWindow;
-import fr.irit.smac.amak.ui.SchedulerToolbar;
-
-/**
- * A scheduler associated to a MAS
- * 
- * @author Alexandre Perles
- *
- */
-public class Scheduler implements Runnable, Serializable {
-	/**
-	 * Unique ID meant to handle serialization correctly
-	 */
-	private static final long serialVersionUID = -4765899565369100376L;
-	/**
-	 * The schedulables object handled by the scheduler
-	 */
-	private final Set<Schedulable> schedulables = new LinkedHashSet<>();
-	/**
-	 * The state of the scheduler {@link State}
-	 */
-	private State state;
-	/**
-	 * The sleep time in ms between each cycle
-	 */
-	private int sleep;
-	/**
-	 * A lock to protect the state
-	 */
-	private final ReentrantLock stateLock = new ReentrantLock();
-	/**
-	 * Method that is called when the scheduler stops
-	 */
-	private Consumer<Scheduler> onStop;
-	/**
-	 * The methods called when the speed is changed. Useful to change the value of
-	 * the GUI slider of {@link SchedulerToolbar}
-	 */
-	private List<Consumer<Scheduler>> onChange = new ArrayList<>();
-	/**
-	 * The idea is to prevent scheduler from launching if the schedulables are not
-	 * yet fully ready
-	 */
-	private int locked = 0;
-	/**
-	 * The default scheduler
-	 */
-	private static Scheduler defaultScheduler;
-	/**
-	 * The schedulables that must be added
-	 */
-	private Queue<Schedulable> pendingAdditionSchedulables = new LinkedList<>();
-	/**
-	 * The schedulables that must be removed
-	 */
-	private Queue<Schedulable> pendingRemovalSchedulables = new LinkedList<>();
-
-	/**
-	 * State of the scheduler
-	 *
-	 */
-	public enum State {
-		/**
-		 * The scheduler is running
-		 */
-		RUNNING,
-		/**
-		 * The scheduler is paused
-		 */
-		IDLE,
-		/**
-		 * The scheduler is expected to stop at the end at the current cycle
-		 */
-		PENDING_STOP
-
-	}
-
-	/**
-	 * Constructor which set the initial state and auto start if requested
-	 * 
-	 * @param _schedulables
-	 *            the corresponding schedulables
-	 */
-	public Scheduler(Schedulable... _schedulables) {
-
-		for (Schedulable schedulable : _schedulables) {
-			this.add(schedulable);
-		}
-		this.state = State.IDLE;
-	}
-
-	/**
-	 * Create or return the default scheduler
-	 * 
-	 * @return The default scheduler
-	 */
-	public static Scheduler getDefaultScheduler() {
-		if (defaultScheduler == null) {
-			defaultScheduler = new Scheduler();
-			if (!Configuration.commandLineMode) {
-				MainWindow.instance();
-				SchedulerToolbar st = new SchedulerToolbar("Default", defaultScheduler);
-				MainWindow.addToolbar(st);
-			}
-		}
-		return defaultScheduler;
-	}
-
-	/**
-	 * Set the delay between two cycles and launch the scheduler if it is not
-	 * running
-	 * 
-	 * @param i
-	 *            the delay between two cycles
-	 */
-	public void startWithSleep(int i) {
-		if (locked > 0) {
-
-			synchronized (onChange) {
-				onChange.forEach(c -> c.accept(this));
-			}
-			return;
-		}
-		setSleep(i);
-		stateLock.lock();
-		switch (state) {
-		case IDLE:
-			state = State.RUNNING;
-			new Thread(this).start();
-			break;
-		default:
-			break;
-		}
-		stateLock.unlock();
-		synchronized (onChange) {
-			onChange.forEach(c -> c.accept(this));
-		}
-	}
-
-	/**
-	 * Start (or continue) with no delay between cycles
-	 */
-	public void start() {
-		startWithSleep(Schedulable.DEFAULT_SLEEP);
-	}
-
-	/**
-	 * Execute one cycle
-	 */
-	public void step() {
-		if (locked > 0) {
-			synchronized (onChange) {
-				onChange.forEach(c -> c.accept(this));
-			}
-			return;
-		}
-		this.setSleep(0);
-		stateLock.lock();
-		switch (state) {
-		case IDLE:
-			state = State.PENDING_STOP;
-			new Thread(this).start();
-			break;
-		default:
-			break;
-
-		}
-		stateLock.unlock();
-		synchronized (onChange) {
-			onChange.forEach(c -> c.accept(this));
-		}
-	}
-
-	/**
-	 * Stop the scheduler if it is running
-	 */
-	public void stop() {
-		stateLock.lock();
-		switch (state) {
-		case RUNNING:
-			state = State.PENDING_STOP;
-			break;
-		default:
-			break;
-
-		}
-		stateLock.unlock();
-		synchronized (onChange) {
-			onChange.forEach(c -> c.accept(this));
-		}
-	}
-
-	/**
-	 * Threaded run method
-	 */
-	@Override
-	public void run() {
-		treatPendingSchedulables();
-		for (Schedulable schedulable : schedulables) {
-			schedulable.onSchedulingStarts();
-		}
-		boolean mustStop;
-		do {
-			for (Schedulable schedulable : schedulables) {
-				schedulable.cycle();
-			}
-			if (getSleep() != 0) {
-				try {
-					Thread.sleep(getSleep());
-				} catch (final InterruptedException e) {
-					e.printStackTrace();
-				}
-			}
-			mustStop = false;
-			for (Schedulable schedulable : schedulables) {
-				mustStop |= schedulable.stopCondition();
-			}
-		} while (state == State.RUNNING && !mustStop);
-		stateLock.lock();
-		state = State.IDLE;
-		stateLock.unlock();
-
-		for (Schedulable schedulable : schedulables) {
-			schedulable.onSchedulingStops();
-		}
-		treatPendingSchedulables();
-		if (onStop != null)
-			onStop.accept(this);
-	}
-
-	/**
-	 * Effectively Add or Remove the schedulables that were added or removed during
-	 * a cycle to avoid {@link ConcurrentModificationException}
-	 */
-	private void treatPendingSchedulables() {
-		while (!pendingAdditionSchedulables.isEmpty())
-			schedulables.add(pendingAdditionSchedulables.poll());
-		while (!pendingRemovalSchedulables.isEmpty())
-			schedulables.remove(pendingRemovalSchedulables.poll());
-
-	}
-
-	/**
-	 * Set the method that must be executed when the system is stopped
-	 * 
-	 * @param _onStop
-	 *            Consumer method
-	 */
-	public final void setOnStop(Consumer<Scheduler> _onStop) {
-		this.onStop = _onStop;
-	}
-
-	/**
-	 * Add a method that must be executed when the scheduler speed is changed
-	 * 
-	 * @param _onChange
-	 *            Consumer method
-	 */
-	public final void addOnChange(Consumer<Scheduler> _onChange) {
-		synchronized (onChange) {
-			this.onChange.add(_onChange);
-		}
-	}
-
-	/**
-	 * Is the scheduler running ?
-	 * 
-	 * @return true if the scheduler is running
-	 */
-	public boolean isRunning() {
-		return state == State.RUNNING;
-	}
-
-	/**
-	 * Getter for the sleep time
-	 * 
-	 * @return the sleep time
-	 */
-
-	public int getSleep() {
-		return sleep;
-	}
-
-	/**
-	 * Setter for the sleep time
-	 * 
-	 * @param sleep
-	 *            The time between each cycle
-	 */
-	public void setSleep(int sleep) {
-		this.sleep = sleep;
-	}
-
-	/**
-	 * Plan to add a schedulable
-	 * 
-	 * @param _schedulable
-	 *            the schedulable to add
-	 */
-	public void add(Schedulable _schedulable) {
-		this.pendingAdditionSchedulables.add(_schedulable);
-	}
-
-	/**
-	 * Plan to remove a schedulable
-	 * 
-	 * @param _schedulable
-	 *            the schedulable to remove
-	 */
-	public void remove(Schedulable _schedulable) {
-		this.pendingRemovalSchedulables.add(_schedulable);
-	}
-
-	/**
-	 * Soft lock the scheduler to avoid a too early running
-	 */
-	public void lock() {
-		locked++;
-	}
-
-	/**
-	 * Soft unlock the scheduler to avoid a too early running
-	 */
-	public void unlock() {
-		locked--;
-	}
-
-}
+package fr.irit.smac.amak;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.ConcurrentModificationException;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
+
+import fr.irit.smac.amak.ui.AmasMultiUIWindow;
+import fr.irit.smac.amak.ui.MainWindow;
+import fr.irit.smac.amak.ui.SchedulerToolbar;
+
+/**
+ * A scheduler associated to a MAS
+ * 
+ * @author Alexandre Perles
+ *
+ */
+public class Scheduler implements Runnable, Serializable {
+	/**
+	 * Unique ID meant to handle serialization correctly
+	 */
+	private static final long serialVersionUID = -4765899565369100376L;
+	/**
+	 * The schedulables object handled by the scheduler
+	 */
+	private final Set<Schedulable> schedulables = new LinkedHashSet<>();
+	/**
+	 * The state of the scheduler {@link State}
+	 */
+	private State state;
+	/**
+	 * The sleep time in ms between each cycle
+	 */
+	private int sleep;
+	/**
+	 * A lock to protect the state
+	 */
+	private final ReentrantLock stateLock = new ReentrantLock();
+	/**
+	 * Method that is called when the scheduler stops
+	 */
+	private Consumer<Scheduler> onStop;
+	/**
+	 * The methods called when the speed is changed. Useful to change the value of
+	 * the GUI slider of {@link SchedulerToolbar}
+	 */
+	private List<Consumer<Scheduler>> onChange = new ArrayList<>();
+	/**
+	 * The idea is to prevent scheduler from launching if the schedulables are not
+	 * yet fully ready
+	 */
+	private int locked = 0;
+	/**
+	 * The default scheduler
+	 */
+	private static Scheduler defaultScheduler;
+	/**
+	 * The schedulables that must be added
+	 */
+	private Queue<Schedulable> pendingAdditionSchedulables = new LinkedList<>();
+	/**
+	 * The schedulables that must be removed
+	 */
+	private Queue<Schedulable> pendingRemovalSchedulables = new LinkedList<>();
+
+	/**
+	 * State of the scheduler
+	 *
+	 */
+	public enum State {
+		/**
+		 * The scheduler is running
+		 */
+		RUNNING,
+		/**
+		 * The scheduler is paused
+		 */
+		IDLE,
+		/**
+		 * The scheduler is expected to stop at the end at the current cycle
+		 */
+		PENDING_STOP
+
+	}
+
+	/**
+	 * Constructor which set the initial state and auto start if requested
+	 * 
+	 * @param _schedulables
+	 *            the corresponding schedulables
+	 */
+	public Scheduler(Schedulable... _schedulables) {
+
+		for (Schedulable schedulable : _schedulables) {
+			this.add(schedulable);
+		}
+		this.state = State.IDLE;
+	}
+
+	/**
+	 * Create or return the default scheduler
+	 * 
+	 * @return The default scheduler
+	 */
+	public static Scheduler getDefaultScheduler() {
+		if (defaultScheduler == null) {
+			defaultScheduler = new Scheduler();
+			if (!Configuration.commandLineMode) {
+				MainWindow.instance();
+				SchedulerToolbar st = new SchedulerToolbar("Default", defaultScheduler);
+				MainWindow.addToolbar(st);
+			}
+		}
+		return defaultScheduler;
+	}
+	
+	public static Scheduler getDefaultScheduler(AmasMultiUIWindow window) {
+		if (defaultScheduler == null) {
+			defaultScheduler = new Scheduler();
+			if (!Configuration.commandLineMode) {
+				//MainWindow.instance();
+				SchedulerToolbar st = new SchedulerToolbar("Default", defaultScheduler);
+				window.addToolbar(st);
+			}
+		}
+		return defaultScheduler;
+	}
+
+	/**
+	 * Set the delay between two cycles and launch the scheduler if it is not
+	 * running
+	 * 
+	 * @param i
+	 *            the delay between two cycles
+	 */
+	public void startWithSleep(int i) {
+		if (locked > 0) {
+
+			synchronized (onChange) {
+				onChange.forEach(c -> c.accept(this));
+			}
+			return;
+		}
+		setSleep(i);
+		stateLock.lock();
+		switch (state) {
+		case IDLE:
+			state = State.RUNNING;
+			new Thread(this).start();
+			break;
+		default:
+			break;
+		}
+		stateLock.unlock();
+		synchronized (onChange) {
+			onChange.forEach(c -> c.accept(this));
+		}
+	}
+
+	/**
+	 * Start (or continue) with no delay between cycles
+	 */
+	public void start() {
+		startWithSleep(Schedulable.DEFAULT_SLEEP);
+	}
+
+	/**
+	 * Execute one cycle
+	 */
+	public void step() {
+		if (locked > 0) {
+			synchronized (onChange) {
+				onChange.forEach(c -> c.accept(this));
+			}
+			return;
+		}
+		this.setSleep(0);
+		stateLock.lock();
+		switch (state) {
+		case IDLE:
+			state = State.PENDING_STOP;
+			new Thread(this).start();
+			break;
+		default:
+			break;
+
+		}
+		stateLock.unlock();
+		synchronized (onChange) {
+			onChange.forEach(c -> c.accept(this));
+		}
+	}
+
+	/**
+	 * Stop the scheduler if it is running
+	 */
+	public void stop() {
+		stateLock.lock();
+		switch (state) {
+		case RUNNING:
+			state = State.PENDING_STOP;
+			break;
+		default:
+			break;
+
+		}
+		stateLock.unlock();
+		synchronized (onChange) {
+			onChange.forEach(c -> c.accept(this));
+		}
+	}
+
+	/**
+	 * Threaded run method
+	 */
+	@Override
+	public void run() {
+		treatPendingSchedulables();
+		for (Schedulable schedulable : schedulables) {
+			schedulable.onSchedulingStarts();
+		}
+		boolean mustStop;
+		do {
+			for (Schedulable schedulable : schedulables) {
+				schedulable.cycle();
+			}
+			if (getSleep() != 0) {
+				try {
+					Thread.sleep(getSleep());
+				} catch (final InterruptedException e) {
+					e.printStackTrace();
+				}
+			}
+			mustStop = false;
+			for (Schedulable schedulable : schedulables) {
+				mustStop |= schedulable.stopCondition();
+			}
+		} while (state == State.RUNNING && !mustStop);
+		stateLock.lock();
+		state = State.IDLE;
+		stateLock.unlock();
+
+		for (Schedulable schedulable : schedulables) {
+			schedulable.onSchedulingStops();
+		}
+		treatPendingSchedulables();
+		if (onStop != null)
+			onStop.accept(this);
+	}
+
+	/**
+	 * Effectively Add or Remove the schedulables that were added or removed during
+	 * a cycle to avoid {@link ConcurrentModificationException}
+	 */
+	private void treatPendingSchedulables() {
+		while (!pendingAdditionSchedulables.isEmpty())
+			schedulables.add(pendingAdditionSchedulables.poll());
+		while (!pendingRemovalSchedulables.isEmpty())
+			schedulables.remove(pendingRemovalSchedulables.poll());
+
+	}
+
+	/**
+	 * Set the method that must be executed when the system is stopped
+	 * 
+	 * @param _onStop
+	 *            Consumer method
+	 */
+	public final void setOnStop(Consumer<Scheduler> _onStop) {
+		this.onStop = _onStop;
+	}
+
+	/**
+	 * Add a method that must be executed when the scheduler speed is changed
+	 * 
+	 * @param _onChange
+	 *            Consumer method
+	 */
+	public final void addOnChange(Consumer<Scheduler> _onChange) {
+		synchronized (onChange) {
+			this.onChange.add(_onChange);
+		}
+	}
+
+	/**
+	 * Is the scheduler running ?
+	 * 
+	 * @return true if the scheduler is running
+	 */
+	public boolean isRunning() {
+		return state == State.RUNNING;
+	}
+
+	/**
+	 * Getter for the sleep time
+	 * 
+	 * @return the sleep time
+	 */
+
+	public int getSleep() {
+		return sleep;
+	}
+
+	/**
+	 * Setter for the sleep time
+	 * 
+	 * @param sleep
+	 *            The time between each cycle
+	 */
+	public void setSleep(int sleep) {
+		this.sleep = sleep;
+	}
+
+	/**
+	 * Plan to add a schedulable
+	 * 
+	 * @param _schedulable
+	 *            the schedulable to add
+	 */
+	public void add(Schedulable _schedulable) {
+		this.pendingAdditionSchedulables.add(_schedulable);
+	}
+
+	/**
+	 * Plan to remove a schedulable
+	 * 
+	 * @param _schedulable
+	 *            the schedulable to remove
+	 */
+	public void remove(Schedulable _schedulable) {
+		this.pendingRemovalSchedulables.add(_schedulable);
+	}
+
+	/**
+	 * Soft lock the scheduler to avoid a too early running
+	 */
+	public void lock() {
+		locked++;
+	}
+
+	/**
+	 * Soft unlock the scheduler to avoid a too early running
+	 */
+	public void unlock() {
+		locked--;
+	}
+
+}
diff --git a/AMAKFX/src/fr/irit/smac/amak/examples/randomants/AntExampleMutliUI.java b/AMAKFX/src/fr/irit/smac/amak/examples/randomants/AntExampleMutliUI.java
new file mode 100644
index 0000000000000000000000000000000000000000..62c06ef392dc2ac841394a5403f56577efebc6a4
--- /dev/null
+++ b/AMAKFX/src/fr/irit/smac/amak/examples/randomants/AntExampleMutliUI.java
@@ -0,0 +1,93 @@
+package fr.irit.smac.amak.examples.randomants;
+
+import fr.irit.smac.amak.Agent;
+import fr.irit.smac.amak.ui.AmasMultiUIWindow;
+import fr.irit.smac.amak.ui.VUI;
+import fr.irit.smac.amak.ui.drawables.DrawableImage;
+
+public class AntExampleMutliUI extends Agent<AntHillExampleMultiUI, WorldExampleMultiUI> {
+	
+	
+	
+	private boolean dead = false; 
+	
+	/**
+	 * X coordinate of the ant in the world
+	 */
+	public double dx;
+	/**
+	 * Y coordinate of the ant in the world
+	 */
+	public double dy;
+	/**
+	 * Angle in radians
+	 */
+	private double angle = Math.random() * Math.PI * 2;
+	private DrawableImage image;
+
+	/**
+	 * Constructor of the ant
+	 * 
+	 * @param amas
+	 *            the amas the ant belongs to
+	 * @param startX
+	 *            Initial X coordinate
+	 * @param startY
+	 *            Initial Y coordinate
+	 */
+	public AntExampleMutliUI(AmasMultiUIWindow window, AntHillExampleMultiUI amas, double startX, double startY) {
+		super(window, amas, startX, startY);
+		System.out.println(amasMultiUIWindow + "            ------------- AntExampleMutliUI 42");
+	}
+	@Override
+	public void onInitialization() {
+		dx = (double) params[0];
+		dy = (double) params[1];
+	}
+
+	@Override
+	protected void onRenderingInitialization() {
+		System.out.println(amasMultiUIWindow + "            ------------- AntExampleMutliUI 52");
+		image = VUI.get(amasMultiUIWindow).createAndAddImage(dx, dy, "file:resources/ant.png");
+		image.setName("Ant "+getId());
+	}
+
+	/**
+	 * Move in a random direction
+	 */
+	@Override
+	protected void onDecideAndAct() {
+		double random = amas.getEnvironment().getRandom().nextGaussian();
+		angle += random * 0.1;
+		dx += Math.cos(angle);
+		dy += Math.sin(angle);
+		while (dx >= getAmas().getEnvironment().getWidth() / 2)
+			dx -= getAmas().getEnvironment().getWidth();
+		while (dy >= getAmas().getEnvironment().getHeight() / 2)
+			dy -= getAmas().getEnvironment().getHeight();
+		while (dx < -getAmas().getEnvironment().getWidth() / 2)
+			dx += getAmas().getEnvironment().getWidth();
+		while (dy < -getAmas().getEnvironment().getHeight() / 2)
+			dy += getAmas().getEnvironment().getHeight();
+
+		if (amas.getEnvironment().getRandom().nextDouble() < 0.001) {
+			dead = true;
+			destroy();
+		}
+
+		if (amas.getEnvironment().getRandom().nextDouble() < 0.001) {
+			new AntExampleMutliUI(amasMultiUIWindow, getAmas(), dx, dy);
+		}
+	}
+
+	@Override
+	public void onUpdateRender() {
+		image.move(dx, dy);
+		image.setAngle(angle);
+		image.setInfo("Ant "+getId()+"\nPosition "+dx+" "+dy+"\nAngle "+angle);
+		if(dead) {
+			image.setFilename("file:Resources/ant_dead.png");
+			image.setInfo("Ant "+getId()+"\nPosition "+dx+" "+dy+"\nAngle "+angle+"\nDead");
+		}
+	}
+}
diff --git a/AMAKFX/src/fr/irit/smac/amak/examples/randomants/AntHillExampleMultiUI.java b/AMAKFX/src/fr/irit/smac/amak/examples/randomants/AntHillExampleMultiUI.java
new file mode 100644
index 0000000000000000000000000000000000000000..fe8564924cfa7fa2c1548c56387abfd8da69181b
--- /dev/null
+++ b/AMAKFX/src/fr/irit/smac/amak/examples/randomants/AntHillExampleMultiUI.java
@@ -0,0 +1,38 @@
+package fr.irit.smac.amak.examples.randomants;
+
+import fr.irit.smac.amak.Amas;
+import fr.irit.smac.amak.Scheduling;
+import fr.irit.smac.amak.tools.RunLaterHelper;
+import fr.irit.smac.amak.ui.AmasMultiUIWindow;
+import fr.irit.smac.amak.ui.VUI;
+import fr.irit.smac.amak.ui.drawables.DrawableString;
+
+public class AntHillExampleMultiUI extends Amas<WorldExampleMultiUI> {
+
+	private DrawableString antsCountLabel;
+
+	public AntHillExampleMultiUI(AmasMultiUIWindow window, WorldExampleMultiUI env) {
+		super(window, env, Scheduling.DEFAULT);
+		System.out.println(window + "            ------------- AntHillExampleMultiUI 16");
+	}
+
+	@Override
+	protected void onRenderingInitialization() {
+		VUI.get(amasMultiUIWindow).createAndAddImage(20, 20, "file:Resources/ant.png").setFixed().setLayer(10).setShowInExplorer(false);
+		antsCountLabel = (DrawableString) VUI.get().createAndAddString(45, 25, "Ants count").setFixed().setLayer(10).setShowInExplorer(false);
+	}
+
+	@Override
+	protected void onInitialAgentsCreation() {
+		for (int i = 0; i < 50; i++) {
+			System.out.println(amasMultiUIWindow + "            ------------- AntHillExampleMultiUI 28");
+			new AntExampleMutliUI(amasMultiUIWindow, this, 0, 0);
+		}
+			
+	}
+
+	@Override
+	protected void onSystemCycleEnd() {
+		RunLaterHelper.runLater(()->antsCountLabel.setText("Ants count: " + getAgents().size()));
+	}
+}
diff --git a/AMAKFX/src/fr/irit/smac/amak/examples/randomants/AntsLaunchExampleMultiUI.java b/AMAKFX/src/fr/irit/smac/amak/examples/randomants/AntsLaunchExampleMultiUI.java
new file mode 100644
index 0000000000000000000000000000000000000000..b592877357310be5f1eeaa46361e75acd60a7396
--- /dev/null
+++ b/AMAKFX/src/fr/irit/smac/amak/examples/randomants/AntsLaunchExampleMultiUI.java
@@ -0,0 +1,58 @@
+package fr.irit.smac.amak.examples.randomants;
+
+import fr.irit.smac.amak.Configuration;
+import fr.irit.smac.amak.ui.AmasMultiUIWindow;
+import fr.irit.smac.amak.ui.MainWindow;
+import javafx.application.Application;
+import javafx.scene.control.Label;
+import javafx.scene.layout.Pane;
+import javafx.stage.Stage;
+
+public class AntsLaunchExampleMultiUI extends Application{
+
+	
+	
+	
+	
+	
+	
+	public static void main (String[] args) {
+		
+		
+		Application.launch(args);
+		
+		
+		
+		//MainWindow.instance();		
+		
+		
+	}
+
+	@Override
+	public void start(Stage primaryStage) throws Exception {
+		
+		Configuration.multiUI=true;
+		
+		AmasMultiUIWindow window = new AmasMultiUIWindow();
+		AmasMultiUIWindow window2 = new AmasMultiUIWindow();
+		
+		WorldExampleMultiUI env = new WorldExampleMultiUI(window);
+		WorldExampleMultiUI env2 = new WorldExampleMultiUI(window2);
+		
+
+		new AntHillExampleMultiUI(window, env);
+		new AntHillExampleMultiUI(window2, env2);
+		
+		Pane panel = new Pane();
+		panel.getChildren().add(new Label("AntHill simulation\n"
+				+ "Ants move randomly.\n"
+				+ "This demo is here to show AMAK rendering capacities.\n"));
+		window.setLeftPanel(panel);
+		
+		Pane panel2 = new Pane();
+		panel2.getChildren().add(new Label("AntHill simulation\n"
+				+ "Ants move randomly.\n"
+				+ "This demo is here to show AMAK rendering capacities.\n"));
+		window2.setLeftPanel(panel2);
+	}
+}
diff --git a/AMAKFX/src/fr/irit/smac/amak/examples/randomants/HelloWorld.java b/AMAKFX/src/fr/irit/smac/amak/examples/randomants/HelloWorld.java
new file mode 100644
index 0000000000000000000000000000000000000000..a1a015c3cbba9b8dc9cf7ef322d8a70065dde946
--- /dev/null
+++ b/AMAKFX/src/fr/irit/smac/amak/examples/randomants/HelloWorld.java
@@ -0,0 +1,37 @@
+package fr.irit.smac.amak.examples.randomants;
+
+import javafx.application.Application;
+import javafx.scene.Group;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.text.Font;
+import javafx.scene.text.Text;
+import javafx.stage.Stage;
+
+public class HelloWorld extends Application {
+
+    @Override public void start(Stage stage) {
+        Text text = new Text(10, 40, "Hello World!");
+        text.setFont(new Font(40));
+        Scene scene = new Scene(new Group(text));
+
+        stage.setTitle("Welcome to JavaFX!"); 
+        stage.setScene(scene); 
+        stage.sizeToScene(); 
+        
+        
+
+        Stage stage2 = new Stage();
+        stage2.setScene(new Scene(new Group(new Button("my second window"))));
+        stage2.show();
+
+        stage.show(); 
+    }
+    
+    
+
+    public static void main(String[] args) {
+        Application.launch(args);
+    }
+}
+
diff --git a/AMAKFX/src/fr/irit/smac/amak/examples/randomants/WorldExample.java b/AMAKFX/src/fr/irit/smac/amak/examples/randomants/WorldExample.java
index 2c6ea56a9ef181a9cf191d87669c578c3dd7e24b..88156754ae2aaa969ed1b24c99ad7143f3854987 100644
--- a/AMAKFX/src/fr/irit/smac/amak/examples/randomants/WorldExample.java
+++ b/AMAKFX/src/fr/irit/smac/amak/examples/randomants/WorldExample.java
@@ -1,28 +1,28 @@
-package fr.irit.smac.amak.examples.randomants;
-
-import fr.irit.smac.amak.Environment;
-import fr.irit.smac.amak.Scheduling;
-
-public class WorldExample extends Environment {
-	public WorldExample(Object...params) {
-		super(Scheduling.DEFAULT, params);
-	}
-
-	private int width;
-	private int height;
-
-	public int getWidth() {
-		return width;
-	}
-
-	public int getHeight() {
-		return height;
-	}
-
-	@Override
-	public void onInitialization() {
-		this.width = 800;
-		this.height = 600;
-	}
-
-}
+package fr.irit.smac.amak.examples.randomants;
+
+import fr.irit.smac.amak.Environment;
+import fr.irit.smac.amak.Scheduling;
+
+public class WorldExample extends Environment {
+	public WorldExample(Object...params) {
+		super(Scheduling.DEFAULT, params);
+	}
+
+	private int width;
+	private int height;
+
+	public int getWidth() {
+		return width;
+	}
+
+	public int getHeight() {
+		return height;
+	}
+
+	@Override
+	public void onInitialization() {
+		this.width = 800;
+		this.height = 600;
+	}
+
+}
diff --git a/AMAKFX/src/fr/irit/smac/amak/examples/randomants/WorldExampleMultiUI.java b/AMAKFX/src/fr/irit/smac/amak/examples/randomants/WorldExampleMultiUI.java
new file mode 100644
index 0000000000000000000000000000000000000000..22f9e6913fffcd74374b7274dc8fe25e1a9ffb21
--- /dev/null
+++ b/AMAKFX/src/fr/irit/smac/amak/examples/randomants/WorldExampleMultiUI.java
@@ -0,0 +1,29 @@
+package fr.irit.smac.amak.examples.randomants;
+
+import fr.irit.smac.amak.Environment;
+import fr.irit.smac.amak.Scheduling;
+import fr.irit.smac.amak.ui.AmasMultiUIWindow;
+
+public class WorldExampleMultiUI extends Environment {
+	public WorldExampleMultiUI(AmasMultiUIWindow window, Object...params) {
+		super(window, Scheduling.DEFAULT, params);
+	}
+
+	private int width;
+	private int height;
+
+	public int getWidth() {
+		return width;
+	}
+
+	public int getHeight() {
+		return height;
+	}
+
+	@Override
+	public void onInitialization() {
+		this.width = 800;
+		this.height = 600;
+	}
+
+}
diff --git a/AMAKFX/src/fr/irit/smac/amak/ui/AmakPlot.java b/AMAKFX/src/fr/irit/smac/amak/ui/AmakPlot.java
index 60a58286244634a53702a0cea0126b6a792c29aa..a50dcea052955e308ffca135ce65c6d0998898a2 100644
--- a/AMAKFX/src/fr/irit/smac/amak/ui/AmakPlot.java
+++ b/AMAKFX/src/fr/irit/smac/amak/ui/AmakPlot.java
@@ -36,6 +36,10 @@ public class AmakPlot {
 	public static void add(AmakPlot chart) {
 		MainWindow.addTabbedPanel(chart.name, new ChartViewer(chart.chart));
 	}
+	
+	public static void add(AmasMultiUIWindow window, AmakPlot chart) {
+		window.addTabbedPanel(chart.name, new ChartViewer(chart.chart));
+	}
 	/* ----- */
 	
 	private String name;
@@ -119,6 +123,79 @@ public class AmakPlot {
 		this(name, chart, true);
 	}
 	
+	
+	/**
+	 * Create a chart
+	 * @param name the name of the chart, used as the tab name.
+	 * @param chartType {@link ChartType#LINE} or {@link ChartType#BAR}
+	 * @param xAxisLabel label for the x (horizontal) axis 
+	 * @param yAxisLabel label for the y (vertical) axis
+	 * @param autoAdd automatically make an {@link AmakPlot#add(AmakPlot)} call ?
+	 */
+	public AmakPlot(AmasMultiUIWindow window, String name, ChartType chartType, String xAxisLabel, String yAxisLabel, boolean autoAdd) {
+		this.name = name;
+		seriesCollection = new XYSeriesCollection();
+		switch (chartType) {
+		case BAR:
+			chart = ChartFactory.createXYBarChart(name, xAxisLabel, false, yAxisLabel, seriesCollection);
+			break;
+		case LINE:
+			chart = ChartFactory.createXYLineChart(name, xAxisLabel, yAxisLabel, seriesCollection);
+			if(useSamplingRenderer) {
+				chart.getXYPlot().setRenderer(new SamplingXYLineRenderer());
+			}
+			XYPlot plot = (XYPlot)chart.getPlot();
+			plot.setDomainGridlinesVisible(true);
+	        plot.setDomainGridlinePaint(Color.lightGray);
+	        plot.setRangeGridlinePaint(Color.lightGray);
+			break;
+		default:
+			System.err.println("AmakPlot : unknow ChartType \""+chartType+"\".");
+			break;
+		}
+		chart.setAntiAlias(false);
+		chart.getPlot().setBackgroundPaint(Color.WHITE);
+		if(autoAdd) {
+			add(window, this);
+		}
+	}
+	
+	/**
+	 * Create a chart and add it to the main window.
+	 * @param name the name of the chart, used as the tab name.
+	 * @param chartType {@link ChartType#LINE} or {@link ChartType#BAR}
+	 * @param xAxisLabel label for the x (horizontal) axis 
+	 * @param yAxisLabel label for the y (vertical) axis
+	 */
+	public AmakPlot(AmasMultiUIWindow window, String name, ChartType chartType, String xAxisLabel, String yAxisLabel) {
+		this(window, name, chartType, xAxisLabel, yAxisLabel, true);
+	}
+	
+	
+	/**
+	 * Create a chart out of a JFreeChart.
+	 * Make sure that your chart use an {@link XYSeriesCollection} as dataset.
+	 * @param name the name of the chart, used as the tab name.
+	 * @param chart the {@link JFreeChart} using a {@link XYSeriesCollection} for dataset.
+	 * @param autoAdd automatically make an {@link AmakPlot#add(AmakPlot)} call ?
+	 */
+	public AmakPlot(AmasMultiUIWindow window, String name, JFreeChart chart, boolean autoAdd) {
+		this.name = name;
+		this.seriesCollection = (XYSeriesCollection) chart.getXYPlot().getDataset();
+		this.chart = chart;
+		add(window, this);
+	}
+	
+	/**
+	 * Create a chart out of a JFreeChart and add it to the main window.
+	 * Make sure that your chart use an {@link XYSeriesCollection} as dataset.
+	 * @param name the name of the chart, used as the tab name.
+	 * @param chart the {@link JFreeChart} using a {@link XYSeriesCollection} for dataset.
+	 */
+	public AmakPlot(AmasMultiUIWindow window, String name, JFreeChart chart) {
+		this(window, name, chart, true);
+	}
+	
 	public String getName() {
 		return name;
 	}
diff --git a/AMAKFX/src/fr/irit/smac/amak/ui/AmasMultiUIWindow.java b/AMAKFX/src/fr/irit/smac/amak/ui/AmasMultiUIWindow.java
new file mode 100644
index 0000000000000000000000000000000000000000..53ca4e46eeecf1df1b2ab7a0db9502cffcf173d0
--- /dev/null
+++ b/AMAKFX/src/fr/irit/smac/amak/ui/AmasMultiUIWindow.java
@@ -0,0 +1,251 @@
+package fr.irit.smac.amak.ui;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.management.InstanceAlreadyExistsException;
+
+import fr.irit.smac.amak.Information;
+import fr.irit.smac.amak.tools.RunLaterHelper;
+import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.scene.Node;
+import javafx.scene.Scene;
+import javafx.scene.control.Menu;
+import javafx.scene.control.MenuBar;
+import javafx.scene.control.MenuItem;
+import javafx.scene.control.Tab;
+import javafx.scene.control.TabPane;
+import javafx.scene.control.ToolBar;
+import javafx.scene.image.Image;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.Priority;
+import javafx.scene.layout.VBox;
+import javafx.stage.Stage;
+import javafx.stage.WindowEvent;
+
+/**
+ * This window is the main one of an AMAS developed using AMAK. It contains a
+ * toolbar panel and various spaces for panels
+ * 
+ * @author of the original version (the Swing one) Alexandre Perles, Marcillaud
+ *         Guilhem
+ *
+ */
+public class AmasMultiUIWindow extends Stage{
+//	/**
+//	 * The window itself
+//	 */
+//	public Stage stage;
+	/**
+	 * The panel which contains the toolbar
+	 */
+	public ToolBar toolbarPanel;
+
+	/**
+	 * The main pane of AMAK
+	 */
+	public BorderPane organizationPane;
+	
+	/**
+	 * The menu bar of the window
+	 */
+	public MenuBar menuBar;
+	/**
+	 * The menus
+	 */
+	public HashMap<String, Menu> menus = new HashMap<String, Menu>();
+	/**
+	 * The panel in which panels with tab can be added
+	 */
+	public TabPane tabbedPanel;
+
+	
+	protected static Object startEnded = new Object();
+
+	/**
+	 * Create the frame.
+	 * 
+	 * @throws InstanceAlreadyExistsException
+	 *             if the MainWindow has already been instantiated. This constructor
+	 *             should be used by the Application of JavaFX only.
+	 */
+	public AmasMultiUIWindow() {
+		synchronized (startEnded) {
+			VBox root = new VBox();
+			
+			// Creation of the menu bar (Top)
+			menuBar = new MenuBar();
+			root.getChildren().add(menuBar);
+			
+			// Border organization
+			organizationPane = new BorderPane();
+			organizationPane.setMinSize(200, 200); //that way we avoid 0 size, which can cause problems
+			root.getChildren().add(organizationPane);
+			VBox.setVgrow(organizationPane, Priority.ALWAYS);
+			
+			// Creation of scene
+			this.setTitle("AMAS");
+			Scene scene = new Scene(root, 450, 300);
+			//stage = primaryStage;
+			this.setScene(scene);
+			this.setOnCloseRequest(new EventHandler<WindowEvent>() {
+				@Override
+				public void handle(WindowEvent event) {
+					Platform.exit();
+				}
+			});
+	
+			// Creation of the toolbar (Bottom)
+			toolbarPanel = new ToolBar();
+			organizationPane.setBottom(toolbarPanel);
+	
+			// Creation of the right part of the split pane (Center Right)
+			tabbedPanel = new TabPane();
+			organizationPane.setCenter(tabbedPanel);
+	
+			// Creation of the close menu item
+			MenuItem menuItem = new MenuItem("Close");
+			menuItem.setOnAction(new EventHandler<ActionEvent>() {
+				@Override
+				public void handle(ActionEvent event) {
+					System.exit(0);
+				}
+			});
+			addToMenu("Options", menuItem);
+	
+			menuBar.getMenus().add(new Menu("AMAKFX v" + Information.VERSION));
+	
+			this.show();
+			
+			startEnded.notify();
+		}
+	}
+
+//	@Override
+//	public void start(Stage primaryStage) throws Exception {
+//		
+//	}
+
+	/**
+	 * Add an action when the JavaFX app close.
+	 * 
+	 * @param onClose
+	 *            The action to be executed when the window is closed
+	 */
+	public static void addOnCloseAction(Runnable onClose) {
+		Runtime.getRuntime().addShutdownHook(new Thread() {
+		    public void run() { onClose.run(); }
+		});
+	}
+	
+//	@Override
+//	public void stop() throws Exception {
+//		super.stop();
+//		System.exit(0);
+//	}
+
+	/**
+	 * Change the icon of the window
+	 * 
+	 * @param filename
+	 *            The filename of the icon
+	 */
+	public  void setWindowIcon(String filename) {
+		RunLaterHelper.runLater(() -> this.getIcons().add(new Image(filename)));
+	}
+
+	/**
+	 * Change the title of the main window
+	 * 
+	 * @param title
+	 *            The new title
+	 */
+	public void setWindowTitle(String title) {
+		RunLaterHelper.runLater(() -> this.setTitle(title));
+	}
+	
+	/**
+	 * Add a button in the menu options
+	 * 
+	 * @param title
+	 *            The title of the button
+	 * @param event
+	 *            The action to be executed
+	 */
+	public  void addOptionsItem(String title, EventHandler<ActionEvent> event) {
+		MenuItem menuItem = new MenuItem(title);
+		menuItem.setOnAction(event);
+		RunLaterHelper.runLater(() -> addToMenu("Options", menuItem));
+	}
+
+	/**
+	 * Add a tool in the toolbar.
+	 * 
+	 * @param tool
+	 */
+	public  void addToolbar(Node tool) {
+		RunLaterHelper.runLater(() -> toolbarPanel.getItems().add(tool));
+	}
+
+	/**
+	 * Set a panel to the left
+	 * 
+	 * @param panel
+	 *            The panel
+	 */
+	public void setLeftPanel(Node panel) {
+		RunLaterHelper.runLater(() -> organizationPane.setLeft(panel));
+	}
+
+	/**
+	 * Set a panel to the right
+	 * 
+	 * @param panel
+	 *            The panel
+	 */
+	public void setRightPanel(Node panel) {
+		RunLaterHelper.runLater(() -> organizationPane.setRight(panel));
+	}
+
+	/**
+	 * Return the unique instance of MainWindow, may create it.
+	 * 
+	 * @return instance
+	 */
+	
+	
+
+
+	/**
+	 * Add a panel with a tab
+	 * 
+	 * @param title
+	 *            The title of the tab
+	 * @param panel
+	 *            The panel to add
+	 */
+	public void addTabbedPanel(String title, Node panel) {
+		Tab t = new DraggableTab(title, panel);
+		RunLaterHelper.runLater(() -> tabbedPanel.getTabs().add(t));
+	}
+	
+	/**
+	 * Add a {@link MenuItem} to a {@link Menu}. May create the menu and add it to the menu bar.
+	 * @param menuName the name of the menu where the item will be added.
+	 * @param item the item to be added.
+	 */
+	public void addToMenu(String menuName, MenuItem item) {
+		//instance();
+		if( !menus.containsKey(menuName) ) {
+			Menu m = new Menu(menuName);
+			menus.put(menuName,m);
+			RunLaterHelper.runLater(() -> menuBar.getMenus().add(m));
+		}
+		RunLaterHelper.runLater(() -> menus.get(menuName).getItems().add(item));
+	}
+}
\ No newline at end of file
diff --git a/AMAKFX/src/fr/irit/smac/amak/ui/VUI.java b/AMAKFX/src/fr/irit/smac/amak/ui/VUI.java
index 136cb472ac33fbffb9e2f7c7ddda551fe2384d81..e396e9bb3deabfc2b3c05beef8826f5002258568 100644
--- a/AMAKFX/src/fr/irit/smac/amak/ui/VUI.java
+++ b/AMAKFX/src/fr/irit/smac/amak/ui/VUI.java
@@ -1,577 +1,588 @@
-package fr.irit.smac.amak.ui;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.locks.ReentrantLock;
-
-import fr.irit.smac.amak.tools.RunLaterHelper;
-import fr.irit.smac.amak.ui.drawables.Drawable;
-import fr.irit.smac.amak.ui.drawables.DrawableImage;
-import fr.irit.smac.amak.ui.drawables.DrawablePoint;
-import fr.irit.smac.amak.ui.drawables.DrawableRectangle;
-import fr.irit.smac.amak.ui.drawables.DrawableString;
-import javafx.event.ActionEvent;
-import javafx.event.EventHandler;
-import javafx.geometry.Insets;
-import javafx.scene.control.Button;
-import javafx.scene.control.Label;
-import javafx.scene.control.ToolBar;
-import javafx.scene.control.Tooltip;
-import javafx.scene.input.MouseEvent;
-import javafx.scene.input.ScrollEvent;
-import javafx.scene.layout.Background;
-import javafx.scene.layout.BackgroundFill;
-import javafx.scene.layout.BorderPane;
-import javafx.scene.layout.CornerRadii;
-import javafx.scene.layout.Pane;
-import javafx.scene.paint.Color;
-import javafx.scene.shape.Rectangle;
-import javafx.scene.text.TextAlignment;
-
-/**
- * 
- * Vectorial UI: This class allows to create dynamic rendering with zoom and
- * move capacities
- * 
- * @author of original version (the Swing one) perles
- *
- */
-public class VUI {
-	/**
-	 * The toolbar of the VUI.
-	 */
-	public ToolBar toolbar;
-	
-	/**
-	 * The VUI explorer.
-	 * @see VuiExplorer
-	 */
-	private VuiExplorer vuiExplorer;
-	
-	/**
-	 * List of objects currently being drawn by the VUI
-	 */
-	private List<Drawable> drawables = new LinkedList<>();
-	/**
-	 * Lock to avoid concurrent modification on the list {@link #drawables}
-	 */
-	private ReentrantLock drawablesLock = new ReentrantLock();
-
-	/**
-	 * A static map to facilitate access to different instances of VUI
-	 */
-	private static Map<String, VUI> instances = new HashMap<>();
-
-	/**
-	 * The horizontal offset of the drawing zone. Used to allow the user to move the
-	 * view.
-	 */
-	private double worldOffsetX;
-
-	/**
-	 * The vertical offset of the drawing zone. Used to allow the user to move the
-	 * view.
-	 */
-	private double worldOffsetY;
-
-	/**
-	 * The last horizontal position of the mouse when dragging
-	 */
-	protected Double lastDragX;
-
-	/**
-	 * The last vertical position of the mouse when dragging
-	 */
-	protected Double lastDragY;
-
-	/**
-	 * The main panel of the VUI
-	 */
-	private BorderPane panel;
-
-	/**
-	 * The canvas on which all is drawn
-	 */
-	private Pane canvas;
-
-	/**
-	 * Label aiming at showing information about the VUI (zoom and offset)
-	 */
-	private Label statusLabel;
-
-	/**
-	 * The default value of the {@link #zoom}
-	 */
-	private double defaultZoom = 100;
-	/**
-	 * The default horizontal position of the view
-	 */
-	private double defaultWorldCenterX = 0;
-	/**
-	 * The default vertical position of the view
-	 */
-	private double defaultWorldCenterY = 0;
-	/**
-	 * The value of the zoom. 100 means 1/1 scale
-	 */
-	protected double zoom = defaultZoom;
-
-	/**
-	 * The horizontal position of the view
-	 */
-	private double worldCenterX = defaultWorldCenterX;
-
-	/**
-	 * The vertical position of the view
-	 */
-	private double worldCenterY = defaultWorldCenterY;
-
-	/**
-	 * Used to be sure that only one thread at the same time create a VUI
-	 */
-	private static ReentrantLock instanceLock = new ReentrantLock();
-
-	/**
-	 * Get the default VUI
-	 * 
-	 * @return the default VUI
-	 */
-	public static VUI get() {
-		if(!instances.containsKey("Default"))
-			MainWindow.addTabbedPanel("Default VUI", get("Default").getPanel());
-		return get("Default");
-	}
-
-	/**
-	 * Create or get a VUI.<br/>
-	 * You have add its panel to the MainWindow yourself.
-	 * 
-	 * @param id
-	 *            The unique id of the VUI
-	 * @return The VUI with id "id"
-	 */
-	public static VUI get(String id) {
-		instanceLock.lock();
-		if (!instances.containsKey(id)) {
-			VUI value = new VUI(id);
-			instances.put(id, value);
-			instanceLock.unlock();
-			return value;
-		}
-		instanceLock.unlock();
-		return instances.get(id);
-	}
-
-	/**
-	 * Constructor of the VUI. This one is private as it can only be created through
-	 * static method.
-	 * 
-	 * @param title
-	 *            The title used for the vui
-	 */
-	private VUI(String title) {
-		Semaphore done = new Semaphore(0);
-		RunLaterHelper.runLater(() -> {
-			panel = new BorderPane();
-
-			toolbar = new ToolBar();
-			statusLabel = new Label("status");
-			statusLabel.setTextAlignment(TextAlignment.LEFT);
-			toolbar.getItems().add(statusLabel);
-			panel.setBottom(toolbar);
-
-			Button resetButton = new Button("Reset");
-			resetButton.setOnAction(new EventHandler<ActionEvent>() {
-				@Override
-				public void handle(ActionEvent event) {
-					zoom = defaultZoom;
-					worldCenterX = defaultWorldCenterX;
-					worldCenterY = defaultWorldCenterY;
-					updateCanvas();
-				}
-			});
-			toolbar.getItems().add(resetButton);
-
-			canvas = new Pane();
-			canvas.setBackground(new Background(new BackgroundFill(Color.WHITE, CornerRadii.EMPTY, Insets.EMPTY)));
-			// clip the canvas (avoid drawing outside of it)
-			Rectangle clip = new Rectangle(0, 0, 0, 0);
-			clip.widthProperty().bind(canvas.widthProperty());
-			clip.heightProperty().bind(canvas.heightProperty());
-			canvas.setClip(clip);
-			
-			canvas.setOnMousePressed(new EventHandler<MouseEvent>() {
-				@Override
-				public void handle(MouseEvent event) {
-					lastDragX = event.getX();
-					lastDragY = event.getY();
-				}
-			});
-			canvas.setOnMouseExited(new EventHandler<MouseEvent>() {
-				@Override
-				public void handle(MouseEvent event) {
-					lastDragX = null;
-					lastDragY = null;
-				}
-			});
-			canvas.setOnMouseDragged(new EventHandler<MouseEvent>() {
-				@Override
-				public void handle(MouseEvent event) {
-					try {
-						double transX = screenToWorldDistance(event.getX() - lastDragX);
-						double transY = screenToWorldDistance(event.getY() - lastDragY);
-						worldCenterX += transX;
-						worldCenterY += transY;
-						worldOffsetX += transX;
-						worldOffsetY += transY;
-						lastDragX = event.getX();
-						lastDragY = event.getY();
-						updateCanvas();
-					} catch (Exception ez) {
-						// Catch exception occurring when mouse is out of the canvas
-					}
-				}
-			});
-
-			canvas.setOnScroll(new EventHandler<ScrollEvent>() {
-				@Override
-				public void handle(ScrollEvent event) {
-					double wdx = screenToWorldDistance(canvas.getWidth() / 2 - event.getX());
-					double wdy = screenToWorldDistance(canvas.getHeight() / 2 - event.getY());
-					zoom += event.getDeltaY() / event.getMultiplierY() * 10;
-					if (zoom < 10)
-						zoom = 10;
-
-					double wdx2 = screenToWorldDistance(canvas.getWidth() / 2 - event.getX());
-					double wdy2 = screenToWorldDistance(canvas.getHeight() / 2 - event.getY());
-					worldCenterX -= wdx2 - wdx;
-					worldCenterY -= wdy2 - wdy;
-					updateCanvas();
-				}
-			});
-
-			panel.setCenter(canvas);
-			
-			//add VuiExplorer
-			vuiExplorer = new VuiExplorer(this);
-			panel.setLeft(vuiExplorer);
-			Button veButton = new Button("VUI explorer");
-			veButton.setOnAction(new EventHandler<ActionEvent>() {
-				@Override
-				public void handle(ActionEvent event) {
-					panel.setLeft(vuiExplorer);
-				}
-			});
-			veButton.setTooltip(new Tooltip("Show the VUI explorer if it was hidden."));
-			toolbar.getItems().add(veButton);
-			
-			done.release();
-		});
-		try {
-			done.acquire();
-		} catch (InterruptedException e) {
-			System.err.println("Failed to make sure that the VUI is correctly initialized.");
-			e.printStackTrace();
-		}
-	}
-
-	/**
-	 * Convert a distance in the world to its equivalent on the screen
-	 * 
-	 * @param d
-	 *            the in world distance
-	 * @return the on screen distance
-	 */
-	public double worldToScreenDistance(double d) {
-		return d * getZoomFactor();
-	}
-
-	/**
-	 * Convert a distance on the screen to its equivalent in the world
-	 * 
-	 * @param d
-	 *            the on screen distance
-	 * @return the in world distance
-	 */
-	public double screenToWorldDistance(double d) {
-		return d / getZoomFactor();
-	}
-
-	/**
-	 * Convert a X in the world to its equivalent on the screen
-	 * 
-	 * @param x
-	 *            the X in world
-	 *
-	 * @return the X on screen distance
-	 */
-	public double worldToScreenX(double x) {
-		return (x + getWorldOffsetX()) * getZoomFactor();
-	}
-
-	/**
-	 * A value that must be multiplied to scale objects
-	 * 
-	 * @return the zoom factor
-	 */
-	public double getZoomFactor() {
-		return zoom / 100;
-	}
-
-	/**
-	 * Convert a Y in the world to its equivalent on the screen
-	 * 
-	 * @param y
-	 *            the Y in world
-	 *
-	 * @return the Y on screen distance
-	 */
-	public double worldToScreenY(double y) {
-		return (-y + getWorldOffsetY()) * getZoomFactor();
-	}
-
-	/**
-	 * Convert a X on the screen to its equivalent in the world
-	 * 
-	 * @param x
-	 *            the X on screen
-	 *
-	 * @return the X in the world distance
-	 */
-	public double screenToWorldX(double x) {
-		return x / getZoomFactor() - getWorldOffsetX();
-	}
-
-	/**
-	 * Convert a Y on the screen to its equivalent in the world
-	 * 
-	 * @param y
-	 *            the Y on screen
-	 *
-	 * @return the Y in the world distance
-	 */
-	public double screenToWorldY(double y) {
-		return -y / getZoomFactor() + getWorldOffsetY();
-	}
-
-	/**
-	 * Add a drawable to the VUI.
-	 * 
-	 * @param d
-	 *            the new drawable
-	 */
-	public void add(Drawable d) {
-		d.setVUI(this);
-		RunLaterHelper.runLater(()-> canvas.getChildren().add(d.getNode()));
-		drawablesLock.lock();
-		drawables.add(d);
-		drawablesLock.unlock();
-		updateCanvas();
-	}
-	
-	/**
-	 * Remove a drawable from the VUI.
-	 * 
-	 * @param d
-	 *            the new drawable
-	 */
-	public void remove(Drawable d) {
-		drawablesLock.lock();
-		drawables.remove(d);
-		drawablesLock.unlock();
-		RunLaterHelper.runLater(()-> canvas.getChildren().remove(d.getNode()));
-		updateCanvas();
-	}
-	
-	/**
-	 * Remove all drawables from the VUI.
-	 */
-	public void clear() {
-		drawablesLock.lock();
-		drawables.clear();
-		RunLaterHelper.runLater(()->canvas.getChildren().clear());
-		drawablesLock.unlock();
-	}
-
-	/**
-	 * Refresh the canvas
-	 */
-	public void updateCanvas() {
-		final double w = canvas.getWidth();
-		final double h = canvas.getHeight();
-
-		setWorldOffsetX(worldCenterX + screenToWorldDistance(w / 2));
-		setWorldOffsetY(worldCenterY + screenToWorldDistance(h / 2));
-
-		drawablesLock.lock();
-		Collections.sort(drawables, (o1, o2) -> o1.getLayer() - o2.getLayer());
-		for (Drawable d : drawables)
-			RunLaterHelper.runLater(()-> d.onDraw());
-		drawablesLock.unlock();
-
-		RunLaterHelper.runLater(() -> {
-			statusLabel.setText(String.format("Zoom: %.2f Center: (%.2f,%.2f)", zoom, worldCenterX, worldCenterY));
-		});
-		
-		RunLaterHelper.runLater(()-> vuiExplorer.update(true));
-	}
-
-	/**
-	 * Get the width of the canvas
-	 * 
-	 * @return the canvas width
-	 */
-	public double getCanvasWidth() {
-		return canvas.getWidth();
-	}
-
-	/**
-	 * Get the height of the canvas
-	 * 
-	 * @return the canvas height
-	 */
-	public double getCanvasHeight() {
-		return canvas.getHeight();
-	}
-
-	/**
-	 * Get the value that must be added to the X coordinate of in world object
-	 * 
-	 * @return the X offset
-	 */
-	public double getWorldOffsetX() {
-		return worldOffsetX;
-	}
-
-	/**
-	 * Set the value that must be added to the X coordinate of in world object
-	 * 
-	 * @param offsetX
-	 *            the X offset
-	 */
-	public void setWorldOffsetX(double offsetX) {
-		this.worldOffsetX = offsetX;
-	}
-
-	/**
-	 * Get the value that must be added to the Y coordinate of in world object
-	 * 
-	 * @return the Y offset
-	 */
-	public double getWorldOffsetY() {
-		return worldOffsetY;
-	}
-
-	/**
-	 * Set the value that must be added to the Y coordinate of in world object
-	 * 
-	 * @param offsetY
-	 *            the Y offset
-	 */
-	public void setWorldOffsetY(double offsetY) {
-		this.worldOffsetY = offsetY;
-	}
-
-	/**
-	 * Create a point and start rendering it
-	 * 
-	 * @param dx
-	 *            the x coordinate
-	 * @param dy
-	 *            the y coordinate
-	 * @return the point object
-	 */
-	public DrawablePoint createAndAddPoint(double dx, double dy) {
-		DrawablePoint drawablePoint = new DrawablePoint(dx, dy);
-		add(drawablePoint);
-		return drawablePoint;
-	}
-
-	/**
-	 * Create a rectangle and start rendering it
-	 * 
-	 * @param x
-	 *            the x coordinate
-	 * @param y
-	 *            the y coordinate
-	 * @param w
-	 *            the width
-	 * @param h
-	 *            the height
-	 * @return the rectangle object
-	 */
-	public DrawableRectangle createAndAddRectangle(double x, double y, double w, double h) {
-		DrawableRectangle d = new DrawableRectangle(x, y, w, h);
-		add(d);
-		return d;
-	}
-
-	/**
-	 * Set the default configuration of the view
-	 * 
-	 * @param zoom
-	 *            the initial zoom value
-	 * @param worldCenterX
-	 *            the initial X center value
-	 * @param worldCenterY
-	 *            the initial Y center value
-	 */
-	public void setDefaultView(double zoom, double worldCenterX, double worldCenterY) {
-		this.zoom = zoom;
-		this.worldCenterX = worldCenterX;
-		this.worldCenterY = worldCenterY;
-		this.defaultZoom = zoom;
-		this.defaultWorldCenterX = worldCenterX;
-		this.defaultWorldCenterY = worldCenterY;
-	}
-
-	/**
-	 * Create an image and start rendering it
-	 * 
-	 * @param dx
-	 *            the x coordinate
-	 * @param dy
-	 *            the y coordinate
-	 * @param filename
-	 *            the filename of the image
-	 * @return the created image
-	 */
-	public DrawableImage createAndAddImage(double dx, double dy, String filename) {
-		DrawableImage image = new DrawableImage(dx, dy, filename);
-		add(image);
-		return image;
-	}
-
-	/**
-	 * Create a string and start rendering it
-	 * 
-	 * @param dx
-	 *            the x coordinate
-	 * @param dy
-	 *            the y coordinate
-	 * @param text
-	 *            the text to display
-	 * @return the created string
-	 */
-	public DrawableString createAndAddString(int dx, int dy, String text) {
-		DrawableString ds = new DrawableString(dx, dy, text);
-		add(ds);
-		return ds;
-	}
-
-	public Pane getCanvas() {
-		return canvas;
-	}
-	
-	public BorderPane getPanel() {
-		return panel;
-	}
-	
-	public List<Drawable> getDrawables() {
-		return drawables;
-	}
-}
+package fr.irit.smac.amak.ui;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.locks.ReentrantLock;
+
+import fr.irit.smac.amak.tools.RunLaterHelper;
+import fr.irit.smac.amak.ui.drawables.Drawable;
+import fr.irit.smac.amak.ui.drawables.DrawableImage;
+import fr.irit.smac.amak.ui.drawables.DrawablePoint;
+import fr.irit.smac.amak.ui.drawables.DrawableRectangle;
+import fr.irit.smac.amak.ui.drawables.DrawableString;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.geometry.Insets;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.ToolBar;
+import javafx.scene.control.Tooltip;
+import javafx.scene.input.MouseEvent;
+import javafx.scene.input.ScrollEvent;
+import javafx.scene.layout.Background;
+import javafx.scene.layout.BackgroundFill;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.CornerRadii;
+import javafx.scene.layout.Pane;
+import javafx.scene.paint.Color;
+import javafx.scene.shape.Rectangle;
+import javafx.scene.text.TextAlignment;
+
+/**
+ * 
+ * Vectorial UI: This class allows to create dynamic rendering with zoom and
+ * move capacities
+ * 
+ * @author of original version (the Swing one) perles
+ *
+ */
+public class VUI {
+	/**
+	 * The toolbar of the VUI.
+	 */
+	public ToolBar toolbar;
+	
+	/**
+	 * The VUI explorer.
+	 * @see VuiExplorer
+	 */
+	private VuiExplorer vuiExplorer;
+	
+	/**
+	 * List of objects currently being drawn by the VUI
+	 */
+	private List<Drawable> drawables = new LinkedList<>();
+	/**
+	 * Lock to avoid concurrent modification on the list {@link #drawables}
+	 */
+	private ReentrantLock drawablesLock = new ReentrantLock();
+
+	/**
+	 * A static map to facilitate access to different instances of VUI
+	 */
+	private static Map<String, VUI> instances = new HashMap<>();
+
+	/**
+	 * The horizontal offset of the drawing zone. Used to allow the user to move the
+	 * view.
+	 */
+	private double worldOffsetX;
+
+	/**
+	 * The vertical offset of the drawing zone. Used to allow the user to move the
+	 * view.
+	 */
+	private double worldOffsetY;
+
+	/**
+	 * The last horizontal position of the mouse when dragging
+	 */
+	protected Double lastDragX;
+
+	/**
+	 * The last vertical position of the mouse when dragging
+	 */
+	protected Double lastDragY;
+
+	/**
+	 * The main panel of the VUI
+	 */
+	private BorderPane panel;
+
+	/**
+	 * The canvas on which all is drawn
+	 */
+	private Pane canvas;
+
+	/**
+	 * Label aiming at showing information about the VUI (zoom and offset)
+	 */
+	private Label statusLabel;
+
+	/**
+	 * The default value of the {@link #zoom}
+	 */
+	private double defaultZoom = 100;
+	/**
+	 * The default horizontal position of the view
+	 */
+	private double defaultWorldCenterX = 0;
+	/**
+	 * The default vertical position of the view
+	 */
+	private double defaultWorldCenterY = 0;
+	/**
+	 * The value of the zoom. 100 means 1/1 scale
+	 */
+	protected double zoom = defaultZoom;
+
+	/**
+	 * The horizontal position of the view
+	 */
+	private double worldCenterX = defaultWorldCenterX;
+
+	/**
+	 * The vertical position of the view
+	 */
+	private double worldCenterY = defaultWorldCenterY;
+
+	/**
+	 * Used to be sure that only one thread at the same time create a VUI
+	 */
+	private static ReentrantLock instanceLock = new ReentrantLock();
+
+	/**
+	 * Get the default VUI
+	 * 
+	 * @return the default VUI
+	 */
+	public static VUI get() {
+		if(!instances.containsKey("Default"))
+			MainWindow.addTabbedPanel("Default VUI", get("Default").getPanel());
+		return get("Default");
+	}
+	
+	public static VUI get(AmasMultiUIWindow window) {
+		if(!instances.containsKey("Default")) {
+			System.out.println(window + "            ------------- VUI 151");
+			System.out.println(get("Default"));
+			System.out.println(get("Default").getPanel());
+			window.addTabbedPanel("Default VUI", get("Default").getPanel());
+		}
+			
+		return get("Default");
+	}
+
+	/**
+	 * Create or get a VUI.<br/>
+	 * You have add its panel to the MainWindow yourself.
+	 * 
+	 * @param id
+	 *            The unique id of the VUI
+	 * @return The VUI with id "id"
+	 */
+	public static VUI get(String id) {
+		instanceLock.lock();
+		if (!instances.containsKey(id)) {
+			VUI value = new VUI(id);
+			instances.put(id, value);
+			instanceLock.unlock();
+			return value;
+		}
+		instanceLock.unlock();
+		return instances.get(id);
+	}
+
+	/**
+	 * Constructor of the VUI. This one is private as it can only be created through
+	 * static method.
+	 * 
+	 * @param title
+	 *            The title used for the vui
+	 */
+	private VUI(String title) {
+		Semaphore done = new Semaphore(0);
+		RunLaterHelper.runLater(() -> {
+			panel = new BorderPane();
+
+			toolbar = new ToolBar();
+			statusLabel = new Label("status");
+			statusLabel.setTextAlignment(TextAlignment.LEFT);
+			toolbar.getItems().add(statusLabel);
+			panel.setBottom(toolbar);
+
+			Button resetButton = new Button("Reset");
+			resetButton.setOnAction(new EventHandler<ActionEvent>() {
+				@Override
+				public void handle(ActionEvent event) {
+					zoom = defaultZoom;
+					worldCenterX = defaultWorldCenterX;
+					worldCenterY = defaultWorldCenterY;
+					updateCanvas();
+				}
+			});
+			toolbar.getItems().add(resetButton);
+
+			canvas = new Pane();
+			canvas.setBackground(new Background(new BackgroundFill(Color.WHITE, CornerRadii.EMPTY, Insets.EMPTY)));
+			// clip the canvas (avoid drawing outside of it)
+			Rectangle clip = new Rectangle(0, 0, 0, 0);
+			clip.widthProperty().bind(canvas.widthProperty());
+			clip.heightProperty().bind(canvas.heightProperty());
+			canvas.setClip(clip);
+			
+			canvas.setOnMousePressed(new EventHandler<MouseEvent>() {
+				@Override
+				public void handle(MouseEvent event) {
+					lastDragX = event.getX();
+					lastDragY = event.getY();
+				}
+			});
+			canvas.setOnMouseExited(new EventHandler<MouseEvent>() {
+				@Override
+				public void handle(MouseEvent event) {
+					lastDragX = null;
+					lastDragY = null;
+				}
+			});
+			canvas.setOnMouseDragged(new EventHandler<MouseEvent>() {
+				@Override
+				public void handle(MouseEvent event) {
+					try {
+						double transX = screenToWorldDistance(event.getX() - lastDragX);
+						double transY = screenToWorldDistance(event.getY() - lastDragY);
+						worldCenterX += transX;
+						worldCenterY += transY;
+						worldOffsetX += transX;
+						worldOffsetY += transY;
+						lastDragX = event.getX();
+						lastDragY = event.getY();
+						updateCanvas();
+					} catch (Exception ez) {
+						// Catch exception occurring when mouse is out of the canvas
+					}
+				}
+			});
+
+			canvas.setOnScroll(new EventHandler<ScrollEvent>() {
+				@Override
+				public void handle(ScrollEvent event) {
+					double wdx = screenToWorldDistance(canvas.getWidth() / 2 - event.getX());
+					double wdy = screenToWorldDistance(canvas.getHeight() / 2 - event.getY());
+					zoom += event.getDeltaY() / event.getMultiplierY() * 10;
+					if (zoom < 10)
+						zoom = 10;
+
+					double wdx2 = screenToWorldDistance(canvas.getWidth() / 2 - event.getX());
+					double wdy2 = screenToWorldDistance(canvas.getHeight() / 2 - event.getY());
+					worldCenterX -= wdx2 - wdx;
+					worldCenterY -= wdy2 - wdy;
+					updateCanvas();
+				}
+			});
+
+			panel.setCenter(canvas);
+			
+			//add VuiExplorer
+			vuiExplorer = new VuiExplorer(this);
+			panel.setLeft(vuiExplorer);
+			Button veButton = new Button("VUI explorer");
+			veButton.setOnAction(new EventHandler<ActionEvent>() {
+				@Override
+				public void handle(ActionEvent event) {
+					panel.setLeft(vuiExplorer);
+				}
+			});
+			veButton.setTooltip(new Tooltip("Show the VUI explorer if it was hidden."));
+			toolbar.getItems().add(veButton);
+			
+			done.release();
+		});
+		try {
+			done.acquire();
+		} catch (InterruptedException e) {
+			System.err.println("Failed to make sure that the VUI is correctly initialized.");
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * Convert a distance in the world to its equivalent on the screen
+	 * 
+	 * @param d
+	 *            the in world distance
+	 * @return the on screen distance
+	 */
+	public double worldToScreenDistance(double d) {
+		return d * getZoomFactor();
+	}
+
+	/**
+	 * Convert a distance on the screen to its equivalent in the world
+	 * 
+	 * @param d
+	 *            the on screen distance
+	 * @return the in world distance
+	 */
+	public double screenToWorldDistance(double d) {
+		return d / getZoomFactor();
+	}
+
+	/**
+	 * Convert a X in the world to its equivalent on the screen
+	 * 
+	 * @param x
+	 *            the X in world
+	 *
+	 * @return the X on screen distance
+	 */
+	public double worldToScreenX(double x) {
+		return (x + getWorldOffsetX()) * getZoomFactor();
+	}
+
+	/**
+	 * A value that must be multiplied to scale objects
+	 * 
+	 * @return the zoom factor
+	 */
+	public double getZoomFactor() {
+		return zoom / 100;
+	}
+
+	/**
+	 * Convert a Y in the world to its equivalent on the screen
+	 * 
+	 * @param y
+	 *            the Y in world
+	 *
+	 * @return the Y on screen distance
+	 */
+	public double worldToScreenY(double y) {
+		return (-y + getWorldOffsetY()) * getZoomFactor();
+	}
+
+	/**
+	 * Convert a X on the screen to its equivalent in the world
+	 * 
+	 * @param x
+	 *            the X on screen
+	 *
+	 * @return the X in the world distance
+	 */
+	public double screenToWorldX(double x) {
+		return x / getZoomFactor() - getWorldOffsetX();
+	}
+
+	/**
+	 * Convert a Y on the screen to its equivalent in the world
+	 * 
+	 * @param y
+	 *            the Y on screen
+	 *
+	 * @return the Y in the world distance
+	 */
+	public double screenToWorldY(double y) {
+		return -y / getZoomFactor() + getWorldOffsetY();
+	}
+
+	/**
+	 * Add a drawable to the VUI.
+	 * 
+	 * @param d
+	 *            the new drawable
+	 */
+	public void add(Drawable d) {
+		d.setVUI(this);
+		RunLaterHelper.runLater(()-> canvas.getChildren().add(d.getNode()));
+		drawablesLock.lock();
+		drawables.add(d);
+		drawablesLock.unlock();
+		updateCanvas();
+	}
+	
+	/**
+	 * Remove a drawable from the VUI.
+	 * 
+	 * @param d
+	 *            the new drawable
+	 */
+	public void remove(Drawable d) {
+		drawablesLock.lock();
+		drawables.remove(d);
+		drawablesLock.unlock();
+		RunLaterHelper.runLater(()-> canvas.getChildren().remove(d.getNode()));
+		updateCanvas();
+	}
+	
+	/**
+	 * Remove all drawables from the VUI.
+	 */
+	public void clear() {
+		drawablesLock.lock();
+		drawables.clear();
+		RunLaterHelper.runLater(()->canvas.getChildren().clear());
+		drawablesLock.unlock();
+	}
+
+	/**
+	 * Refresh the canvas
+	 */
+	public void updateCanvas() {
+		final double w = canvas.getWidth();
+		final double h = canvas.getHeight();
+
+		setWorldOffsetX(worldCenterX + screenToWorldDistance(w / 2));
+		setWorldOffsetY(worldCenterY + screenToWorldDistance(h / 2));
+
+		drawablesLock.lock();
+		Collections.sort(drawables, (o1, o2) -> o1.getLayer() - o2.getLayer());
+		for (Drawable d : drawables)
+			RunLaterHelper.runLater(()-> d.onDraw());
+		drawablesLock.unlock();
+
+		RunLaterHelper.runLater(() -> {
+			statusLabel.setText(String.format("Zoom: %.2f Center: (%.2f,%.2f)", zoom, worldCenterX, worldCenterY));
+		});
+		
+		RunLaterHelper.runLater(()-> vuiExplorer.update(true));
+	}
+
+	/**
+	 * Get the width of the canvas
+	 * 
+	 * @return the canvas width
+	 */
+	public double getCanvasWidth() {
+		return canvas.getWidth();
+	}
+
+	/**
+	 * Get the height of the canvas
+	 * 
+	 * @return the canvas height
+	 */
+	public double getCanvasHeight() {
+		return canvas.getHeight();
+	}
+
+	/**
+	 * Get the value that must be added to the X coordinate of in world object
+	 * 
+	 * @return the X offset
+	 */
+	public double getWorldOffsetX() {
+		return worldOffsetX;
+	}
+
+	/**
+	 * Set the value that must be added to the X coordinate of in world object
+	 * 
+	 * @param offsetX
+	 *            the X offset
+	 */
+	public void setWorldOffsetX(double offsetX) {
+		this.worldOffsetX = offsetX;
+	}
+
+	/**
+	 * Get the value that must be added to the Y coordinate of in world object
+	 * 
+	 * @return the Y offset
+	 */
+	public double getWorldOffsetY() {
+		return worldOffsetY;
+	}
+
+	/**
+	 * Set the value that must be added to the Y coordinate of in world object
+	 * 
+	 * @param offsetY
+	 *            the Y offset
+	 */
+	public void setWorldOffsetY(double offsetY) {
+		this.worldOffsetY = offsetY;
+	}
+
+	/**
+	 * Create a point and start rendering it
+	 * 
+	 * @param dx
+	 *            the x coordinate
+	 * @param dy
+	 *            the y coordinate
+	 * @return the point object
+	 */
+	public DrawablePoint createAndAddPoint(double dx, double dy) {
+		DrawablePoint drawablePoint = new DrawablePoint(dx, dy);
+		add(drawablePoint);
+		return drawablePoint;
+	}
+
+	/**
+	 * Create a rectangle and start rendering it
+	 * 
+	 * @param x
+	 *            the x coordinate
+	 * @param y
+	 *            the y coordinate
+	 * @param w
+	 *            the width
+	 * @param h
+	 *            the height
+	 * @return the rectangle object
+	 */
+	public DrawableRectangle createAndAddRectangle(double x, double y, double w, double h) {
+		DrawableRectangle d = new DrawableRectangle(x, y, w, h);
+		add(d);
+		return d;
+	}
+
+	/**
+	 * Set the default configuration of the view
+	 * 
+	 * @param zoom
+	 *            the initial zoom value
+	 * @param worldCenterX
+	 *            the initial X center value
+	 * @param worldCenterY
+	 *            the initial Y center value
+	 */
+	public void setDefaultView(double zoom, double worldCenterX, double worldCenterY) {
+		this.zoom = zoom;
+		this.worldCenterX = worldCenterX;
+		this.worldCenterY = worldCenterY;
+		this.defaultZoom = zoom;
+		this.defaultWorldCenterX = worldCenterX;
+		this.defaultWorldCenterY = worldCenterY;
+	}
+
+	/**
+	 * Create an image and start rendering it
+	 * 
+	 * @param dx
+	 *            the x coordinate
+	 * @param dy
+	 *            the y coordinate
+	 * @param filename
+	 *            the filename of the image
+	 * @return the created image
+	 */
+	public DrawableImage createAndAddImage(double dx, double dy, String filename) {
+		DrawableImage image = new DrawableImage(dx, dy, filename);
+		add(image);
+		return image;
+	}
+
+	/**
+	 * Create a string and start rendering it
+	 * 
+	 * @param dx
+	 *            the x coordinate
+	 * @param dy
+	 *            the y coordinate
+	 * @param text
+	 *            the text to display
+	 * @return the created string
+	 */
+	public DrawableString createAndAddString(int dx, int dy, String text) {
+		DrawableString ds = new DrawableString(dx, dy, text);
+		add(ds);
+		return ds;
+	}
+
+	public Pane getCanvas() {
+		return canvas;
+	}
+	
+	public BorderPane getPanel() {
+		return panel;
+	}
+	
+	public List<Drawable> getDrawables() {
+		return drawables;
+	}
+}