From 3b51778029709b5336473a4a6a5b00e6cba90aa5 Mon Sep 17 00:00:00 2001
From: BrunoDatoMeneses <bruno.dato.meneses@gmail.com>
Date: Thu, 19 Sep 2019 09:47:16 +0200
Subject: [PATCH] DEL: to delete

---
 .../src/agents/AmoebaAgentMultiUI.java        | 111 +++
 AMOEBAonAMAK/src/gui/ContextRendererFX.java   |  11 +-
 .../src/gui/ContextRendererFXMultiUI.java     |  92 +++
 AMOEBAonAMAK/src/gui/NoneRenderer.java        |   2 +-
 AMOEBAonAMAK/src/gui/RenderStrategy.java      |   3 +-
 .../src/gui/RenderStrategyMutlUI.java         |  34 +
 AMOEBAonAMAK/src/kernel/AMOEBA.java           |  66 +-
 AMOEBAonAMAK/src/kernel/AMOEBAMultiUI.java    | 770 ++++++++++++++++++
 8 files changed, 1043 insertions(+), 46 deletions(-)
 create mode 100644 AMOEBAonAMAK/src/agents/AmoebaAgentMultiUI.java
 create mode 100644 AMOEBAonAMAK/src/gui/ContextRendererFXMultiUI.java
 create mode 100644 AMOEBAonAMAK/src/gui/RenderStrategyMutlUI.java
 create mode 100644 AMOEBAonAMAK/src/kernel/AMOEBAMultiUI.java

diff --git a/AMOEBAonAMAK/src/agents/AmoebaAgentMultiUI.java b/AMOEBAonAMAK/src/agents/AmoebaAgentMultiUI.java
new file mode 100644
index 00000000..9c8516fc
--- /dev/null
+++ b/AMOEBAonAMAK/src/agents/AmoebaAgentMultiUI.java
@@ -0,0 +1,111 @@
+package agents;
+
+import agents.percept.Percept;
+import fr.irit.smac.amak.Agent;
+import fr.irit.smac.amak.tools.Loggable;
+import gui.RenderStrategy;
+import gui.RenderStrategyMutlUI;
+import kernel.AMOEBA;
+import kernel.World;
+
+/**
+ * The base class for all AMOEBA agents
+ */
+public abstract class AmoebaAgentMultiUI extends Agent<AMOEBA, World> implements Loggable {
+	// Attributes
+	protected String name;
+	private boolean dying;
+	
+	protected RenderStrategyMutlUI renderStrategy;
+
+	/**
+	 * Instantiate a new agent attached to an amoeba
+	 * @param the amoeba
+	 */
+	public AmoebaAgentMultiUI(AMOEBA amas, Object... params) {
+		super(amas, params);
+		this.dying = false;
+	}
+	
+	@Override
+	protected void onReady() {
+		super.onReady();
+		logger().debug("CYCLE "+getAmas().getCycle(), "Agent %s ready.", toString());
+	}
+
+	@Override
+	protected void onDecide() {
+	}
+
+	@Override
+	protected void onRenderingInitialization() {
+		if(renderStrategy != null) {
+			renderStrategy.initialize(getAmas().getVUIMulti());
+			
+		}
+	}
+	
+	@Override
+	public void onUpdateRender() {
+		amas.getEnvironment().incrementNbActivatedAgent();
+		if(renderStrategy != null && !isDying()) {
+			if (amas.isRenderUpdate()) {
+				renderStrategy.render();
+			}
+		}
+	}
+
+	/**
+	 * Set the name of the agent. Useful for visualization, and essential for {@link Percept}.
+	 * @param name
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+	@Override
+	public void destroy() {
+		dying = true;
+		if(renderStrategy != null) {
+			renderStrategy.delete();
+		}
+		super.destroy();
+		logger().debug("CYCLE "+getAmas().getCycle(), "Agent %s destroyed.", toString());
+	}
+
+	/**
+	 * Get the name of the agent. Useful for visualization, and essential for {@link Percept}.
+	 * @param name
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * Tell if the agent is dying. A dying agent no longer perform any useful action, but is not yet removed from its system.
+	 * @return
+	 */
+	public boolean isDying() {
+		return dying;
+	}
+	
+	/**
+	 * Set the render strategy of an agent.<br/>
+	 * {@link RenderStrategy#delete()} the old one, and {@link RenderStrategy#initialize()} the new one.
+	 * @param renderStrategy
+	 * @see RenderStrategy
+	 */
+	public void setRenderStrategy(RenderStrategyMutlUI renderStrategy) {
+		if(this.renderStrategy != null) this.renderStrategy.delete();
+		this.renderStrategy = renderStrategy;
+		if(this.renderStrategy != null) this.renderStrategy.initialize(getAmas().getVUIMulti());
+	}
+	
+	/**
+	 * Get the render strategy of an agent.
+	 * @return
+	 */
+	public RenderStrategyMutlUI getRenderStrategy() {
+		return renderStrategy;
+	}
+}
diff --git a/AMOEBAonAMAK/src/gui/ContextRendererFX.java b/AMOEBAonAMAK/src/gui/ContextRendererFX.java
index cd484386..6faa3717 100644
--- a/AMOEBAonAMAK/src/gui/ContextRendererFX.java
+++ b/AMOEBAonAMAK/src/gui/ContextRendererFX.java
@@ -2,7 +2,6 @@ package gui;
 
 import agents.context.Context;
 import agents.percept.Percept;
-import fr.irit.smac.amak.ui.VUIMulti;
 import fr.irit.smac.amak.ui.drawables.DrawableRectangle;
 import gui.utils.ContextColor;
 import javafx.scene.paint.Color;
@@ -65,8 +64,8 @@ public class ContextRendererFX extends RenderStrategy {
 	 * window.
 	 */
 	@Override
-	public void initialize(VUIMulti vui) {
-		getDrawable(vui).setName(context.toString()); // create the drawable if it does not exist
+	public void initialize() {
+		getDrawable().setName(context.toString()); // create the drawable if it does not exist
 
 	}
 
@@ -82,11 +81,11 @@ public class ContextRendererFX extends RenderStrategy {
 	 * 
 	 * @return
 	 */
-	public DrawableRectangle getDrawable(VUIMulti vui) {
+	public DrawableRectangle getDrawable() {
 		if (!context.isDying() && drawable == null) {
 			drawable = new DrawableContext(0, 0, 0, 0, context);
-			vui.add(drawable);
+			AmoebaWindow.instance().mainVUI.add(drawable);
 		}
 		return drawable;
 	}
-}
+}
\ No newline at end of file
diff --git a/AMOEBAonAMAK/src/gui/ContextRendererFXMultiUI.java b/AMOEBAonAMAK/src/gui/ContextRendererFXMultiUI.java
new file mode 100644
index 00000000..29cbd994
--- /dev/null
+++ b/AMOEBAonAMAK/src/gui/ContextRendererFXMultiUI.java
@@ -0,0 +1,92 @@
+package gui;
+
+import agents.context.Context;
+import agents.percept.Percept;
+import fr.irit.smac.amak.ui.VUIMulti;
+import fr.irit.smac.amak.ui.drawables.DrawableRectangle;
+import gui.utils.ContextColor;
+import javafx.scene.paint.Color;
+
+/**
+ * A render strategy for contexts using AMAKFX tools.<br/>
+ * A Context is represented by a {@link DrawableRectangle} drawn onto {@link AmoebaWindow#mainVUI}.
+ * 
+ * @author Hugo
+ *
+ */
+public class ContextRendererFXMultiUI extends RenderStrategyMutlUI {
+
+	private Context context;
+
+	private DrawableContext drawable;
+
+	public ContextRendererFXMultiUI(Object o) {
+		this((Context) o);
+	}
+
+	/**
+	 * @param context the context to be rendered.
+	 */
+	public ContextRendererFXMultiUI(Context context) {
+		super(context);
+		this.context = context;
+	}
+
+	@Override
+	public void render() {
+		updatePosition();
+		updateColor();
+		drawable.setName(context.toString());
+		drawable.setInfo(context.toStringFull());
+	}
+
+	private void updateColor() {
+		Double[] c = ContextColor.colorFromCoefs(context.getFunction().getCoef());
+		drawable.setColor(new Color(c[0], c[1], c[2], 90d / 255d));
+	}
+	
+	public String getColorForUnity() {
+		Double[] c = ContextColor.colorFromCoefs(context.getFunction().getCoef());
+		 return c[0].intValue() + "," + c[1].intValue() + "," + c[2].intValue() + ",100";
+	}
+
+	private void updatePosition() {
+		Percept p1 = context.getAmas().getDimensionSelector().d1();
+		Percept p2 = context.getAmas().getDimensionSelector().d2();
+		double x = context.getRanges().get(p1).getStart();
+		double y = context.getRanges().get(p2).getStart();
+		drawable.setWidth(context.getRanges().get(p1).getLenght());
+		drawable.setHeight(context.getRanges().get(p2).getLenght());
+		drawable.move(x, y);
+	}
+
+	/**
+	 * Initialize the drawable.
+	 * window.
+	 */
+	@Override
+	public void initialize(VUIMulti vui) {
+		getDrawable(vui).setName(context.toString()); // create the drawable if it does not exist
+
+	}
+
+	@Override
+	public void delete() {
+		if (drawable != null)
+			drawable.delete();
+	}
+
+
+	/**
+	 * Return the visualization for the VUI, may create and add it to the VUI.
+	 * 
+	 * @return
+	 */
+	public DrawableRectangle getDrawable(VUIMulti vui) {
+		if (!context.isDying() && drawable == null) {
+			drawable = new DrawableContext(0, 0, 0, 0, context);
+			vui.add(drawable);
+		}
+		return drawable;
+	}
+}
diff --git a/AMOEBAonAMAK/src/gui/NoneRenderer.java b/AMOEBAonAMAK/src/gui/NoneRenderer.java
index 438a9809..e78259dd 100644
--- a/AMOEBAonAMAK/src/gui/NoneRenderer.java
+++ b/AMOEBAonAMAK/src/gui/NoneRenderer.java
@@ -14,7 +14,7 @@ public class NoneRenderer extends RenderStrategy {
 	}
 
 	@Override
-	public void initialize(VUIMulti vui) {
+	public void initialize() {
 	}
 
 	@Override
diff --git a/AMOEBAonAMAK/src/gui/RenderStrategy.java b/AMOEBAonAMAK/src/gui/RenderStrategy.java
index 7552c951..8cb1dd9d 100644
--- a/AMOEBAonAMAK/src/gui/RenderStrategy.java
+++ b/AMOEBAonAMAK/src/gui/RenderStrategy.java
@@ -18,8 +18,7 @@ public abstract class RenderStrategy {
 	/**
 	 * Called when the rendered object need to be initialized
 	 */
-	//abstract public void initialize();
-	abstract public void initialize(VUIMulti vui);
+	abstract public void initialize();
 	
 	/**
 	 * Called to render the object.
diff --git a/AMOEBAonAMAK/src/gui/RenderStrategyMutlUI.java b/AMOEBAonAMAK/src/gui/RenderStrategyMutlUI.java
new file mode 100644
index 00000000..1d7bd9e3
--- /dev/null
+++ b/AMOEBAonAMAK/src/gui/RenderStrategyMutlUI.java
@@ -0,0 +1,34 @@
+package gui;
+
+import fr.irit.smac.amak.ui.VUIMulti;
+
+/**
+ * Strategy on how to render an object.
+ * See {@link ContextRendererFX} for example on how to extends this class.
+ * @author Hugo
+ */
+public abstract class RenderStrategyMutlUI {
+	
+	/**
+	 * @param o the object to be rendered
+	 */
+	public RenderStrategyMutlUI(Object o) {
+	}
+	
+	/**
+	 * Called when the rendered object need to be initialized
+	 */
+	//abstract public void initialize();
+	abstract public void initialize(VUIMulti vui);
+	
+	/**
+	 * Called to render the object.
+	 */
+	abstract public void render();
+	
+	/**
+	 * Called when the render of the object is no longer needed.
+	 */
+	abstract public void delete();
+
+}
diff --git a/AMOEBAonAMAK/src/kernel/AMOEBA.java b/AMOEBAonAMAK/src/kernel/AMOEBA.java
index bf1b2c62..70eb7ac7 100644
--- a/AMOEBAonAMAK/src/kernel/AMOEBA.java
+++ b/AMOEBAonAMAK/src/kernel/AMOEBA.java
@@ -23,8 +23,6 @@ import fr.irit.smac.amak.Scheduling;
 import fr.irit.smac.amak.tools.Log;
 import fr.irit.smac.amak.tools.RunLaterHelper;
 import fr.irit.smac.amak.ui.AmakPlot;
-import fr.irit.smac.amak.ui.VUIMulti;
-import gui.AmoebaMultiUIWindow;
 import gui.AmoebaWindow;
 import gui.DimensionSelector;
 import kernel.backup.IBackupSystem;
@@ -40,9 +38,6 @@ import utils.PrintOnce;
  */
 public class AMOEBA extends Amas<World> implements IAMOEBA {
 	// -- Attributes
-	
-	
-	public VUIMulti vuiMulti;
 	/**
 	 * Utility to save, autosave, and load amoebas.
 	 */
@@ -53,8 +48,6 @@ public class AMOEBA extends Amas<World> implements IAMOEBA {
 	 */
 	public StudiedSystem studiedSystem;
 	
-	public AmoebaMultiUIWindow multiUIWindow;
-	
 	private Head head;
 	private TypeLocalModel localModel = TypeLocalModel.MILLER_REGRESSION;
 	private HashMap<String, Double> perceptions = new HashMap<String, Double>();
@@ -89,9 +82,8 @@ public class AMOEBA extends Amas<World> implements IAMOEBA {
 	 * @param studiedSystem
 	 *            the studied system
 	 */
-	public AMOEBA(AmoebaMultiUIWindow window, VUIMulti vui) {
-		super(window, vui, new World(), Scheduling.HIDDEN);
-		vuiMulti = vui;
+	public AMOEBA() {
+		super(new World(), Scheduling.HIDDEN);
 	}
 	
 	/**
@@ -99,9 +91,8 @@ public class AMOEBA extends Amas<World> implements IAMOEBA {
 	 * 
 	 * @param path path to the config file.
 	 */
-	public AMOEBA(AmoebaMultiUIWindow window, VUIMulti vui, String path, StudiedSystem studiedSystem) {
-		super(window, vui, new World(), Scheduling.HIDDEN);
-		vuiMulti = vui;
+	public AMOEBA(String path, StudiedSystem studiedSystem) {
+		super(new World(), Scheduling.HIDDEN);
 		this.studiedSystem = studiedSystem;
 		setRenderUpdate(true);
 		saver = new SaveHelperImpl(this);
@@ -121,22 +112,23 @@ public class AMOEBA extends Amas<World> implements IAMOEBA {
 	
 	@Override
 	protected void onRenderingInitialization() {
-		((AmoebaMultiUIWindow) amasMultiUIWindow).initialize(this);
+		AmoebaWindow.instance().initialize(this);
 	}
 
 	@Override
 	protected void onUpdateRender() {
 		// Update statistics
-		if(amasMultiUIWindow!=null) {
-
-			AmakPlot loopNCS = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("This loop NCS");
-			AmakPlot allNCS = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("All time NCS");
-			AmakPlot nbAgent = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Number of agents");
-			AmakPlot errors = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Errors");
-			AmakPlot distancesToModels = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Distances to models");
-			AmakPlot gloabalMappingCriticality = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Global Mapping Criticality");
-			AmakPlot timeExecution = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Time Execution");
-			AmakPlot criticalities = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Criticalities");
+		if(AmoebaWindow.isInstance()) {
+			AmoebaWindow window = AmoebaWindow.instance();
+
+			AmakPlot loopNCS = window.getPlot("This loop NCS");
+			AmakPlot allNCS = window.getPlot("All time NCS");
+			AmakPlot nbAgent = window.getPlot("Number of agents");
+			AmakPlot errors = window.getPlot("Errors");
+			AmakPlot distancesToModels = window.getPlot("Distances to models");
+			AmakPlot gloabalMappingCriticality = window.getPlot("Global Mapping Criticality");
+			AmakPlot timeExecution = window.getPlot("Time Execution");
+			AmakPlot criticalities = window.getPlot("Criticalities");
 			
 			
 			boolean notify = isRenderUpdate();
@@ -182,7 +174,7 @@ public class AMOEBA extends Amas<World> implements IAMOEBA {
 		}
 		
 		if (isRenderUpdate()) {
-			((AmoebaMultiUIWindow)amasMultiUIWindow).mainVUI.updateCanvas();
+			AmoebaWindow.instance().mainVUI.updateCanvas();
 			updateAgentsVisualisation();
 			RunLaterHelper.runLater(() -> {resetCycleWithoutRender();});
 		}
@@ -462,7 +454,7 @@ public class AMOEBA extends Amas<World> implements IAMOEBA {
 	 */
 	public void allowGraphicalScheduler(boolean allow) {
 		if (!Configuration.commandLineMode) {
-			((AmoebaMultiUIWindow)amasMultiUIWindow).schedulerToolbar.setDisable(!allow);
+			AmoebaWindow.instance().schedulerToolbar.setDisable(!allow);
 		}
 	}
 
@@ -484,7 +476,7 @@ public class AMOEBA extends Amas<World> implements IAMOEBA {
 		super.addPendingAgents();
 		nextCycleRunAllAgents();
 		if(!Configuration.commandLineMode) {
-			((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.update(getPercepts());
+			AmoebaWindow.instance().dimensionSelector.update(getPercepts());
 			updateAgentsVisualisation();
 		}
 	}
@@ -512,7 +504,7 @@ public class AMOEBA extends Amas<World> implements IAMOEBA {
 	public void setRenderUpdate(boolean renderUpdate) {
 		if (!Configuration.commandLineMode) {
 			this.renderUpdate = renderUpdate;
-			((AmoebaMultiUIWindow)amasMultiUIWindow).toggleRender.setSelected(renderUpdate);
+			AmoebaWindow.instance().toggleRender.setSelected(renderUpdate);
 			if(renderUpdate == true)
 				nextCycleRunAllAgents();
 		}
@@ -603,13 +595,13 @@ public class AMOEBA extends Amas<World> implements IAMOEBA {
 		for(Agent<? extends Amas<World>, World> a : getAgents()) {
 			a.onUpdateRender();
 		}
-		((AmoebaMultiUIWindow)amasMultiUIWindow).point.move(((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d1().getValue(), ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d2().getValue());
-		((AmoebaMultiUIWindow)amasMultiUIWindow).rectangle.setHeight(2*getEnvironment().getContextCreationNeighborhood(null, ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d2()));
-		((AmoebaMultiUIWindow)amasMultiUIWindow).rectangle.setWidth(2*getEnvironment().getContextCreationNeighborhood(null, ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d1()));
-		((AmoebaMultiUIWindow)amasMultiUIWindow).rectangle.move(((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d1().getValue() - getEnvironment().getContextCreationNeighborhood(null, ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d1()), ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d2().getValue() - getEnvironment().getContextCreationNeighborhood(null, ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d2()));
-		((AmoebaMultiUIWindow)amasMultiUIWindow).mainVUI.updateCanvas();
-		((AmoebaMultiUIWindow)amasMultiUIWindow).point.toFront();
-		((AmoebaMultiUIWindow)amasMultiUIWindow).point.setInfo(getCursorInfo());
+		AmoebaWindow.instance().point.move(AmoebaWindow.instance().dimensionSelector.d1().getValue(), AmoebaWindow.instance().dimensionSelector.d2().getValue());
+		AmoebaWindow.instance().rectangle.setHeight(2*getEnvironment().getContextCreationNeighborhood(null, AmoebaWindow.instance().dimensionSelector.d2()));
+		AmoebaWindow.instance().rectangle.setWidth(2*getEnvironment().getContextCreationNeighborhood(null, AmoebaWindow.instance().dimensionSelector.d1()));
+		AmoebaWindow.instance().rectangle.move(AmoebaWindow.instance().dimensionSelector.d1().getValue() - getEnvironment().getContextCreationNeighborhood(null, AmoebaWindow.instance().dimensionSelector.d1()), AmoebaWindow.instance().dimensionSelector.d2().getValue() - getEnvironment().getContextCreationNeighborhood(null, AmoebaWindow.instance().dimensionSelector.d2()));
+		AmoebaWindow.instance().mainVUI.updateCanvas();
+		AmoebaWindow.instance().point.toFront();
+		AmoebaWindow.instance().point.setInfo(getCursorInfo());
 	}
 	
 	/**
@@ -617,7 +609,7 @@ public class AMOEBA extends Amas<World> implements IAMOEBA {
 	 * @return
 	 */
 	public DimensionSelector getDimensionSelector() {
-		return ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector;
+		return AmoebaWindow.instance().dimensionSelector;
 	}
 	
 	/**
@@ -767,4 +759,4 @@ public class AMOEBA extends Amas<World> implements IAMOEBA {
 		percepts = null;
 	}
 	
-}
+}
\ No newline at end of file
diff --git a/AMOEBAonAMAK/src/kernel/AMOEBAMultiUI.java b/AMOEBAonAMAK/src/kernel/AMOEBAMultiUI.java
new file mode 100644
index 00000000..e0a80944
--- /dev/null
+++ b/AMOEBAonAMAK/src/kernel/AMOEBAMultiUI.java
@@ -0,0 +1,770 @@
+package kernel;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import agents.AmoebaAgent;
+import agents.context.Context;
+import agents.context.localModel.LocalModel;
+import agents.context.localModel.LocalModelMillerRegression;
+import agents.context.localModel.TypeLocalModel;
+import agents.head.Head;
+import agents.percept.Percept;
+import fr.irit.smac.amak.Agent;
+import fr.irit.smac.amak.Amas;
+import fr.irit.smac.amak.Configuration;
+import fr.irit.smac.amak.Scheduling;
+import fr.irit.smac.amak.tools.Log;
+import fr.irit.smac.amak.tools.RunLaterHelper;
+import fr.irit.smac.amak.ui.AmakPlot;
+import fr.irit.smac.amak.ui.VUIMulti;
+import gui.AmoebaMultiUIWindow;
+import gui.AmoebaWindow;
+import gui.DimensionSelector;
+import kernel.backup.IBackupSystem;
+import kernel.backup.ISaveHelper;
+import kernel.backup.SaveHelperDummy;
+import kernel.backup.SaveHelperImpl;
+import ncs.NCS;
+import utils.PrintOnce;
+
+/**
+ * The AMOEBA amas
+ *
+ */
+public class AMOEBAMultiUI extends Amas<World> implements IAMOEBA {
+	// -- Attributes
+	
+	
+	public VUIMulti vuiMulti;
+	/**
+	 * Utility to save, autosave, and load amoebas.
+	 */
+	public ISaveHelper saver = new SaveHelperDummy();
+	
+	/**
+	 * The system studied by the amoeba.
+	 */
+	public StudiedSystem studiedSystem;
+	
+	public AmoebaMultiUIWindow multiUIWindow;
+	
+	private Head head;
+	private TypeLocalModel localModel = TypeLocalModel.MILLER_REGRESSION;
+	private HashMap<String, Double> perceptions = new HashMap<String, Double>();
+	private boolean useOracle = true;
+
+	private boolean runAll = false;
+	private boolean creationOfNewContext = true;
+	private boolean renderUpdate;
+	
+	private int cycleWithoutRender = 0;
+
+	private ArrayList<Context> spatiallyAlteredContext = new ArrayList<>();
+	private ArrayList<Context> toKillContexts = new ArrayList<>();
+	
+	private ArrayList<Context> lastModifiedContext = new ArrayList<>();
+
+	private ArrayList<Context> alteredContexts = new ArrayList<>();
+	
+	private HashSet<Context> validContexts;
+	private ReadWriteLock validContextLock = new ReentrantReadWriteLock();
+	
+	private HashSet<Context> neighborContexts ;
+	private ReadWriteLock neighborContextsLock = new ReentrantReadWriteLock();
+	
+	public AmoebaData data;
+	private ArrayList<Percept> percepts;
+
+	/**
+	 * Instantiates a new, empty, amoeba.
+	 * For ease of use, consider using {@link AMOEBAMultiUI#AMOEBAMultiUI(String, StudiedSystem)}.
+	 *
+	 * @param studiedSystem
+	 *            the studied system
+	 */
+	public AMOEBAMultiUI(AmoebaMultiUIWindow window, VUIMulti vui) {
+		super(window, vui, new World(), Scheduling.HIDDEN);
+		vuiMulti = vui;
+	}
+	
+	/**
+	 * Intantiate a default amoeba from a config file.
+	 * 
+	 * @param path path to the config file.
+	 */
+	public AMOEBAMultiUI(AmoebaMultiUIWindow window, VUIMulti vui, String path, StudiedSystem studiedSystem) {
+		super(window, vui, new World(), Scheduling.HIDDEN);
+		vuiMulti = vui;
+		this.studiedSystem = studiedSystem;
+		setRenderUpdate(true);
+		saver = new SaveHelperImpl(this);
+		saver.load(path);
+	}
+
+	@Override
+	protected void onInitialConfiguration() {
+		super.onInitialConfiguration();
+		if(Configuration.allowedSimultaneousAgentsExecution != 1) {
+			PrintOnce.print("Warning ! Multithreading is not currently sopported !\n"
+					+ "Please use Configuration.allowedSimultaneousAgentsExecution=1");
+		}
+		getEnvironment().setAmoeba(this);
+		data = new AmoebaData();
+	}
+	
+	@Override
+	protected void onRenderingInitialization() {
+		((AmoebaMultiUIWindow) amasMultiUIWindow).initialize(this);
+	}
+
+	@Override
+	protected void onUpdateRender() {
+		// Update statistics
+		if(amasMultiUIWindow!=null) {
+
+			AmakPlot loopNCS = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("This loop NCS");
+			AmakPlot allNCS = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("All time NCS");
+			AmakPlot nbAgent = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Number of agents");
+			AmakPlot errors = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Errors");
+			AmakPlot distancesToModels = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Distances to models");
+			AmakPlot gloabalMappingCriticality = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Global Mapping Criticality");
+			AmakPlot timeExecution = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Time Execution");
+			AmakPlot criticalities = ((AmoebaMultiUIWindow)amasMultiUIWindow).getPlot("Criticalities");
+			
+			
+			boolean notify = isRenderUpdate();
+			
+			HashMap<NCS, Integer> thisLoopNCS = environment.getThisLoopNCS();
+			HashMap<NCS, Integer> allTimeNCS = environment.getAllTimeNCS();
+			for (NCS ncs : NCS.values()) {
+				loopNCS.addData(ncs, cycle, thisLoopNCS.get(ncs), notify);
+				allNCS.addData(ncs, cycle, allTimeNCS.get(ncs), notify);
+			}
+			nbAgent.addData("Percepts", cycle, getPercepts().size(), notify);
+			nbAgent.addData("Contexts", cycle, getContexts().size(), notify);
+			nbAgent.addData("Activated", cycle, environment.getNbActivatedAgent(), notify);
+
+			errors.addData("Criticality", cycle, head.getNormalizedCriticicality(), notify);
+			errors.addData("Mean criticality", cycle, head.getAveragePredictionCriticity(), notify);
+			errors.addData("Error allowed", cycle, head.getErrorAllowed(), notify);
+			
+			distancesToModels.addData("Distance to model", cycle, head.getDistanceToRegression(), notify);
+			distancesToModels.addData("Average distance to model", cycle, head.criticalities.getCriticalityMean("distanceToRegression"), notify);
+			distancesToModels.addData("Allowed distance to model", cycle, head.getDistanceToRegressionAllowed(), notify);
+			
+			gloabalMappingCriticality.addData("Current Value", cycle, head.getAverageSpatialCriticality(), notify);
+			gloabalMappingCriticality.addData("Zero", cycle, 0.0, notify);
+			
+			timeExecution.addData("HeadPlay", cycle, data.executionTimesSums[0], notify);
+			timeExecution.addData("EndogenousPlay", cycle, data.executionTimesSums[1], notify);
+			timeExecution.addData("ContextSelfAnalisis", cycle, data.executionTimesSums[2], notify);
+			timeExecution.addData("IncompetentNCS", cycle, data.executionTimesSums[3], notify);
+			timeExecution.addData("ConcurrenceNCS", cycle, data.executionTimesSums[4], notify);
+			timeExecution.addData("NewContextNCS", cycle, data.executionTimesSums[5], notify);
+			timeExecution.addData("OvermappingNCS", cycle, data.executionTimesSums[6], notify);
+			timeExecution.addData("Other", cycle, data.executionTimesSums[7], notify);
+			timeExecution.addData("BestContextInNeighbors", cycle, data.executionTimesSums[8], notify);
+			timeExecution.addData("CreateContext", cycle, data.executionTimesSums[9], notify);
+			timeExecution.addData("UpdateStatitics", cycle, data.executionTimesSums[10], notify);
+			timeExecution.addData("ChildContext", cycle, data.executionTimesSums[11], notify);
+			timeExecution.addData("PotentialRequest", cycle, data.executionTimesSums[12], notify);
+			
+			criticalities.addData("Prediction", cycle, data.evolutionCriticalityPrediction, notify);
+			criticalities.addData("Mapping", cycle, data.evolutionCriticalityMapping, notify);
+			criticalities.addData("Confidence", cycle, data.evolutionCriticalityConfidence, notify);
+		}
+		
+		if (isRenderUpdate()) {
+			((AmoebaMultiUIWindow)amasMultiUIWindow).mainVUI.updateCanvas();
+			updateAgentsVisualisation();
+			RunLaterHelper.runLater(() -> {resetCycleWithoutRender();});
+		}
+	}
+
+	@Override
+	protected void onSystemCycleBegin() {
+		if (cycle % 1000 == 0) {
+			Log.defaultLog.inform("AMOEBA", "Cycle " + cycle + ". Nb agents: "+getAgents().size());
+		}
+		
+		if(isRenderUpdate()) {
+			incrementCycleWithoutRender();
+			/* deactivate render update and stop simulation if UI is too far
+			 * behind the simulation (10 cycles)
+			 */
+			if(getCycleWithoutRender() > 10) {
+				setRenderUpdate(false);
+				RunLaterHelper.runLater(()->{
+					// we (sadly) have to put it inside a runlater to correctly update the slider
+					getScheduler().stop(); 
+				});
+				Log.defaultLog.warning("AMOEBA UI", "Rendering cannot keep up with simulation, it has been deactivated. "
+						+ "To reactiavte it, slow down the simulation and toggle the \"Allow Rendering\" button.");
+			}
+		}
+		
+		if (studiedSystem != null) {
+			
+			studiedSystem.playOneStep();
+			
+			perceptions = studiedSystem.getOutput();
+			
+			
+		}
+		
+		environment.preCycleActions();
+		head.clearAllUseableContextLists();
+		validContexts = null;
+		neighborContexts = null;
+		environment.resetNbActivatedAgent();
+		spatiallyAlteredContext.clear();
+		toKillContexts.clear();
+		lastModifiedContext.clear();
+		alteredContexts.clear();
+	}
+	
+	synchronized private void incrementCycleWithoutRender() {
+		cycleWithoutRender += 1;
+	}
+	
+	synchronized private void resetCycleWithoutRender() {
+		cycleWithoutRender = 0;
+	}
+	
+	synchronized private int getCycleWithoutRender() {
+		return cycleWithoutRender;
+	}
+	
+	@Override
+	protected void onSystemCycleEnd() {
+		
+		if(studiedSystem != null) {
+			if(head.isActiveLearning()) {
+				studiedSystem.setActiveLearning(true);
+				studiedSystem.setSelfRequest(head.getSelfRequest());
+				 
+			}
+		}
+		
+		super.onSystemCycleEnd();
+		if(saver != null)
+			saver.autosave();
+	}
+
+	/**
+	 * Define what is done during a cycle, most importantly it launch agents.
+	 *
+	 * Every 1000 cycles, all Context are launched, allowing to delete themselves if
+	 * they're too small. To change this behavior you have to modify this method.
+	 */
+	@Override
+	public void cycle() {
+		cycle++;
+
+		onSystemCycleBegin();
+
+		// run percepts
+		List<Percept> synchronousPercepts = getPercepts().stream().filter(a -> a.isSynchronous())
+				.collect(Collectors.toList());
+		//Collections.sort(synchronousPercepts, new AgentOrderComparator());
+
+		for (Percept agent : synchronousPercepts) {
+			executor.execute(agent);
+		}
+		try {
+			perceptionPhaseSemaphore.acquire(synchronousPercepts.size());
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+		}
+		try {
+			decisionAndActionPhasesSemaphore.acquire(synchronousPercepts.size());
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+		}
+
+		// it is sometime useful to run all context agent
+		// especially to check if they're not too small,
+		// or after reactivating rendering.
+		if (cycle % 1000 == 0) {
+			runAll = true;
+		}
+
+		Stream<Context> contextStream = null;
+		if (runAll) {
+			contextStream = getContexts().stream(); // update all context
+			runAll = false;
+		} else {
+			HashSet<Context> vcontexts = getValidContexts();
+			if (vcontexts == null) {
+				vcontexts = new HashSet<>();
+			}
+			contextStream = vcontexts.stream(); // or only valid ones
+		}
+		
+		getHeadAgent().setActivatedNeighborsContexts(new ArrayList<Context>(getNeighborContexts()));
+		
+		
+		// run contexts
+		List<Context> synchronousContexts = contextStream.filter(a -> a.isSynchronous()).collect(Collectors.toList());
+		//Collections.sort(synchronousContexts, new AgentOrderComparator());
+
+		for (Context agent : synchronousContexts) {
+			executor.execute(agent);
+		}
+		try {
+			perceptionPhaseSemaphore.acquire(synchronousContexts.size());
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+		}
+		try {
+			decisionAndActionPhasesSemaphore.acquire(synchronousContexts.size());
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+		}
+
+		// run head
+		List<Head> heads = new ArrayList<>();
+		heads.add(head);
+		List<Head> synchronousHeads = heads.stream().filter(a -> a.isSynchronous()).collect(Collectors.toList());
+		//Collections.sort(synchronousHeads, new AgentOrderComparator());
+
+		for (Head agent : synchronousHeads) {
+			executor.execute(agent);
+		}
+		try {
+			perceptionPhaseSemaphore.acquire(synchronousHeads.size());
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+		}
+		try {
+			decisionAndActionPhasesSemaphore.acquire(synchronousHeads.size());
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+		}
+
+		removePendingAgents();
+
+		addPendingAgents();
+
+		onSystemCycleEnd();
+
+		if (!Configuration.commandLineMode) {
+			onUpdateRender();
+			
+			if(Configuration.waitForGUI) {
+				// we put an action in JavaFX rendering queue
+				RunLaterHelper.runLater(() -> {
+					renderingPhaseSemaphore.release();
+				});
+				// and wait for it to finish
+				try {
+					renderingPhaseSemaphore.acquire();
+				} catch (InterruptedException e) {
+					Log.defaultLog.error("[AMAS GUI]", "Failed to wait for GUI update to finish.");
+					e.printStackTrace();
+				}
+				// now the queue should be clear
+			}
+		}
+
+	}
+
+	@Override
+	public HashMap<String, Double> learn(HashMap<String, Double> perceptionsActionState) {
+		StudiedSystem ss = studiedSystem;
+		studiedSystem = null;
+		setPerceptionsAndActionState(perceptionsActionState);
+		cycle();
+		studiedSystem = ss;
+		
+		return null;
+	}
+
+	@Override
+	public double request(HashMap<String, Double> perceptionsActionState) {
+		boolean usingOracle = isUseOracle();
+		if (usingOracle)
+			head.changeOracleConnection();
+		StudiedSystem ss = studiedSystem;
+		studiedSystem = null;
+		setPerceptionsAndActionState(perceptionsActionState);
+		cycle();
+		if (usingOracle)
+			head.changeOracleConnection();
+		studiedSystem = ss;
+		return getAction();
+	}
+	
+	@Override
+	public HashMap<String, Double> maximize(HashMap<String, Double> known){
+		ArrayList<Percept> percepts = getPercepts();
+		ArrayList<Percept> unknown = new ArrayList<>(percepts);
+		unknown.removeIf(p ->known.containsKey(p.getName()));
+		//System.out.println("known : "+known.keySet());
+		//System.out.println("unknow : "+unknown);
+		if(unknown.isEmpty()) {
+			return null;
+		}
+		
+		//get partially activated context
+		ArrayList<Context> pac = new ArrayList<>();
+		for(Context c : getContexts()) {
+			boolean good = true;
+			for(String p : known.keySet()) {
+				if(!c.getRangeByPerceptName(p).contains2(known.get(p))) {
+					good = false;
+					break;
+				}
+			}
+			if(good) pac.add(c);
+		}
+		
+		ArrayList<HashMap<String, Double>> sol = new ArrayList<>();
+		for(Context c : pac) {
+			sol.add(c.getLocalModel().getMaxWithConstraint(known));
+		}
+		HashMap<String, Double> max = new HashMap<>();
+
+		Double maxValue = Double.NEGATIVE_INFINITY;
+		max.put("oracle", maxValue);
+		//find best solution
+		for(HashMap<String, Double> s : sol) {
+			if(s.get("oracle") > maxValue) {
+				maxValue = s.get("oracle");
+				max = s;
+			}
+		}
+		return max;
+	}
+
+	public LocalModel buildLocalModel(Context context) {
+		switch (localModel) {
+		case MILLER_REGRESSION:
+			return new LocalModelMillerRegression(context);
+
+		default:
+			throw new IllegalArgumentException("Unknown model " + localModel + ".");
+		}
+	}
+
+	/**
+	 * Activate or deactivate the graphical scheduler. Allowing or denying the user
+	 * to change the simulation speed.
+	 *
+	 * @param allow
+	 */
+	public void allowGraphicalScheduler(boolean allow) {
+		if (!Configuration.commandLineMode) {
+			((AmoebaMultiUIWindow)amasMultiUIWindow).schedulerToolbar.setDisable(!allow);
+		}
+	}
+
+	@Override
+	public void clearAgents() {
+		List<Agent<? extends Amas<World>, World>> agents = getAgents();
+		for (Agent<? extends Amas<World>, World> agent : agents) {
+			AmoebaAgent amoebaAgent = (AmoebaAgent) agent;
+			amoebaAgent.destroy();
+		}
+		this.head = null;
+		super.removePendingAgents();
+	}
+
+	/**
+	 * Called when a {@link IBackupSystem} has finished loading the amoeba.
+	 */
+	public void onLoadEnded() {
+		super.addPendingAgents();
+		nextCycleRunAllAgents();
+		if(!Configuration.commandLineMode) {
+			((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.update(getPercepts());
+			updateAgentsVisualisation();
+		}
+	}
+
+	@Override
+	public void setCreationOfNewContext(boolean creationOfNewContext) {
+		this.creationOfNewContext = creationOfNewContext;
+	}
+
+	@Override
+	public void setHead(Head head) {
+		this.head = head;
+	}
+
+	@Override
+	public void setLocalModel(TypeLocalModel localModel) {
+		this.localModel = localModel;
+	}
+
+	/**
+	 * Activate or deactivate rendering of agents at runtime.
+	 *
+	 * @param renderUpdate
+	 */
+	public void setRenderUpdate(boolean renderUpdate) {
+		if (!Configuration.commandLineMode) {
+			this.renderUpdate = renderUpdate;
+			((AmoebaMultiUIWindow)amasMultiUIWindow).toggleRender.setSelected(renderUpdate);
+			if(renderUpdate == true)
+				nextCycleRunAllAgents();
+		}
+	}
+
+	/**
+	 * Set input used by percepts and oracle.
+	 *
+	 * @param perceptionsAndActions
+	 */
+	public void setPerceptionsAndActionState(HashMap<String, Double> perceptionsAndActions) {
+		this.perceptions = perceptionsAndActions;
+	}
+
+	/**
+	 * Get the last prediction from the system.
+	 *
+	 * @return
+	 */
+	public double getAction() {
+		return head.getAction();
+	}
+
+	public ArrayList<Context> getContexts() {
+		ArrayList<Context> contexts = new ArrayList<>();
+		for (Agent<? extends Amas<World>, World> agent : getAgents()) {
+			if ((agent instanceof Context)) {
+				contexts.add((Context) agent);
+			}
+		}
+		return contexts;
+	}
+
+	public ArrayList<Head> getHeads() {
+		ArrayList<Head> heads = new ArrayList<>();
+		heads.add(head);
+		return heads;
+	}
+
+	public ArrayList<Percept> getPercepts() {
+		if(percepts == null || percepts.size()==0) {
+			setPercepts();
+		}	
+		return percepts;
+	}
+
+	/**
+	 * Get the value for a perception
+	 * @param key key of the perception
+	 * @return the value of the perception
+	 */
+	public Double getPerceptions(String key) {
+		return this.perceptions.get(key);
+	}
+
+	@Override
+	public boolean isCreationOfNewContext() {
+		return creationOfNewContext;
+	}
+
+	/**
+	 * Tell AMOEBA to run all (contexts) agent for the next cycle.
+	 */
+	public void nextCycleRunAllAgents() {
+		runAll = true;
+	}
+
+	/**
+	 * Is rendering activated ?
+	 * @return
+	 */
+	public boolean isRenderUpdate() {
+		return (!Configuration.commandLineMode) && renderUpdate;
+	}
+
+	/**
+	 * Should AMOEBA use the oracle ? If false then AMOEBA will not learn.
+	 * @return
+	 */
+	public boolean isUseOracle() {
+		return useOracle;
+	}
+	
+	/**
+	 * Ask the agents to update their visualization, and update some UI element related to them.
+	 */
+	public void updateAgentsVisualisation() {
+		for(Agent<? extends Amas<World>, World> a : getAgents()) {
+			a.onUpdateRender();
+		}
+		((AmoebaMultiUIWindow)amasMultiUIWindow).point.move(((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d1().getValue(), ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d2().getValue());
+		((AmoebaMultiUIWindow)amasMultiUIWindow).rectangle.setHeight(2*getEnvironment().getContextCreationNeighborhood(null, ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d2()));
+		((AmoebaMultiUIWindow)amasMultiUIWindow).rectangle.setWidth(2*getEnvironment().getContextCreationNeighborhood(null, ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d1()));
+		((AmoebaMultiUIWindow)amasMultiUIWindow).rectangle.move(((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d1().getValue() - getEnvironment().getContextCreationNeighborhood(null, ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d1()), ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d2().getValue() - getEnvironment().getContextCreationNeighborhood(null, ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector.d2()));
+		((AmoebaMultiUIWindow)amasMultiUIWindow).mainVUI.updateCanvas();
+		((AmoebaMultiUIWindow)amasMultiUIWindow).point.toFront();
+		((AmoebaMultiUIWindow)amasMultiUIWindow).point.setInfo(getCursorInfo());
+	}
+	
+	/**
+	 * The tool telling which dimension to display
+	 * @return
+	 */
+	public DimensionSelector getDimensionSelector() {
+		return ((AmoebaMultiUIWindow)amasMultiUIWindow).dimensionSelector;
+	}
+	
+	/**
+	 * Get the last perception.
+	 * @return
+	 */
+	public HashMap<String, Double> getPerceptionsAndActionState() {
+		return perceptions;
+	}
+	
+	/**
+	 * Set the studied system that will be used to learn with the internal scheduler.
+	 * @param studiedSystem
+	 */
+	public void setStudiedSystem(StudiedSystem studiedSystem) {
+		this.studiedSystem = studiedSystem;
+	}
+	
+	public Head getHeadAgent() {
+		return head;
+	}
+	
+	public ArrayList<Context> getSpatiallyAlteredContextForUnityUI() {
+		return spatiallyAlteredContext;
+	}
+	
+	public void addSpatiallyAlteredContextForUnityUI(Context ctxt) {
+		if(!ctxt.isFlat())
+			spatiallyAlteredContext.add(ctxt);
+	}
+	
+	public ArrayList<Context> getToKillContextsForUnityUI() {
+		return toKillContexts;
+	}
+	
+	public void addToKillContextForUnityUI(Context ctxt) {
+		toKillContexts.add(ctxt);
+	}
+	
+	public void addLastmodifiedContext(Context context) {
+		if(!lastModifiedContext.contains(context)) {
+			lastModifiedContext.add(context);
+		}
+	}
+	
+	public ArrayList<Context> getLastModifiedContexts(){
+		return lastModifiedContext;
+	}
+	
+	/**
+	 * Adds the altered context.
+	 *
+	 * @param context the context
+	 */
+	public void addAlteredContext(Context context) {
+		alteredContexts.add(context);
+	}
+	
+	/**
+	 * Return the current set of valid contexts.
+	 *
+	 * Synchronized with a readLock.
+	 *
+	 * @return
+	 */
+	public HashSet<Context> getValidContexts() {
+		HashSet<Context> ret;
+		validContextLock.readLock().lock();
+		if (validContexts == null) {
+			ret = null;
+		} else {
+			ret = new HashSet<>(validContexts);
+		}
+		validContextLock.readLock().unlock();
+		return ret;
+	}
+	
+	/**
+	 * Update the set of valid context. The update is done with an intersect of the
+	 * previous and new set.
+	 *
+	 * Synchronized with a writeLock.
+	 * @param validContexts new validContexts set.
+	 */
+	@SuppressWarnings("unchecked")
+	public void updateNeighborContexts(HashSet<Context> neighborContexts) {
+		neighborContextsLock.writeLock().lock();
+		if (this.neighborContexts == null) {
+			this.neighborContexts = (HashSet<Context>) neighborContexts.clone();
+		} else {
+			this.neighborContexts.retainAll(neighborContexts);
+		}
+		neighborContextsLock.writeLock().unlock();
+	}
+	
+	public HashSet<Context> getNeighborContexts() {
+		HashSet<Context> ret;
+		neighborContextsLock.readLock().lock();
+		if (neighborContexts == null) {
+			ret = null;
+		} else {
+			ret = new HashSet<>(neighborContexts);
+		}
+		neighborContextsLock.readLock().unlock();
+		return ret;
+	}
+	
+	/**
+	 * Update the set of valid context. The update is done with an intersect of the
+	 * previous and new set.
+	 *
+	 * Synchronized with a writeLock.
+	 * @param validContexts new validContexts set.
+	 */
+	@SuppressWarnings("unchecked")
+	public void updateValidContexts(HashSet<Context> validContexts) {
+		validContextLock.writeLock().lock();
+		if (this.validContexts == null) {
+			this.validContexts = (HashSet<Context>) validContexts.clone();
+		} else {
+			this.validContexts.retainAll(validContexts);
+		}
+		validContextLock.writeLock().unlock();
+	}
+	
+	private String getCursorInfo() {
+		String message = "";
+		for(Percept pct : getPercepts()) {
+			message += pct.getName() + "\t" + pct.getValue() +"\t[ " + pct.getMin() +" ; " + pct.getMax() + " ]\n" ;
+		}
+		return message;
+	}
+	
+	public void setPercepts() {
+		percepts = new ArrayList<Percept>();
+		for (Agent<? extends Amas<World>, World> agent : getAgents()) {
+			if ((agent instanceof Percept)) {
+				Percept p = (Percept) agent;
+				if(!p.isDying()) {
+					percepts.add(p);
+				}
+			}
+		}
+	}
+	
+	public void addPercept(Percept pct) {
+		percepts = null;
+	}
+	
+}
-- 
GitLab