package api;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.DoubleSummaryStatistics;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JSplitPane;
import javax.swing.border.EmptyBorder;
import javax.swing.text.NumberFormatter;

import algorithm.objectiveFunction.TopologieObjectiveFunction;
import classes.AbstractCanvasObject;
import classes.Category;
import classes.Edge;
import classes.GroupNode;
import classes.Flexibility;
import classes.HolonObject;
import classes.HolonSwitch;
import classes.IdCounterElem;
import classes.Node;
import classes.HolonElement.Priority;
import ui.controller.Control;
import ui.controller.FlexManager.FlexState;
import ui.model.DecoratedGroupNode;
import ui.model.DecoratedState;
import ui.model.Model;
import ui.model.DecoratedHolonObject.HolonObjectState;
import ui.model.DecoratedSwitch.SwitchState;
import ui.model.DecoratedNetwork;
import ui.view.Console;

public abstract class TopologieAlgorithmFramework implements AddOn{
	//Algo
	protected int rounds = 1;
	protected int amountOfNewCables = 20;
	
	
	//Panel
	private JPanel content = new JPanel();
	protected Console console = new Console();
	private JPanel borderPanel = new JPanel();
	private HashMap<String, JPanel> panelMap = new HashMap<String, JPanel>();
	
	
	
	
	//Settings groupNode
	private DecoratedGroupNode dGroupNode = null;
	
	
	//access
	private ArrayList<AccessWrapper> accessWildcards = new  ArrayList<AccessWrapper>();
	LinkedList<List<Integer>> resetChain = new LinkedList<List<Integer>>();
	
	
	private HashMap<Integer, AbstractCanvasObject> accessIntToObject = new HashMap<Integer, AbstractCanvasObject>();
	private HashMap<AbstractCanvasObject, Integer> accessObjectToInt = new HashMap<AbstractCanvasObject, Integer>();
	private HashMap<Integer, AbstractCanvasObject> accessIntegerToWildcard = new HashMap<Integer, AbstractCanvasObject>();
	private HashMap<AbstractCanvasObject, GroupNode> accessGroupNode = new HashMap<AbstractCanvasObject, GroupNode>(); 
	
	private HashSet<IndexCable> cableSet = new HashSet<IndexCable>();
	private ArrayList<IndexCable> cableList = new ArrayList<IndexCable>();
	private HashMap<IndexCable, Double> addedIndexCable = new HashMap<IndexCable, Double>();
	private int countForAccessMap = 0;
	private int amountOfExistingCables = 0;
	private ArrayList<HolonSwitch> switchList = new ArrayList<HolonSwitch>();
	private HashMap<HolonSwitch, GroupNode> accessSwitchGroupNode = new HashMap<HolonSwitch, GroupNode>(); 
	private ArrayList<Edge> edgeList = new ArrayList<Edge>();
	
	boolean algoUseElements = false, algoUseSwitches = true, algoUseFlexes = true;
	
	//time
	private long startTime;
	
	
	private RunProgressBar runProgressbar = new RunProgressBar();
	
	
	
	//concurrency
	private Thread runThread = new Thread();
	protected boolean cancel = false;

	//holeg interaction
	protected Control  control;

	
	//printing
	private Printer runPrinter = new Printer(plottFileName());
	protected List<Double> runList = new LinkedList<Double>();

	//Parameter
	@SuppressWarnings("rawtypes")
	LinkedList<ParameterStepping> parameterSteppingList= new LinkedList<ParameterStepping>();
	protected boolean useStepping = false;
	//SwitchButton
	

	
	
	public TopologieAlgorithmFramework(){
		content.setLayout(new BorderLayout());
		JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
				createOptionPanel() , console);
		splitPane.setResizeWeight(0.0);
		content.add(splitPane, BorderLayout.CENTER);
		content.setPreferredSize(new Dimension(1200,800));
	}
	
	
	
	
	
	
	private JPanel createOptionPanel() {
		JPanel optionPanel = new JPanel(new BorderLayout());
		JScrollPane scrollPane = new JScrollPane(createParameterPanel());
		scrollPane.setBorder(BorderFactory.createTitledBorder("Parameters"));
		optionPanel.add(scrollPane,  BorderLayout.CENTER);
		optionPanel.add(createButtonPanel(), BorderLayout.PAGE_END);
		return optionPanel;
	}
	
	private JPanel createParameterPanel() {
		JPanel parameterPanel = new JPanel(null);
		parameterPanel.setPreferredSize(new Dimension(510,300));
		borderPanel.setLayout(new BoxLayout(borderPanel, BoxLayout.PAGE_AXIS));
		addIntParameter("Number of New Cables", amountOfNewCables, intInput -> amountOfNewCables = intInput, () -> amountOfNewCables, 0);
		addSeperator();
		addIntParameter("Repetitions", rounds, intInput -> rounds = intInput, () -> rounds, 1);
		JScrollPane scrollPane = new JScrollPane(borderPanel);
		scrollPane.setBounds(10, 0, 850, 292);
		scrollPane.setBorder(BorderFactory.createEmptyBorder());
		parameterPanel.add(scrollPane);	
		
		
		JProgressBar progressBar = runProgressbar.getJProgressBar();
		progressBar.setBounds(900, 35, 185, 20);
		progressBar.setStringPainted(true);
		parameterPanel.add(progressBar);
		
		JButton addCategoryButton = new JButton("Add Category");
		addCategoryButton.setBounds(900, 65, 185, 30);
		addCategoryButton.addActionListener(clicked -> createWildcardsCategory());
		parameterPanel.add(addCategoryButton);
		return parameterPanel;
	}
	private JPanel createButtonPanel() {
		JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
		
		JButton toggleSwitchesButton =  new JButton("Toggle Switches");
		toggleSwitchesButton.setToolTipText("Set all switches active or inactive.");
		toggleSwitchesButton.addActionListener(actionEvent -> toggleSwitches());
		buttonPanel.add(toggleSwitchesButton);
		
		
		
		JButton resetButton =  new JButton("Reset");
		resetButton.setToolTipText("Resets the State to before the Algorithm has runed.");
		resetButton.addActionListener(actionEvent -> reset());
		buttonPanel.add(resetButton);
		
		JButton cancelButton =  new JButton("Cancel Run");
		cancelButton.addActionListener(actionEvent -> cancel());
		buttonPanel.add(cancelButton);
		
		JButton fitnessButton =  new JButton("Fitness");
		fitnessButton.setToolTipText("Fitness for the current state.");
		fitnessButton.addActionListener(actionEvent -> fitness());
		buttonPanel.add(fitnessButton);
		
		JButton runButton =  new JButton("Run");
		runButton.addActionListener(actionEvent -> {
			if(runThread.isAlive()) {
				return;
			}
			reset();
			this.resetAllList();
			resetChain.clear();
			Runnable task = () -> run();
			runThread = new Thread(task);
			runThread.start();
		});
		buttonPanel.add(runButton);
		
		
		
		return buttonPanel;
	}
	
	
	
	//ParameterImports
	
	private void toggleSwitches() {
		List<HolonSwitch> allSwitchList = control.getModel().getAllSwitches();
		if(allSwitchList.isEmpty()) return;
		boolean set = allSwitchList.get(0).getState(control.getModel().getCurIteration());
		allSwitchList.forEach(hSwitch -> {
			hSwitch.setManualMode(true);
			hSwitch.setManualState(!set);
		});
		updateVisual();
	}



	//addSeperator
	protected void addSeperator() {
		borderPanel.add(Box.createRigidArea(new Dimension(5, 5)));
		borderPanel.add(new JSeparator());
		borderPanel.add(Box.createRigidArea(new Dimension(5, 5)));
	}


	//int
	protected void addIntParameter(String parameterName, int parameterValue, Consumer<Integer> setter, Supplier<Integer> getter) {
		this.addIntParameter(parameterName, parameterValue, setter, getter, true, Integer.MIN_VALUE, Integer.MAX_VALUE);
	}
	
	protected void addIntParameter(String parameterName, int parameterValue, Consumer<Integer> setter, Supplier<Integer> getter, int parameterMinValue) {
		this.addIntParameter(parameterName, parameterValue, setter, getter, true, parameterMinValue, Integer.MAX_VALUE);
	}
	
	protected void addIntParameter(String parameterName, int parameterValue, Consumer<Integer> setter, Supplier<Integer> getter, boolean visible, int parameterMinValue, int parameterMaxValue) {
		JPanel singleParameterPanel = new JPanel();
		singleParameterPanel.setLayout(new BoxLayout(singleParameterPanel, BoxLayout.LINE_AXIS));
		singleParameterPanel.setAlignmentX(0.0f);
		singleParameterPanel.add(new JLabel(parameterName + ": "));
		singleParameterPanel.add(Box.createHorizontalGlue());
		NumberFormat format = NumberFormat.getIntegerInstance();
		format.setGroupingUsed(false);
		format.setParseIntegerOnly(true);
		NumberFormatter integerFormatter = new NumberFormatter(format);
		integerFormatter.setMinimum(parameterMinValue);
		integerFormatter.setMaximum(parameterMaxValue);
		integerFormatter.setCommitsOnValidEdit(true);
		JFormattedTextField singleParameterTextField = new  JFormattedTextField(integerFormatter);
		singleParameterTextField.setValue(parameterValue);
		String minValue = (parameterMinValue == Integer.MIN_VALUE)?"Integer.MIN_VALUE":String.valueOf(parameterMinValue);
		String maxValue = (parameterMaxValue == Integer.MAX_VALUE)?"Integer.MAX_VALUE":String.valueOf(parameterMaxValue);
		singleParameterTextField.setToolTipText("Only integer \u2208 [" + minValue + "," + maxValue + "]");
		singleParameterTextField.addPropertyChangeListener(actionEvent -> setter.accept(Integer.parseInt(singleParameterTextField.getValue().toString())));
		singleParameterTextField.setMaximumSize(new Dimension(200, 30));
		singleParameterTextField.setPreferredSize(new Dimension(200, 30));
		singleParameterPanel.add(singleParameterTextField);
		
		
		ParameterStepping<Integer> intParameterStepping = new ParameterStepping<Integer>(setter, getter, Integer::sum , (a,b) -> a * b, 1, 1);
		intParameterStepping.useThisParameter = false;
		parameterSteppingList.add(intParameterStepping);
		
		JCheckBox useSteppingCheckBox = new JCheckBox();
		useSteppingCheckBox.setSelected(false);
		singleParameterPanel.add(useSteppingCheckBox);
		
		
		
		JLabel stepsLabel = new JLabel("Steps: ");
		stepsLabel.setEnabled(false);
		singleParameterPanel.add(stepsLabel);
		
		NumberFormatter stepFormatter = new NumberFormatter(format);
		stepFormatter.setMinimum(1);
		stepFormatter.setMaximum(Integer.MAX_VALUE);
		stepFormatter.setCommitsOnValidEdit(true);
		
		
		JFormattedTextField stepsTextField = new  JFormattedTextField(stepFormatter);
		stepsTextField.setEnabled(false);
		stepsTextField.setValue(1);
		stepsTextField.setToolTipText("Only integer \u2208 [" + 1 + "," + Integer.MAX_VALUE + "]");
		stepsTextField.addPropertyChangeListener(actionEvent -> intParameterStepping.stepps = Integer.parseInt(stepsTextField.getValue().toString()));
		stepsTextField.setMaximumSize(new Dimension(40, 30));
		stepsTextField.setPreferredSize(new Dimension(40, 30));
		singleParameterPanel.add(stepsTextField);
		
		JLabel stepsSizeLabel = new JLabel("StepsSize: ");
		stepsSizeLabel.setEnabled(false);
		singleParameterPanel.add(stepsSizeLabel);
		
		JFormattedTextField stepsSizeTextField = new  JFormattedTextField(stepFormatter);
		stepsSizeTextField.setEnabled(false);
		stepsSizeTextField.setValue(1);
		stepsSizeTextField.setToolTipText("Only integer \u2208 [" + 1 + "," + Integer.MAX_VALUE + "]");
		stepsSizeTextField.addPropertyChangeListener(actionEvent -> intParameterStepping.stepSize = Integer.parseInt(stepsSizeTextField.getValue().toString()));
		stepsSizeTextField.setMaximumSize(new Dimension(40, 30));
		stepsSizeTextField.setPreferredSize(new Dimension(40, 30));
		singleParameterPanel.add(stepsSizeTextField);
		
		useSteppingCheckBox.addActionListener(actionEvent -> {
			boolean enabled = useSteppingCheckBox.isSelected();
			intParameterStepping.useThisParameter = enabled;
			this.useStepping = this.parameterSteppingList.stream().anyMatch(parameter -> parameter.useThisParameter);
			stepsLabel.setEnabled(enabled);
			stepsTextField.setEnabled(enabled);
			stepsSizeLabel.setEnabled(enabled);
			stepsSizeTextField.setEnabled(enabled);
		});
		panelMap.put(parameterName, singleParameterPanel);
		singleParameterPanel.setVisible(visible);
		borderPanel.add(singleParameterPanel);
	}
	
	
	//double
	protected void addDoubleParameter(String parameterName, double parameterValue, Consumer<Double> setter, Supplier<Double> getter) {
		this.addDoubleParameter(parameterName, parameterValue, setter, getter, true, Double.MIN_VALUE, Double.MAX_VALUE);
	}
	
	
	protected void addDoubleParameter(String parameterName, double parameterValue, Consumer<Double> setter, Supplier<Double> getter, double parameterMinValue) {
		this.addDoubleParameter(parameterName, parameterValue, setter, getter, true, parameterMinValue, Double.MAX_VALUE);
	}
	
	
	protected void addDoubleParameter(String parameterName, double parameterValue, Consumer<Double> setter, Supplier<Double> getter, boolean visible, double parameterMinValue, double parameterMaxValue) {
		JPanel singleParameterPanel = new JPanel();
		singleParameterPanel.setLayout(new BoxLayout(singleParameterPanel, BoxLayout.LINE_AXIS));
		singleParameterPanel.setAlignmentX(0.0f);
		singleParameterPanel.add(new JLabel(parameterName + ": "));
		singleParameterPanel.add(Box.createHorizontalGlue());
		NumberFormat doubleFormat = NumberFormat.getNumberInstance(Locale.US);
		doubleFormat.setMinimumFractionDigits(1);
		doubleFormat.setMaximumFractionDigits(10);
		doubleFormat.setRoundingMode(RoundingMode.HALF_UP);
		NumberFormatter doubleFormatter = new NumberFormatter(doubleFormat);
		doubleFormatter.setMinimum(parameterMinValue);
		doubleFormatter.setMaximum(parameterMaxValue);
		doubleFormatter.setCommitsOnValidEdit(true);
		JFormattedTextField singleParameterTextField = new  JFormattedTextField(doubleFormatter);
		singleParameterTextField.setValue(parameterValue);
		String minValue = (parameterMinValue == Double.MIN_VALUE)?"Double.MIN_VALUE":String.valueOf(parameterMinValue);
		String maxValue = (parameterMaxValue == Double.MAX_VALUE)?"Double.MAX_VALUE":String.valueOf(parameterMaxValue);
		singleParameterTextField.setToolTipText("Only double \u2208 [" + minValue + "," + maxValue + "]");
		singleParameterTextField.addPropertyChangeListener(actionEvent -> setter.accept(Double.parseDouble(singleParameterTextField.getValue().toString())));
		singleParameterTextField.setMaximumSize(new Dimension(200, 30));
		singleParameterTextField.setPreferredSize(new Dimension(200, 30));
		singleParameterPanel.add(singleParameterTextField);
		
		ParameterStepping<Double> doubleParameterStepping = new ParameterStepping<Double>(setter, getter, (a,b) -> a+b , (a,b) -> a * b, 1.0, 1);
		doubleParameterStepping.useThisParameter = false;
		parameterSteppingList.add(doubleParameterStepping);
		
		JCheckBox useSteppingCheckBox = new JCheckBox();
		useSteppingCheckBox.setSelected(false);
		singleParameterPanel.add(useSteppingCheckBox);
		
		
		
		JLabel stepsLabel = new JLabel("Steps: ");
		stepsLabel.setEnabled(false);
		singleParameterPanel.add(stepsLabel);
		NumberFormat format = NumberFormat.getIntegerInstance();
		format.setGroupingUsed(false);
		format.setParseIntegerOnly(true);
		NumberFormatter integerFormatter = new NumberFormatter(format);
		integerFormatter.setMinimum(1);
		integerFormatter.setMaximum(Integer.MAX_VALUE);
		integerFormatter.setCommitsOnValidEdit(true);
	
		
		
		JFormattedTextField stepsTextField = new  JFormattedTextField(integerFormatter);
		stepsTextField.setEnabled(false);
		stepsTextField.setValue(1);
		stepsTextField.setToolTipText("Only integer \u2208 [" + 1 + "," + Integer.MAX_VALUE + "]");
		stepsTextField.addPropertyChangeListener(actionEvent -> doubleParameterStepping.stepps = Integer.parseInt(stepsTextField.getValue().toString()));
		stepsTextField.setMaximumSize(new Dimension(40, 30));
		stepsTextField.setPreferredSize(new Dimension(40, 30));
		singleParameterPanel.add(stepsTextField);
		
		JLabel stepsSizeLabel = new JLabel("StepsSize: ");
		stepsSizeLabel.setEnabled(false);
		singleParameterPanel.add(stepsSizeLabel);
		
		NumberFormatter doubleFormatterForStepping = new NumberFormatter(doubleFormat);
		doubleFormatterForStepping.setCommitsOnValidEdit(true);
		JFormattedTextField stepsSizeTextField = new  JFormattedTextField(doubleFormatterForStepping);
		stepsSizeTextField.setEnabled(false);
		stepsSizeTextField.setValue(1.0);
		stepsSizeTextField.setToolTipText("Only double");
		stepsSizeTextField.addPropertyChangeListener(actionEvent -> doubleParameterStepping.stepSize = Double.parseDouble(stepsSizeTextField.getValue().toString()));
		stepsSizeTextField.setMaximumSize(new Dimension(40, 30));
		stepsSizeTextField.setPreferredSize(new Dimension(40, 30));
		singleParameterPanel.add(stepsSizeTextField);
		
		useSteppingCheckBox.addActionListener(actionEvent -> {
			boolean enabled = useSteppingCheckBox.isSelected();
			doubleParameterStepping.useThisParameter = enabled;
			this.useStepping = this.parameterSteppingList.stream().anyMatch(parameter -> parameter.useThisParameter);
			stepsLabel.setEnabled(enabled);
			stepsTextField.setEnabled(enabled);
			stepsSizeLabel.setEnabled(enabled);
			stepsSizeTextField.setEnabled(enabled);
		});
		panelMap.put(parameterName, singleParameterPanel);
		singleParameterPanel.setVisible(visible);
		borderPanel.add(singleParameterPanel);
	}
	//boolean
	protected void addBooleanParameter(String parameterName, boolean parameterValue, Consumer<Boolean> setter, List<String> showParameterNames, List<String> hideParameterNames){
		JPanel singleParameterPanel = new JPanel();
		panelMap.put(parameterName, singleParameterPanel);
		singleParameterPanel.setLayout(new BoxLayout(singleParameterPanel, BoxLayout.LINE_AXIS));
		singleParameterPanel.setAlignmentX(0.0f);
		singleParameterPanel.add(new JLabel(parameterName + ": "));
		singleParameterPanel.add(Box.createHorizontalGlue());
		JCheckBox useGroupNodeCheckBox = new JCheckBox();
		useGroupNodeCheckBox.addActionListener(actionEvent -> {
			setter.accept(useGroupNodeCheckBox.isSelected());
			showParameterNames.forEach(string -> panelMap.get(string).setVisible(useGroupNodeCheckBox.isSelected()));
			hideParameterNames.forEach(string -> panelMap.get(string).setVisible(!useGroupNodeCheckBox.isSelected()));
		});
		useGroupNodeCheckBox.setSelected(parameterValue);
		singleParameterPanel.add(useGroupNodeCheckBox);
		borderPanel.add(singleParameterPanel);
	}
	

	private void startTimer(){
		startTime = System.currentTimeMillis();
	}
	private long printElapsedTime(){
		long elapsedMilliSeconds = System.currentTimeMillis() - startTime;
		console.println("Execution Time of Algo in Milliseconds:" + elapsedMilliSeconds);
		return elapsedMilliSeconds;
	}
	
	
	
	private void cancel() {
		if(runThread.isAlive()) {
			console.println("Cancel run.");
			cancel = true;
			runProgressbar.cancel();
		} else {
			console.println("Nothing to cancel.");
		}
	}
	private void createWildcardsCategory() {
		Category category = control.searchCategory("Wildcards");
		if(category == null) {
			try {
				control.addCategory("Wildcards");
			} catch (IOException e) {
				console.println("IO Exception - Creating WIldcards Category failed.");
				System.out.println("IO Exception - Creating WIldcards Category failed.");
				e.printStackTrace();
			}
		}
	}
	
	private void fitness() {
		if(runThread.isAlive()) {
			console.println("Run have to be cancelled First.");
			return;
		}
//		reset();
//		this.extractPositionAndAccess();
		double currentFitness = evaluateNetworkAndPrint();
		console.println("Actual Fitnessvalue: " + currentFitness);
	}
	
	
	protected double evaluatePosition(List<Integer> positionToEvaluate) {
		setState(positionToEvaluate); // execution time critical
		return evaluateNetwork();
	}

	private double evaluateNetwork() {
		runProgressbar.step();
		DecoratedState actualstate = control.getSimManager().getActualDecorState();
		return evaluateState(actualstate, calculateAmountOfAddedSwitches(), addedCableMeter(), false);
	}
	private double evaluateNetworkAndPrint() {
		runProgressbar.step();
		for(HolonSwitch hSwitch: switchList) {
			hSwitch.setManualMode(true);
			hSwitch.setManualState(false);
		}
		control.calculateStateOnlyForCurrentTimeStep();
		DecoratedState actualstate = control.getSimManager().getActualDecorState();
		return evaluateState(actualstate, calculateAmountOfAddedSwitches(), addedCableMeter(), true);
	}
	
	
	private double addedCableMeter() {
		return addedIndexCable.values().stream().reduce(0.0, Double::sum);
	}

	private int calculateAmountOfAddedSwitches() {
		return (int)this.switchList.stream().filter(sw -> sw.getName().contains("AddedSwitch")).count();
	}
	
	protected abstract double evaluateState(DecoratedState actualstate, int amountOfAddedSwitch, double addedCableMeter, boolean moreInfromation);

	
	private void run() {
		cancel = false;
		control.guiDisable(true);
		runPrinter.openStream();
		runPrinter.println("");
		runPrinter.println("Start:" + stringStatFromActualState());
		runPrinter.closeStream();
		if(this.useStepping) {
			initParameterStepping();
			do {
					executeAlgoWithParameter();
					if(cancel) break;
					resetState();
			}while(updateOneParameter());
			resetParameterStepping();
		}else {
			executeAlgoWithParameter();
			
		}
		TopologieObjectiveFunction.log.clear();
		updateVisual();
		runProgressbar.finishedCancel();
		control.guiDisable(false);
	}
	@SuppressWarnings("rawtypes")
	private void initParameterStepping() {
		for(ParameterStepping param :this.parameterSteppingList) {
			param.init();
		}
		
	}
	@SuppressWarnings("rawtypes")
	private void resetParameterStepping() {
		for(ParameterStepping param :this.parameterSteppingList) {
			param.reset();
		}
		
	}




	@SuppressWarnings("rawtypes")
	private boolean updateOneParameter() {
		List<ParameterStepping> parameterInUseList = this.parameterSteppingList.stream().filter(param -> param.useThisParameter).collect(Collectors.toList());
		Collections.reverse(parameterInUseList);
		int lastParameter = parameterInUseList.size() - 1 ;
		int actualParameter = 0;
		for(ParameterStepping param : parameterInUseList) {
			
			if(param.canUpdate()) {
				param.update();
				return true;
			}else {
				if(actualParameter == lastParameter) break;
				param.reset();
			}
			actualParameter++;
		}
		//No Param can be updated 
		return false;
	}






	private void executeAlgoWithParameter(){
		double startFitness = evaluatePosition(extractPositionAndAccess());
		resetChain.removeLast();
		runPrinter.openStream();
		runPrinter.println("");
		runPrinter.println(algoInformationToPrint());
		runPrinter.closeStream();
		console.println(algoInformationToPrint());
		runProgressbar.start();
		Individual runBest = new Individual();
		runBest.fitness = Double.MAX_VALUE;
		for(int r = 0; r < rounds; r++)
		{	
			
			resetState();
			startTimer();
			Individual  roundBest = executeAlgo();
			if(cancel)return;
			long executionTime = printElapsedTime();
			setState(roundBest.position);
			runPrinter.openStream();
			runPrinter.println(runList.stream().map(Object::toString).collect(Collectors.joining(", ")));
			runPrinter.println(stringStatFromActualState());
			runPrinter.println("Result: " + roundBest.fitness + " ExecutionTime:" + executionTime);
			runPrinter.closeStream();
			
			if(roundBest.fitness < runBest.fitness) runBest = roundBest;
		}
		
		control.getSimManager().resetFlexManagerForTimeStep(control.getModel().getCurIteration());
		setState(runBest.position);
		for(HolonSwitch hSwitch: switchList) {
			hSwitch.setManualMode(true);
			hSwitch.setManualState(false);
		}
		updateVisual();
		evaluateNetworkAndPrint();
		console.println("Start: " + startFitness);
		console.println("AlgoResult: " + runBest.fitness);
	}
	
	







	protected abstract Individual executeAlgo();






	private void reset() {
		if(runThread.isAlive()) {
			console.println("Run have to be cancelled First.");
			return;
		}
		if(!resetChain.isEmpty()) {
			console.println("Resetting..");
			setState(resetChain.getFirst());
			resetChain.clear();
			control.resetSimulation();
			control.setCurIteration(0);
			updateVisual();
		}else {
			console.println("No run inistialized.");
		}
	}


	/**
	 * To let the User See the current state without touching the Canvas.
	 */
	private void updateVisual() {
		control.calculateStateAndVisualForCurrentTimeStep();
	}
	/**
	 * Sets the Model back to its original State before the LAST run.
	 */
	private void resetState() {
		if(!resetChain.isEmpty()) {
			setState(resetChain.removeLast());			
		}
		resetAllList();
	}


	/**
	 * Sets the State out of the given position for calculation or to show the user.
	 * @param position
	 */
	private void setState(List<Integer> position) {
		this.removeAllAddedObjects();
		for(int i = 0; i < this.amountOfNewCables; i++) {
			generateCable(position.get(2 * i), position.get(2 * i + 1), position.get(2 * amountOfNewCables + i) == 1);
		}
		//Switches new Cable
		//Switches existing cable
		int count = 0;
		for(int i = 3 * amountOfNewCables; i < 3 * this.amountOfNewCables + this.amountOfExistingCables; i++) {
			generateEdgeFromIndexCable(cableList.get(count++), position.get(i) == 1);
		}
		//WildCards
		count = 0;
		for(int i = 3 * amountOfNewCables + amountOfExistingCables; i < position.size(); i++) {
			accessWildcards.get(count++).setState(position.get(i));
		}
		for(HolonSwitch hSwitch: switchList) {
			hSwitch.setManualMode(true);
			hSwitch.setManualState(false);
		}
		control.calculateStateOnlyForCurrentTimeStep();
}


	/**
	 * Method to get the current Position alias a ListOf Booleans for aktive settings on the Objects on the Canvas.
	 * Also initialize the Access Hashmap to swap faster positions.
	 * @param model
	 * @return
	 */
	protected List<Integer> extractPositionAndAccess() {
		Model model = control.getModel();
		
		resetAllList();
		Category category = control.searchCategory("Wildcards");
		if(category != null) {
			for(int count = 0; count < category.getObjects().size(); count++ ) {
				accessIntegerToWildcard.put(count + 1, category.getObjects().get(count));
			}			
		}else {
			console.println("No 'Wildcards' Category");
		}
		
		
		
		List<Integer> initialState = new ArrayList<Integer>();
		generateAccess(model.getObjectsOnCanvas(), null);			
		addCables(model.getEdgesOnCanvas());
		model.getEdgesOnCanvas().clear();
		//New Cables
		for(int i = 0; i < this.amountOfNewCables; i++) {
			initialState.add(0);
			initialState.add(0);
		}
		//switch in new Cables
		for(int i = 0; i < this.amountOfNewCables; i++) {
			initialState.add(0);
		}
		//Switch in initial Cable
		cableSet.stream().forEach(indexCale -> initialState.add(0));
		amountOfExistingCables = cableSet.size();
		//wildcards
		for(int i = 0; i < accessWildcards.size(); i++) {
			initialState.add(0);
		}
		resetChain.add(initialState);
		//console.println(accessIntToObject.values().stream().map(hO -> hO.getName()).collect(Collectors.joining(", ")));
		//console.println(cableSet.stream().map(Object::toString).collect(Collectors.f(", ")));
		return initialState;
	}






	private void resetAllList() {
		//-->reset
		accessWildcards.clear();
		this.countForAccessMap = 0;
		amountOfExistingCables = 0;
		accessIntToObject.clear();
		accessObjectToInt.clear();
		cableSet.clear();
		cableList.clear();
		accessGroupNode.clear();
		accessIntegerToWildcard.clear();
		addedIndexCable.clear();
		switchList.clear();
		accessSwitchGroupNode.clear();
		edgeList.clear();
		//<---
	}
	
	
	
	
	/**
	 * Method to extract the Informations recursively out of the Model.
	 * @param nodes
	 * @param positionToInit
	 * @param timeStep
	 */
	private void generateAccess(List<AbstractCanvasObject> nodes, GroupNode groupnode) {
		for(AbstractCanvasObject aCps : nodes) {
			if(aCps instanceof HolonObject) {
				HolonObject hO = (HolonObject) aCps;
				accessIntToObject.put(++countForAccessMap, hO);
				accessObjectToInt.put(hO, countForAccessMap);
				if(hO.getName().contains("Wildcard")) {
					accessWildcards.add(new AccessWrapper(hO));
				}
				if(groupnode != null) {
					accessGroupNode.put(hO, groupnode);
				}
			}
			if(aCps instanceof HolonSwitch) {
				HolonSwitch hSwitch = (HolonSwitch) aCps;
				accessIntToObject.put(++countForAccessMap, hSwitch);
				accessObjectToInt.put(hSwitch, countForAccessMap);
				if(groupnode != null) {
					accessGroupNode.put(hSwitch, groupnode);
				}
			}
			if(aCps instanceof Node) {
				Node node = (Node) aCps;
				accessIntToObject.put(++countForAccessMap, node);
				accessObjectToInt.put(node, countForAccessMap);
				if(groupnode != null) {
					accessGroupNode.put(node, groupnode);
				}
			}
			else if(aCps instanceof GroupNode) {
				generateAccess(((GroupNode)aCps).getNodes(), (GroupNode) aCps);
			}
		}
	}
	
	
	protected void resetWildcards() {
		this.accessWildcards.forEach(wrapper -> wrapper.resetState());
	}
	/**
	 * All Nodes have to be in the access map !!
	 * @param cables
	 */
	private void addCables(List<Edge> edges) {
		
		for (Edge edge : edges) {
			edge.setUnlimitedCapacity(true);
			edgeList.add(edge);
			//console.println("Cable from " + edge.getA().getName() + " to " + edge.getB().getName());
			if(!accessObjectToInt.containsKey(edge.getA())) {
				console.println("Node A [" + edge.getA() + "] from Edge[" + edge + "] not exist");
				continue;
			} else if (!accessObjectToInt.containsKey(edge.getB())) {
				console.println("Node B [" + edge.getB() + "]from Edge[" + edge + "] not exist");
				continue;
			}
			IndexCable cable = new IndexCable(accessObjectToInt.get(edge.getA()), accessObjectToInt.get(edge.getB()));
			boolean success = cableSet.add(cable);
			if(success) {
				cableList.add(cable);
			}
			
		}
	}
	
	
	
	private void generateCable(int index0, int index1, boolean switchBetween) {
		//If cable isnt valid
		if(index0 == 0 || index1 == 0 || index0 == index1) {
			//console.println("Cable("+index1+","+index2+ ") isn't valid");
			return;
		}
		IndexCable cable = new IndexCable(index0, index1);
		//if cable is in existing cables
		if(cableSet.contains(cable) || addedIndexCable.keySet().contains(cable)) {
			return;
		}
		generateEdgeFromIndexCable(cable, switchBetween);
		addedIndexCable.put(cable, cable.getLength());
	}
	
	private void generateEdgeFromIndexCable(IndexCable cable, boolean switchBetween){
		if(switchBetween) {
			//generate Switch
			AbstractCanvasObject fromObject =  accessIntToObject.get(cable.first);
			AbstractCanvasObject toObject =  accessIntToObject.get(cable.second);
			int middleX = (fromObject.getPosition().x +   toObject.getPosition().x)/2;
			int middleY = (fromObject.getPosition().y +   toObject.getPosition().y)/2;
			HolonSwitch newSwitch = new HolonSwitch("AddedSwitch");
			newSwitch.setId(IdCounterElem.nextId());
			newSwitch.setPosition(middleX, middleY);
			//If fromObject is in Group
			if(accessGroupNode.containsKey(fromObject)) {
				GroupNode groupnode = accessGroupNode.get(fromObject);
				groupnode.getNodes().add(newSwitch);
				accessSwitchGroupNode.put(newSwitch, groupnode);
			} else if(accessGroupNode.containsKey(toObject)) {
				GroupNode groupnode = accessGroupNode.get(toObject);
				groupnode.getNodes().add(newSwitch);
				accessSwitchGroupNode.put(newSwitch, groupnode);
			}else {
				control.getModel().getObjectsOnCanvas().add(newSwitch);		
			}
			//else if toObject is in Group
			this.switchList.add(newSwitch);
			//Generate Cable From Object A To Switch
			Edge edge1 = new Edge(fromObject, newSwitch);
			edge1.setUnlimitedCapacity(true);
			control.getModel().getEdgesOnCanvas().add(edge1);
			edgeList.add(edge1);
			
			//Generate Cable From Object B To Switch
			Edge edge = new Edge(newSwitch, toObject);
			edge.setUnlimitedCapacity(true);
			control.getModel().getEdgesOnCanvas().add(edge);
			edgeList.add(edge);
			}else {
			Edge edge = new Edge(accessIntToObject.get(cable.first), accessIntToObject.get(cable.second));
			edge.setUnlimitedCapacity(true);
			control.getModel().getEdgesOnCanvas().add(edge);
			edgeList.add(edge);
		}
	}
	private void removeAllAddedObjects() {
		control.getModel().getEdgesOnCanvas().removeAll(edgeList);
		addedIndexCable.clear();
		//control.getModel().getObjectsOnCanvas().removeAll(switchList);
		for(HolonSwitch hSwitch: switchList) {
			if(this.accessSwitchGroupNode.containsKey(hSwitch)) {
				accessSwitchGroupNode.get(hSwitch).getNodes().remove(hSwitch);
			}
			else {
				control.getModel().getObjectsOnCanvas().remove(hSwitch);
			}
		}
		accessSwitchGroupNode.clear();
		switchList.clear();
		edgeList.clear();
	}
	
	
	private String stringStatFromActualState() {
		if(dGroupNode != null)
		{
			//GetActualDecoratedGroupNode
			dGroupNode = control.getSimManager().getActualVisualRepresentationalState().getCreatedGroupNodes().get(dGroupNode.getModel());
			int amountOfSupplier = dGroupNode.getAmountOfSupplier();
			int amountOfConsumer = dGroupNode.getAmountOfConsumer();
			int amountOfPassiv = dGroupNode.getAmountOfPassiv();
			int amountOfObjects = amountOfSupplier + amountOfConsumer + amountOfPassiv;
			int unSuppliedConsumer = dGroupNode.getAmountOfConsumerWithState(HolonObjectState.NOT_SUPPLIED);
			int partiallySuppliedConsumer = dGroupNode.getAmountOfConsumerWithState(HolonObjectState.PARTIALLY_SUPPLIED);
			int suppliedConsumer = dGroupNode.getAmountOfConsumerWithState(HolonObjectState.SUPPLIED);
			int overSuppliedConsumer = dGroupNode.getAmountOfConsumerWithState(HolonObjectState.OVER_SUPPLIED);
			
			
			int activeElements = dGroupNode.getAmountOfAktiveElemntsFromHolonObjects();
			int elements = dGroupNode.getAmountOfElemntsFromHolonObjects();
			return	"HolonObjects["
				+	" Producer: " + amountOfSupplier  + "/" + amountOfObjects + "("+ (float)amountOfSupplier/(float)amountOfObjects * 100 + "%)"
				+	" Unsupplied: " + unSuppliedConsumer  + "/" + amountOfObjects + "("+ (float)unSuppliedConsumer/(float)amountOfObjects * 100 + "%)"
				+	" PartiallySupplied: " + partiallySuppliedConsumer  + "/" + amountOfObjects + "("+ (float)partiallySuppliedConsumer/(float)amountOfObjects * 100 + "%)"
				+	" Supplied: " + suppliedConsumer  + "/" + amountOfObjects + "("+ (float)suppliedConsumer/(float)amountOfObjects * 100 + "%)"
				+	" Passiv: " + overSuppliedConsumer  + "/" + amountOfObjects + "("+ (float)overSuppliedConsumer/(float)amountOfObjects * 100 + "%)"
				+  "]" + "   HolonElemnts["
				+	" Active: " + activeElements  + "/" + elements + "("+ (float)activeElements/(float)elements * 100 + "%)"
				+ "]";
		}
		DecoratedState state = control.getSimManager().getActualDecorState();
		int amountOfSupplier = 0, amountOfConsumer = 0, amountOfPassiv = 0, unSuppliedConsumer = 0, partiallySuppliedConsumer = 0, suppliedConsumer = 0, overSuppliedConsumer = 0;
		int activeElements = 0, amountOfelements = 0;
		int totalConsumption = 0, totalProduction = 0;
		for(DecoratedNetwork net : state.getNetworkList()) {
			amountOfConsumer += net.getAmountOfConsumer();
			amountOfSupplier += net.getAmountOfSupplier();
			amountOfPassiv += net.getAmountOfPassiv();
			unSuppliedConsumer += net.getAmountOfConsumerWithState(HolonObjectState.NOT_SUPPLIED);
			partiallySuppliedConsumer += net.getAmountOfConsumerWithState(HolonObjectState.PARTIALLY_SUPPLIED);
			suppliedConsumer += net.getAmountOfConsumerWithState(HolonObjectState.SUPPLIED);
			overSuppliedConsumer += net.getAmountOfConsumerWithState(HolonObjectState.OVER_SUPPLIED);
			amountOfelements += net.getAmountOfElements();
			activeElements += net.getAmountOfActiveElements();
			totalConsumption += net.getTotalConsumption();
			totalProduction += net.getTotalProduction();
		}
		int amountOfObjects = amountOfSupplier + amountOfConsumer + amountOfPassiv;
		int difference = Math.abs(totalProduction - totalConsumption);
		
		
		
		int amountHolons = state.getNetworkList().size();
		int amountSwitch = state.getDecoratedSwitches().size();
		int amountActiveSwitch = (int)state.getDecoratedSwitches().stream().filter(dswitch -> (dswitch.getState() == SwitchState.Closed)).count();
		
		int addedSwitches = calculateAmountOfAddedSwitches();
		double addedCableMeters = addedCableMeter();
		double wildcardCost = TopologieObjectiveFunction.calculateWildcardCost(state);
		double cableCost = TopologieObjectiveFunction.calculateWildcardCost(state);
		double switchCost = TopologieObjectiveFunction.calculateWildcardCost(state);
		double totalCost = wildcardCost + cableCost + switchCost;
		
		DoubleSummaryStatistics overStat = state.getNetworkList().stream().flatMap(net -> {
			return net.getConsumerList().stream().filter(con -> con.getState() == HolonObjectState.OVER_SUPPLIED);
		}).mapToDouble(con -> con.getSupplyBarPercentage()).summaryStatistics();
		
		DoubleSummaryStatistics partiallyStat = state.getNetworkList().stream().flatMap(net -> {
			return net.getConsumerList().stream().filter(con -> con.getState() == HolonObjectState.PARTIALLY_SUPPLIED);
		}).mapToDouble(con -> con.getSupplyBarPercentage()).summaryStatistics();
		
		return	"HolonObjects["
			+ " Passiv: " + percentage(amountOfPassiv, amountOfObjects)
			+ " Producer: " + percentage(amountOfSupplier, amountOfObjects)
			+ " Consumer: " + percentage(amountOfConsumer, amountOfObjects)
			+ " Unsupplied: " + percentage(unSuppliedConsumer, amountOfConsumer)
			+ " PartiallySupplied: " + percentage(partiallySuppliedConsumer, amountOfObjects) 
			+ " with SupplyPercentage(Min: " + partiallyStat.getMin() 
			+ " Max: "+ partiallyStat.getMax() 
			+ " Average: " +partiallyStat.getAverage() +  ")"
			+ " Supplied: " + percentage(suppliedConsumer, amountOfConsumer)
			+ " Over: " + percentage(overSuppliedConsumer, amountOfConsumer)
			+ " with SupplyPercentage(Min: " + overStat.getMin() 
			+ " Max: "+ overStat.getMax() 
			+ " Average: " + overStat.getAverage() +  ")"
			+ "]" + "   HolonElemnts["
			+ " Active: " + percentage(activeElements, amountOfelements)
			+ "]" 
			+ " activeSwitches:" + percentage(amountActiveSwitch,amountSwitch)
			+ " Holons: " + amountHolons
			+ " totalConsumption: " + totalConsumption
			+ " totalProduction: " + totalProduction
			+ " difference: " + difference
			+ " Topologie["
			+ " addedCableMeters:" + addedCableMeters
			+ " addedSwitches: " + addedSwitches
			+ " totalCost: " + totalCost + "("
			+ " wildcardCost: " + wildcardCost
			+ " cableCost: " + cableCost
			+ " switchCost: " + switchCost
			+  ")]"
			;
		
	}
	
	
	private String percentage(int actual, int max) {
		return  actual  + "/" + max + "("+ (float)actual/(float)max * 100 + "%)";
	}
	

	
	@Override
	public JPanel getPanel() {
		return content;
	}

	@Override
	public void setController(Control control) {
		this.control = control;
	}
	
	//                 | New Cable          | Switches   | Wildcards             |
	//return index:    |  countForAccessMap | 1  		 | accessWildcards.size()|	
	public int getMaximumIndexObjects(int index) {
		int maximumIndex = -1;
		//New Cables
		if(index < 2 * amountOfNewCables) {
			maximumIndex =  this.countForAccessMap;
		}
		//Switches in existing and in new Cables
		else if (index < 3 * amountOfNewCables + this.amountOfExistingCables) {
			maximumIndex =  1;
		}
		//wildcards
		else {
			maximumIndex =  this.accessIntegerToWildcard.size();
		}
		return maximumIndex;
	}
	
	
	private class RunProgressBar{
		//progressbar
		private JProgressBar progressBar = new JProgressBar();
		private int count = 0;
		private boolean isActive = false;
		
		public void step() {
			if(isActive) progressBar.setValue(count++);
		}
		public void start() {
			progressBar.setIndeterminate(false);
			count = 0;
			isActive = true;
			progressBar.setValue(0);
			progressBar.setMaximum(getProgressBarMaxCount());
		}
		public void cancel() {
			isActive = false;
			progressBar.setIndeterminate(true);
		}
		public void finishedCancel() {
			progressBar.setIndeterminate(false);
			progressBar.setValue(0);
		}
		public JProgressBar getJProgressBar(){
			return progressBar;
		}
	}
	
	protected abstract int getProgressBarMaxCount();
	
	protected abstract String algoInformationToPrint();
	protected abstract String plottFileName();
	
	
	
	public class Printer{
		private JFileChooser fileChooser = new JFileChooser();
		private BufferedWriter out;
		public Printer(String filename){
			fileChooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
			fileChooser.setSelectedFile(new File(filename));
		}
		public void openStream() {
			File file = fileChooser.getSelectedFile();
			try {
				file.createNewFile();
				out = new BufferedWriter(new OutputStreamWriter(
					    new FileOutputStream(file, true), "UTF-8"));
			} catch (IOException e) {
				System.out.println(e.getMessage());
			}
		}
		
		
		public void println(String stringToPrint) {
			try {
				out.write(stringToPrint);
				out.newLine();
			} catch (IOException e) {
				System.out.println(e.getMessage());
			}
		}
		public void closeStream() {
			try {
				out.close();
			} catch (IOException e) {
				System.out.println(e.getMessage());
			}
		}
	}
		
	
	/**
	 * A Wrapper Class to access wildcards
	 */
	private class AccessWrapper {
		int state = 0;
		HolonObject wildcard;
		public AccessWrapper(HolonObject wildcard) {
			this.wildcard = wildcard;
		}
		
		public void setState(int state) {
			if(this.state !=  state) {
				this.state = state;
				if(state > 0) {
					wildcard.getElements().clear();
					HolonObject hO = (HolonObject)accessIntegerToWildcard.get(state);
					if(hO == null) {
						console.println("null set state(" + state + ")");
					}else {
						if(hO.getName().contains(":")) {
							wildcard.setName("Wildcard" + hO.getName().substring(hO.getName().lastIndexOf(":")));
						}else {
							wildcard.setName("Wildcard");
						}
						wildcard.getElements().addAll(hO.getElements());
						wildcard.setImage(hO.getImage());
					}
				}else {
					resetState();
				}
			}
		}
		public void resetState() {
			state = 0;
			wildcard.setName("Wildcard");
			wildcard.setImage("/Images/home-2.png");
			wildcard.getElements().clear();
		}
		
		public String toString() {
			return wildcard + "have state: " + state;
		}
	}
	
	
	
	
	private   class  Handle<T>{
		public T object;
		Handle(T object){
			this.object = object;
		}
		public String toString() {
			return object.toString();
		}
	}
	public class Individual {
		public double fitness;
		public  List<Integer> position;
		
		public Individual(){};
		/**
		 *  Copy Constructor
		 */
		public Individual(Individual c){
			position = c.position.stream().collect(Collectors.toList());
			fitness = c.fitness;
		}
	}
	
	protected class ParameterStepping<T>{
		boolean useThisParameter = false;
		String paramaterName;
		private int count = 0;
		int stepps;
		T stepSize;
		T startValue;
		Consumer<T> setter;
		Supplier<T> getter;
		BiFunction<Integer,T,T> multyply;
		BiFunction<T,T,T> add;
		ParameterStepping(Consumer<T> setter, Supplier<T> getter, BiFunction<T,T,T> add, BiFunction<Integer,T,T> multyply, T stepSize, int stepps){
			this.setter = setter;
			this.getter = getter;
			this.multyply = multyply;
			this.add = add;
			this.stepSize = stepSize;
			this.stepps = stepps;
		}
		
		void init() {
			startValue = getter.get();
		}
		
		boolean canUpdate() {
			return count  < stepps;
		}
		
		void update(){
			if(canUpdate()) {
				setter.accept(add.apply(startValue, multyply.apply(count + 1, stepSize)));
				count ++;
			}
		}
		
		void reset() {
			setter.accept(startValue);
			count = 0;
		}
	}
	
	
	
	
	
	public class IndexCable{
	    public final Integer first;
	    public final Integer second;

	    public IndexCable(Integer first, Integer second) {
	    	if(first.compareTo(second) == 0) {
	    		throw new IllegalArgumentException("(" + first + "==" + second + ")" 
	    							+ "Two ends of the cable are at the same Object");
	    	} else if(first.compareTo(second) < 0) {
	    		this.first = first;
	    		this.second = second;	    		
	    	}else {
	    		this.first = second;
	    		this.second = first;
	    	}
	    }

	    @Override
	    public boolean equals(Object o) {
	        if (!(o instanceof IndexCable)) {
	            return false;
	        }
	        IndexCable p = (IndexCable) o;
	        return Objects.equals(p.first, first) && Objects.equals(p.second, second);
	    }

	    @Override
	    public int hashCode() {
	        return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
	    }
	    @Override
	    public String toString() {
			return "{" + first + "," + second + "}";
	    }
	    public double getLength() {
	    	return accessIntToObject.get(first).getPosition().Distance(accessIntToObject.get(second).getPosition());
	    }
	}
}
