package ui.view;

import classes.*;

import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;

import interfaces.CategoryListener;
import interfaces.GraphEditable;
import interfaces.LocalMode;

import org.apache.commons.compress.archivers.ArchiveException;

import ui.controller.Control;
import ui.controller.SimulationManager;
import ui.controller.UpdateController;
import ui.model.DecoratedState;
import ui.model.Model;
import ui.model.Model.FairnessModel;
import ui.view.NewPopUp.Option;
import utility.ImageImport;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.plaf.ColorUIResource;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellRenderer;

import java.awt.*;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.*;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import java.util.Objects;
import java.util.Timer;
import java.util.TimerTask;
import java.util.stream.Collectors;

/**
 * Graphical User Interface.
 *
 * @author Gruppe14
 */
public class GUI implements CategoryListener {
	
	static final Color PALE_RED=new Color(255, 192, 192);
	
	/**
	 * Menu on the Top containing File, Edit View Help etc
	 */
	private final JMenuBar menuBar = new JMenuBar();
	private final JMenu mnNewMenu = new JMenu("File");
	private final JMenu mnNewMenuEdit = new JMenu("Edit");
	private final JMenu mnNewMenuOptions = new JMenu("Options");
	private final JMenu mnNewMenuView = new JMenu("View");
	private final JMenu menuWindow = new JMenu("Window");
	
	/** Help Menu containing helpful Informations and the AboutUs Popup */
	private final JMenu mnHelp = new JMenu("Help");
	
	/** 
	 * Help -> Introduction
	 * A small Introduction of the Application, SmartGrids and Holons 
	 */
	private final JMenuItem mntmIntroduction = new JMenuItem("Introduction");

	/** 
	 * Help -> UserManual
	 */
	private final JMenuItem mntmUserManual = new JMenuItem("User Manual");
	
	/** Help -> Algorithm Help Menu */
	private final JMenuItem mntmAlgorithmHelp = new JMenuItem("Algorithm Introduction");
	
	/** Help -> CodeDocumentation */
	private final JMenuItem mntmCodeDoc = new JMenuItem("Code Documentation");
	
	/** Help -> AboutUs */
	private final JMenuItem mntmAboutUs = new JMenuItem("About Us");
	
	
	
	private final JCheckBoxMenuItem consoleLogCheckBox = new JCheckBoxMenuItem(
			"Show program console log");
	private final JCheckBoxMenuItem useFlexibleDevicesCheckBox = new JCheckBoxMenuItem(
			"Automatically use flexible devices");
	/** checked if supplyBars should be shown */
	private final JCheckBoxMenuItem showSupplyBarsCheckBox = new JCheckBoxMenuItem(
			"Show supply bars.");
	private final JCheckBoxMenuItem showTooltipsCheckBox = new JCheckBoxMenuItem(
			"Show tooltips.");
	/** menu for the different fairness Models */
	private final JMenu mnFairnessModel = new JMenu("Fairness Model");
	/** press to supply minimum demand first */
	private final JMenuItem mntmFairMinFirst = new JMenuItem(
			"Minimum demand first");
	/** press to give everyone the same energy */
	private final JMenuItem mntmFairAlleEqual = new JMenuItem(
			"Equal supply for everyone");
	private final JMenuItem mntmOpen = new JMenuItem("Open");
	private final JMenuItem mntmNew = new JMenuItem("New");
	private final JMenuItem mntmSave = new JMenuItem("Save");
	private final JMenuItem mntmCanvasSize = new JMenuItem("Set View Size");
	private final JMenuItem mntmBackground = new JMenuItem("Background Image");
	private final JMenuItem mntmSplitView = new JMenuItem("Split View");
	private final JSplitPane splitPane = new JSplitPane();
	private final JSplitPane splitPane1 = new JSplitPane();
	// the tabbed canvas containing the different sub-net tabs of the grid (Main
	// Grid + Nodes of Nodes)
	
	private final JLabel lblHint = new JLabel("To connect two Objects use SHIFT + Left Mouse Button");
	private final JPanel myPanel = new JPanel(new BorderLayout());
	private final JTabbedPane tabbedPaneInnerOriginal = new JTabbedPane(
			JTabbedPane.TOP);
	// the main canvas where we can see the grid currently displayed
	private final JScrollPane canvasSP = new JScrollPane();
	private final JScrollPane scrollPane1 = new JScrollPane();
	// private final JScrollPane holonSP = new JScrollPane();
	// the original tabbed Pane (containing tabs for view, statistics, holon,
	// flexibility)
	private final JTabbedPane tabbedPaneOriginal = new JTabbedPane(
			JTabbedPane.TOP);
	// the same tabbed Pane that appears once the view is split
	private final JTabbedPane tabbedPaneSplit = new JTabbedPane(JTabbedPane.TOP);
	private final JPopupMenu popmenuEdit = new JPopupMenu();
	private final JMenuItem editItem = new JMenuItem("Edit Object");
	private final StatisticPanel statSplitPane;
	private final JScrollPane statScrollPane;
	private final JLabel maxGraph = new JLabel("100%");
	private final JLabel medGraph = new JLabel("50%");
	private final JLabel minGraph = new JLabel("0%");
	private final JLabel elementGraph = new JLabel("None ");
	private final ArrayList<HolonElement> selectedElements = new ArrayList<>();
	private final JTree tree = new JTree();
	/******************************************
	 ************* Right Container*************
	 ******************************************
	 * Right Container: here comes the information about the HolonObject, such
	 * as HolonElements Information, Properties and Consumption/Production
	 * graph.
	 **/
	private final JSplitPane splitHolonElPro = new JSplitPane(
			JSplitPane.VERTICAL_SPLIT);
	private final JSplitPane splitGraphHolonEl = new JSplitPane(
			JSplitPane.VERTICAL_SPLIT);
	private final int distanceBetweenElementsAndGraph = 350;
	// Model for single or multi selection
	private final JPanel scrollElements = new JPanel();
	private final JScrollPane tableHolonElementScrollPane = new JScrollPane();
	// In this section are all the properties that correspond to the clicked
	// HolonObject, such as connections, name, Type, etc.
	// Table for Properties --> Cell with (0,1) is editable by CpsObjt and
	// Cell(3,1) is editable by Edges
	private final JTable tableProperties = new JTable() {

		private static final long serialVersionUID = 1L;

		@Override
		public TableCellRenderer getCellRenderer(int row, int column) {
			if (getValueAt(row, column) instanceof Boolean) {
				return super.getDefaultRenderer(Boolean.class);
			} else {
				return super.getCellRenderer(row, column);
			}
		}

		@Override
		public TableCellEditor getCellEditor(int row, int column) {
			if (getValueAt(row, column) instanceof Boolean) {
				return super.getDefaultEditor(Boolean.class);
			} else {
				return super.getCellEditor(row, column);
			}
		}

	};
	//Prechoosed local Periods
	private String[] comboContext = {
	         "", "5", "10", "20" ,"100", "1000"
	};
	private JComboBox<String> localPeriodInput = new JComboBox<String>(comboContext);
	JButton resetButton = new JButton("", new ImageIcon(ImageImport.loadImage("/Images/resetIcon3.png")));
	ImageIcon localPeriodButtonImage = new ImageIcon(GrayFilter.createDisabledImage(ImageImport.loadImage("/Images/Graph.png")));
	private JButton localPeriodButton = new JButton("", localPeriodButtonImage);
	private final JPanel graphLabel = new JPanel();
	private final JScrollPane scrollProperties = new JScrollPane();
	// In this section is the graph for the selected HolonElement of the clicked
	// HolonObject
	private final JTable tableGraph = new JTable();
	private final DefaultTableModel tableModelGraph = new DefaultTableModel();
	private final JScrollPane scrollGraph = new JScrollPane();
	private final Model model;
	private final Control controller;

	// In this section are all the Holonelements that correspond to the clicked
	// HolonObject with consumption/production, name and amount.
	private final JPanel panel = new JPanel();
	private final JPanel panelHolonEl = new JPanel();
	// Buttons

	private final JButton btnAdd = new JButton("New");
	private final JPopupMenu btnAddPopUp = new JPopupMenu("New");
	private final JMenuItem mItemNew = new JMenuItem("New..");
	private final JMenuItem mItemCategory = new JMenuItem("Category");
	private final JMenuItem mItemObject = new JMenuItem("Object");
	private final JMenuItem mItemSwitch = new JMenuItem("Switch");
	private final JMenuItem mItemBattery = new JMenuItem("Battery");
	private final JButton btnDel = new JButton("Delete");
	private final JButton btnAddHolEL = new JButton("New Element");
	private final JButton btnDelHolEL = new JButton("Delete Element");
	private final JButton resetGraphBtn = new JButton("Reset");

	private final JToolBar toolBar = new JToolBar();
	private final JToolBar toolBarHolonEl = new JToolBar();
	private final JToolBar toolBarGraph = new JToolBar();
	// Languages
	private final JMenuItem englishBtn = new JMenuItem("EN");
	private final JMenuItem spanishBtn = new JMenuItem("ES");
	private final JMenuItem germanBtn = new JMenuItem("DE");
	private final JMenuItem czechBtn = new JMenuItem("CZ");
	private final JMenuItem chineseBtn = new JMenuItem("ZH");
	private final MyCanvas canvas;
	private final HolonCanvas holonCanvas;
	private final UnitGraph unitGraph;
	/** Textfield to show the period of an element */
	private final JTextField unitGraphLocalPeriod = new JTextField(6);
	private final JSplitPane splitPane3 = new JSplitPane();
	private final JSlider sizeSlider = new JSlider();
	private final JLabel lblImageSize = new JLabel(Languages.getLanguage()[94]);
	private final JMenuItem mntmUndo = new JMenuItem("Undo");
	private final JMenuItem mntmRedo = new JMenuItem("Redo");
	private final JMenuItem mntmEditEdges = new JMenuItem("Edge Properties");
	private final JMenuItem mntmFindReplace = new JMenuItem("Find/ Replace");
	private final JMenuItem mntmAlignAll = new JMenuItem("Align All");
	private final JMenuItem mntmEditShowedInformation = new JMenuItem(
			"Edit showed Information");
	private final JMenuItem mntmResetCategory = new JMenuItem(
			"Reset Categories");
	private final JMenu mnLanguage = new JMenu("Language");
	private final String[] columnNamesMulti = { "Object", "Nr.", "Device",
			"Energy", "Flexibility active", "Quantity", "Activated" };
	private final String[] columnNamesSingle = { "Nr.", "Device", "Energy",
			"Flexibility active", "Quantity", "Activated" };
	private final ArrayList<PropertyTable> tables = new ArrayList<>();
	private final String[] comboBoxCat = { "Category", "Object", "Switch", "Battery" };
	private final UpdateController updCon;
	private final JSplitPane splitPane_1 = new JSplitPane();
	private final JSlider holonBodySizeSlider = new JSlider();
	private final JLabel lblHolonBodySize = new JLabel("HolonBody SIze");
	private final JLabel lblSelectedElement = new JLabel("Selected Element: ");
	// for doubleclick
	private boolean click = false;
	private JFrame holegJFrame;
	private JTabbedPane tabTemp; // tabbedPaneOriginal or tabbedPaneSplit
	private JSplitPane tempSplit;
	private boolean initSplit = true;
	private String catOfObjToBeEdited;
	private GroupNodeCanvas unc;
	private JPanel contentPane;
	private String holonEleNamesDisplayed = "None ";
	// Pop up Windows
	private AddObjectPopUp addObjectPopUP;
	private AboutUsPopUp aboutUsPopUp;
	private AddElementPopUp addElementPopUp;
	// variables
	private boolean dragging = false;
	private String actualObjectClicked;
	private Image img = null;
	private AbstractCanvasObject tempCps = null;
	private int yValueElements = 0;
	// Time Stuff
	private TimePanel timePanel;
	public TimePanel getTimePanel() {
		return timePanel;
	}

	// Coord for all Cells with text
	private int yThis;
	private int xThis;
	// Coord for all Cells with boolean values (checkbox)
	private int yBTis;
	private int xBThis;
	// Coord for the Edit-Modus in the PropertieTable
	private int yProThis;
	private int xProThis;
	private int yProThisOneClick;
	private int xProThisOneClick;
	private AbstractCanvasObject temp = null;
	private String warningText = "Warning";
	private String saveBeforeNew = "Do you want to save your current data?";
	private String eraseCategory = "Do you really want to delete the Category ";
	private String selectObjBeforeErase = "Please select a Category or an Object in the left library in order to delete something.";

	
	private List<Outliner> outlinerList = new ArrayList<Outliner>();
	private List<FlexWindow> flexList = new ArrayList<FlexWindow>();

	private JMenuItem removeItem = new JMenuItem("Remove");

	
	/**
	 * Create the application.
	 *
	 * @param control
	 *            the Controller
	 */
	GUI(Control control) {
		this.controller = control;
		this.model = control.getModel();
		control.setGui(this);
		statSplitPane = new StatisticPanel(controller);
		model.addGraphListener(statSplitPane);
		model.setStatPanel(statSplitPane);
		statScrollPane = new JScrollPane(statSplitPane);
		this.unitGraph = new UnitGraph(model, control);
		this.canvas = new MyCanvas(model, control, unitGraph);
		this.holonCanvas = new HolonCanvas(model, control);

		control.initListener(this);
		model.setTableProperties(tableProperties);
		initialize();
		updateCategories(model.getCategories());
		updCon = new UpdateController(model, controller);
	}


	/**
	 * Initialize the contents of the frame.
	 */
	@SuppressWarnings({ "serial", "unchecked" })
	private void initialize() {
		holegJFrame = new JFrame();
		holegJFrame.setTitle("HOLEG Simulator");
		// try to restore old position/dimensions
		ArrayList<Integer> savedWindowDim = controller
				.loadSavedWindowDimensionsIfExistent();
		if (savedWindowDim.size() == 4) {
			holegJFrame.setBounds(savedWindowDim.get(0),
					savedWindowDim.get(1), savedWindowDim.get(2),
					savedWindowDim.get(3));
		}

		// if the upper part of the window is showing, the windows can still be
		// moved,
		// but if it is not, we need to move it to somewhere else
		if (savedWindowDim.size() != 4 || !isUpperPanelInsideBounds()) {
			holegJFrame.setBounds(100, 100, 1000, 800);
			holegJFrame.setExtendedState(JFrame.MAXIMIZED_BOTH);
		}
		holegJFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

		holegJFrame.addWindowListener(new java.awt.event.WindowAdapter() {
			@Override
			public void windowClosing(java.awt.event.WindowEvent windowEvent) {
				if (JOptionPane.showConfirmDialog(holegJFrame,
						Languages.getLanguage()[88],
						"HOLEG",
						JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
					controller.deleteDirectory(new File(System
							.getProperty("user.home")
							+ "/.config/HolonGUI/Autosave"));

					// try to save the position and size of the window, such
					// that (if possible)
					// it can be opened in the same position the next time
					try {
						controller.savePosAndSizeOfWindow(
								holegJFrame.getX(),
								holegJFrame.getY(),
								holegJFrame.getWidth(),
								holegJFrame.getHeight());
					} catch (Exception e) {
						e.printStackTrace();
					}
					System.exit(1);
				}
				System.exit(0);
			}
		});

		contentPane = (JPanel) holegJFrame.getContentPane();

		int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
		InputMap inputMap = contentPane.getInputMap(condition);
		ActionMap actionMap = contentPane.getActionMap();

		String cntrlZDown = "controlZ";
		inputMap.put(KeyStroke.getKeyStroke("control Z"), cntrlZDown);
		actionMap.put(cntrlZDown, new AbstractAction() {

			private static final long serialVersionUID = 1L;

			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					controller.loadAutoSave(controller.getUndoSave());
					closeInvalidUpperNodeTabs();
					
					controller.calculateStateAndVisualForCurrentTimeStep();
					canvas.repaint();
					unitGraph.update(model.getObjectsOnCanvas());
					updateUpperNodes();
				} catch (IOException eex) {
					eex.printStackTrace();
				}
			}
		});

		String cntrlYDown = "controlY";
		inputMap.put(KeyStroke.getKeyStroke("control Y"), cntrlYDown);
		actionMap.put(cntrlYDown, new AbstractAction() {

			private static final long serialVersionUID = 1L;

			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					controller.loadAutoSave(controller.getRedoSave());

					closeInvalidUpperNodeTabs();
					
					controller.calculateStateAndVisualForCurrentTimeStep();
					canvas.repaint();
					unitGraph.update(model.getObjectsOnCanvas());
					updateUpperNodes();
				} catch (IOException ex) {
					ex.printStackTrace();
				}
			}
		});

		String cntrlADown = "controlA";
		inputMap.put(KeyStroke.getKeyStroke("control A"), cntrlADown);
		AbstractAction controlA = new AbstractAction() {
			private static final long serialVersionUID = 1L;

			@Override
			public void actionPerformed(ActionEvent e) {
				chooseTabTemp();

				model.getSelectedCpsObjects().clear();

				// Uppernode Canvas?
				JScrollPane scrollPane = getScrollPaneFromTabbedPane();
				Component canvasOrUpperNodeCanvas = scrollPane.getViewport()
						.getComponent(0);

				if (canvasOrUpperNodeCanvas instanceof GroupNodeCanvas) {
					GroupNodeCanvas uNC = (GroupNodeCanvas) canvasOrUpperNodeCanvas;
					for (AbstractCanvasObject cps : uNC.upperNode.getNodes()) {
						controller.addSelectedObject(cps);
					}
					uNC.repaint();
					// or Canvas?
				} else if (canvasOrUpperNodeCanvas instanceof MyCanvas) {
					for (AbstractCanvasObject cps : model.getObjectsOnCanvas()) {
						controller.addSelectedObject(cps);
					}
					canvas.repaint();
				}
				controller.getObjectsInDepth();

			}
		};
		actionMap.put(cntrlADown, controlA);

		String delDown = "delete";
		inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0, false),
				delDown);
		actionMap.put(delDown, new AbstractAction() {

			private static final long serialVersionUID = 1L;

			@Override
			public void actionPerformed(ActionEvent e) {
				chooseTabTemp();

				// Uppernode Canvas?
				JScrollPane scrollPane = getScrollPaneFromTabbedPane();
				Component canvasOrUpperNodeCanvas = scrollPane.getViewport()
						.getComponent(0);

				// check whether a producer was deleted (this triggers a
				// complete re-evaluation of the net)
				boolean wasProducerDeleted = true;

				if (canvasOrUpperNodeCanvas instanceof GroupNodeCanvas) {
					GroupNodeCanvas uNC = (GroupNodeCanvas) canvasOrUpperNodeCanvas;
					for (AbstractCanvasObject cps : model.getSelectedCpsObjects()) {


						controller.removeTrackingObj(cps);
						if (uNC.upperNode.getNodes().contains(cps)) {
							controller.delObjUpperNode(cps, uNC.upperNode);
							unc.setToolTip(false);

							// remove UpperNodeTab if UpperNode deleted
							removeUpperNodeTab(cps);
						}
					}
					uNC.repaint();

					// or Canvas?
				} else if (canvasOrUpperNodeCanvas instanceof MyCanvas) {
					boolean save = false;
					// Edge Deleting
					Edge edgeHighlight = model.getSelectedEdge();
					if (edgeHighlight != null) {
						controller.removeEdgesOnCanvas(edgeHighlight);
						((MyCanvas) canvasOrUpperNodeCanvas).edgeHighlight = null;
					}
					for (int j = 0; j < model.getSelectedCpsObjects().size(); j++) {
						AbstractCanvasObject cps = model.getSelectedCpsObjects()
								.get(j);

					

						controller.removeTrackingObj(cps);
						if (j < model.getSelectedCpsObjects().size() - 1)
							save = true;
						controller.delCanvasObject(cps, save);
						canvas.setToolTip(false);

						// remove UpperNodeTab if UpperNode deleted
						removeUpperNodeTab(cps);
					}
					canvas.repaint();
				}

				// recalculate net if a producer was deleted
				if (wasProducerDeleted) {
					controller.resetSimulation();
					controller.calculateStateAndVisualForCurrentTimeStep();
				}

				model.getSelectedCpsObjects().clear();
				hideScrollGraph();
			}
		});

		String cntrlFDown = "controlF";
		inputMap.put(KeyStroke.getKeyStroke("control F"), cntrlFDown);
		actionMap.put(cntrlFDown, new AbstractAction() {

			private static final long serialVersionUID = 1L;

			@Override
			public void actionPerformed(ActionEvent e) {
				SearchPopUp dialog = new SearchPopUp(controller, canvas,
						holegJFrame);
				dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
				dialog.setVisible(true);
			}
		});

		String cntrlCDown = "controlC";
		inputMap.put(KeyStroke.getKeyStroke("control C"), cntrlCDown);
		AbstractAction controlC = new AbstractAction() {
			private static final long serialVersionUID = 1L;

			@Override
			public void actionPerformed(ActionEvent e) {
				chooseTabTemp();

				JScrollPane scrollPane = getScrollPaneFromTabbedPane();
				if (!model.getSelectedCpsObjects().isEmpty()) {
					if (scrollPane.getViewport().getComponent(0) instanceof GroupNodeCanvas)
						controller.copy(((GroupNodeCanvas) scrollPane
								.getViewport().getComponent(0)).upperNode);
					else
						controller.copy(null);
					if (!model.getClipboradObjects().isEmpty()) {
						canvas.itemPaste.setEnabled(true);
					}
				}
			}
		};
		actionMap.put(cntrlCDown, controlC);

		String cntrlVDown = "controlV";
		inputMap.put(KeyStroke.getKeyStroke("control V"), cntrlVDown);
		AbstractAction controlV = new AbstractAction() {
			private static final long serialVersionUID = 1L;

			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					tabTemp = null;
					if (tabbedPaneOriginal.getMousePosition() != null) {
						tabTemp = tabbedPaneOriginal;
					} else {
						if (!initSplit) {
							tabTemp = tabbedPaneSplit;
						}
					}

					if(tabTemp == null)return;
					JScrollPane scrollPane = getScrollPaneFromTabbedPane();
					Component canvasOrUpperNodeCanvas = scrollPane
							.getViewport().getComponent(0);

					if (tabTemp != null
							&& canvasOrUpperNodeCanvas instanceof GroupNodeCanvas) {

						controller
								.paste(((GroupNodeCanvas) canvasOrUpperNodeCanvas).upperNode,
										canvasOrUpperNodeCanvas
												.getMousePosition());
						unitGraph.update(model.getSelectedCpsObjects());
						controller.calculateStateAndVisualForCurrentTimeStep();
						scrollPane.getViewport().getComponent(0).repaint();
					} else {
						controller.paste(null, canvas.getMousePosition());
						unitGraph.update(model.getSelectedCpsObjects());
						controller.calculateStateAndVisualForCurrentTimeStep();
						canvas.repaint();
					}
				} catch (HeadlessException | JsonParseException
						| UnsupportedFlavorException | IOException e1) {
					JLabel message = new JLabel(
							"The Clipboard information cannot be pasted into Application.");
					JOptionPane.showMessageDialog(holegJFrame, message,
							"", JOptionPane.ERROR_MESSAGE);
				}

			}
		};
		actionMap.put(cntrlVDown, controlV);

		String cntrlXDown = "controlX";
		inputMap.put(KeyStroke.getKeyStroke("control X"), cntrlXDown);
		AbstractAction controlX = new AbstractAction() {
			private static final long serialVersionUID = 1L;

			@Override
			public void actionPerformed(ActionEvent e) {
				chooseTabTemp();

				JScrollPane scrollPane = getScrollPaneFromTabbedPane();
				if (!model.getSelectedCpsObjects().isEmpty()) {
					if (scrollPane.getViewport().getComponent(0) instanceof GroupNodeCanvas) {
						controller.cut(((GroupNodeCanvas) scrollPane
								.getViewport().getComponent(0)).upperNode);
						controller.calculateStateAndVisualForCurrentTimeStep();
						scrollPane.getViewport().getComponent(0).repaint();
					} else {
						controller.cut(null);
						controller.calculateStateAndVisualForCurrentTimeStep();
						canvas.repaint();
					}
					if (!model.getClipboradObjects().isEmpty()) {
						canvas.itemPaste.setEnabled(true);
					}
				}
			}
		};
		actionMap.put(cntrlXDown, controlX);

		holegJFrame.setJMenuBar(menuBar);

		holegJFrame.setIconImage(ImageImport.loadImage(
				"/Images/Holeg.png", 30, 30));

		menuBar.add(mnNewMenu);

		mnNewMenu.add(mntmNew);

		mnNewMenu.add(mntmOpen);

		mnNewMenu.add(mntmSave);

		menuBar.add(mnNewMenuEdit);

		mnNewMenuEdit.add(mntmUndo);

		mnNewMenuEdit.add(mntmRedo);

		mnLanguage.add(englishBtn);
		englishBtn.setIcon(new ImageIcon(new ImageIcon(
				"res/Button_Images/FlagEN.png").getImage().getScaledInstance(
				20, 20, java.awt.Image.SCALE_SMOOTH)));
		mnLanguage.add(spanishBtn);
		spanishBtn.setIcon(new ImageIcon(new ImageIcon(
				"res/Button_Images/FlagES.png").getImage().getScaledInstance(
				20, 20, java.awt.Image.SCALE_SMOOTH)));
		mnLanguage.add(germanBtn);
		germanBtn.setIcon(new ImageIcon(new ImageIcon(
				"res/Button_Images/FlagDE.png").getImage().getScaledInstance(
				20, 20, java.awt.Image.SCALE_SMOOTH)));
		// mnLanguage.add(czechBtn);
		// czechBtn.setIcon(new ImageIcon(new
		// ImageIcon("res/Button_Images/FlagCZ.png").getImage().getScaledInstance(20,
		// 20, java.awt.Image.SCALE_SMOOTH)));
		mnLanguage.add(chineseBtn);
		chineseBtn.setIcon(new ImageIcon(new ImageIcon(
				"res/Button_Images/FlagZH.png").getImage().getScaledInstance(
				20, 20, java.awt.Image.SCALE_SMOOTH)));

		mntmFindReplace.addActionListener(actionEvent -> {
			try {
				SearchPopUp dialog = new SearchPopUp(controller, canvas,
						holegJFrame);
				dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
				dialog.setVisible(true);
				controller.getObjectsInDepth();
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		});

		mnNewMenuEdit.add(mntmFindReplace);
		mntmEditShowedInformation
				.addActionListener(actionEvent -> {
					try {
						DisplayedInformationPopUp dialog = new DisplayedInformationPopUp(
								canvas, contentPane, controller,
								holegJFrame);
						dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
						dialog.setVisible(true);
					} catch (Exception ex) {
						ex.printStackTrace();
					}
				});
	
		
		mnNewMenuEdit.add(mntmEditShowedInformation);
		mnNewMenuEdit.add(mntmEditEdges);
		mntmEditEdges.addActionListener(actionEvent -> {
			EditEdgesPopUp edgePopUp = new EditEdgesPopUp(holegJFrame);
			edgePopUp.setCanvas(canvas);
			edgePopUp.setController(controller);
			edgePopUp.setVisible(true);
		});
		
		
		//Edit -> Align All
		
		mnNewMenuEdit.add(mntmAlignAll);
		mntmAlignAll.addActionListener(actionEvent -> {
			// getScrollPaneFromTabbedPane().getViewport().getComponent(0) is always the active canvas
			AbstractCanvas activeCanvas = ((AbstractCanvas) getScrollPaneFromTabbedPane().getViewport().getComponent(0));
			if (activeCanvas != null) {
				activeCanvas.tryToAlignObjects();
				activeCanvas.repaint();
			}
		});
		
		
		menuBar.add(mnNewMenuOptions);

		mnNewMenuOptions.add(mntmResetCategory);
		mntmResetCategory.addActionListener(actionEvent -> {
			ArrayList<Category> cat = model.getCategories();
			try {
				while (!cat.isEmpty()) {
					controller.deleteCategory(cat.get(0).getName());

				}
				controller.resetCategorys();
			} catch (Exception e2) {
				System.out.println(e2.getMessage());
			}

			tree.repaint();
		});


		mnNewMenuOptions.add(useFlexibleDevicesCheckBox);
		useFlexibleDevicesCheckBox.setSelected(true);
		useFlexibleDevicesCheckBox
				.addActionListener(actionEvent -> model
						.setUseFlexibleDevices(useFlexibleDevicesCheckBox
								.isSelected()));

		/**
		 * Add Fairness Model Option to the option Menu
		 */
		mnNewMenuOptions.add(mnFairnessModel);

		mnFairnessModel.add(mntmFairMinFirst);
		mntmFairMinFirst.setForeground(Color.BLUE);
		mntmFairMinFirst
				.setToolTipText("HolonObjects with the smallest mininum Demand will be partially supplied first.\n"
						+ "After that as many HolonObjects as possible will get fully supplied.");

		mntmFairMinFirst
				.addActionListener(arg0 -> {
					controller.setFairnessModel(FairnessModel.MininumDemandFirst);
					mntmFairMinFirst.setForeground(Color.BLUE);
					mntmFairAlleEqual.setForeground(mnFairnessModel
							.getForeground());
					controller.calculateStateAndVisualForCurrentTimeStep();
					// Update UpperNodes
					Component canvasOrUpperNodeCanvas = getScrollPaneFromTabbedPane()
							.getViewport().getComponent(0);
					if (canvasOrUpperNodeCanvas != null
							&& canvasOrUpperNodeCanvas instanceof GroupNodeCanvas) {
						((GroupNodeCanvas) canvasOrUpperNodeCanvas).repaint();
					}
				});

		mnFairnessModel.add(mntmFairAlleEqual);
		mntmFairAlleEqual
				.setToolTipText("HolonObjects will all get the same amount of energy.");

		mntmFairAlleEqual.addActionListener(arg0 -> {
			controller.setFairnessModel(FairnessModel.AllEqual);
			mntmFairAlleEqual.setForeground(Color.BLUE);
			mntmFairMinFirst.setForeground(mnFairnessModel.getForeground());
			controller.calculateStateAndVisualForCurrentTimeStep();
			// Update UpperNodes
				Component canvasOrUpperNodeCanvas = getScrollPaneFromTabbedPane()
						.getViewport().getComponent(0);
				if (canvasOrUpperNodeCanvas != null
						&& canvasOrUpperNodeCanvas instanceof GroupNodeCanvas) {
					((GroupNodeCanvas) canvasOrUpperNodeCanvas).repaint();
				}
			});

		menuBar.add(mnNewMenuView);

		mnNewMenuView.add(mntmCanvasSize);
		mntmCanvasSize.addActionListener(actionEvent -> {
			CanvasResizePopUp popUp = new CanvasResizePopUp(model, controller,
					canvas, tabbedPaneOriginal, tabbedPaneSplit,
					holegJFrame);
			popUp.setVisible(true);
		});
		
		mnNewMenuView.add(splitPane3);

		sizeSlider.setMinimum(15);
		sizeSlider.setMaximum(115);
		sizeSlider
				.addChangeListener(changeEvent -> {
					controller.setScale(sizeSlider.getValue());

					JScrollPane scrollPane = getScrollPaneFromTabbedPane();

					if (scrollPane.getViewport().getComponent(0) instanceof GroupNodeCanvas) {
						scrollPane.getViewport().getComponent(0).repaint();
					} else {
						canvas.repaint();
					}
					if (!initSplit
							&& scrollPane.getViewport().getComponent(0) instanceof GroupNodeCanvas) {
						scrollPane.getViewport().getComponent(0).repaint();
					} else {
						canvas.repaint();
					}
				});

		mnNewMenuView.add(mntmCanvasSize);
		mnNewMenuView.add(mntmSplitView);

		/*
		 * Adds Checkbox to turn supply bars on/off
		 */
		mnNewMenuView.add(showSupplyBarsCheckBox);
		showSupplyBarsCheckBox.setSelected(true);
		showSupplyBarsCheckBox.addActionListener(arg0 -> {
			controller.setShowSupplyBars(showSupplyBarsCheckBox.isSelected());

			canvas.repaint();

			// Update UpperNodes
				JScrollPane spane = getScrollPaneFromTabbedPane();
				if(spane != null){
					Component canvasOrUpperNodeCanvas = spane.getViewport().getComponent(0);
					if (canvasOrUpperNodeCanvas != null
							&& canvasOrUpperNodeCanvas instanceof GroupNodeCanvas) {
						((GroupNodeCanvas) canvasOrUpperNodeCanvas).repaint();
					}
				}
			});
		
		mnNewMenuView.add(showTooltipsCheckBox);
		showTooltipsCheckBox.setSelected(true);
		showTooltipsCheckBox.addActionListener(arg0 -> {
			showHint(showTooltipsCheckBox.isSelected());
			});
		initWindowMenu();
		// Split View
		mntmSplitView
				.addActionListener(actionEvent -> {
					for (int i = 0; i < tabbedPaneOriginal.getTabCount(); i++) {
						// add outer tabs
						// (inner tabs are added by tabbedPaneSplit
						// changelistener)
						tabbedPaneSplit.addTab(
								tabbedPaneOriginal.getTitleAt(i), null);
					}
					if (tabbedPaneOriginal.getSelectedComponent() == statScrollPane) {
						tabbedPaneOriginal.setComponentAt(0, null);
						tabbedPaneSplit.setComponentAt(0, canvasSP);
						tabbedPaneSplit.setSelectedIndex(0);
					} else {
						tabbedPaneOriginal.setComponentAt(1, null);
						tabbedPaneSplit.setComponentAt(1, statScrollPane);
						tabbedPaneSplit.setSelectedIndex(1);
					}
					tempSplit = new JSplitPane();
					tempSplit.setBorder(null);
					tempSplit.setRightComponent(tabbedPaneSplit);
					tempSplit.setLeftComponent(tabbedPaneOriginal);
					tempSplit.setDividerLocation(tabbedPaneOriginal
							.getWidth() / 2);
					tempSplit.setResizeWeight(0.9);
					initSplit = false;
				
					contentPane.updateUI();
				});
		
		
		
		
		mnNewMenuView.add(mntmBackground);

		mntmBackground
				.addActionListener(actionEvent -> {
					tabTemp = tabbedPaneOriginal;
					JScrollPane scrollPane = getScrollPaneFromTabbedPane();

					if (scrollPane.getViewport().getComponent(0) instanceof MyCanvas) {
						BackgroundPopUp backgroundDialog = new BackgroundPopUp(
								model, controller, canvas, null,
								holegJFrame);
						backgroundDialog
								.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
						backgroundDialog.setVisible(true);
					} else if (scrollPane.getViewport().getComponent(0) instanceof GroupNodeCanvas) {
						GroupNodeCanvas uNodeCanvas = (GroupNodeCanvas) (scrollPane
								.getViewport().getComponent(0));
						BackgroundPopUp backgroundDialog = new BackgroundPopUp(
								model, controller, null, uNodeCanvas.upperNode,
								holegJFrame);
						backgroundDialog
								.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
						backgroundDialog.setVisible(true);
						uNodeCanvas.repaint();
					}
				});

		splitPane3.setRightComponent(sizeSlider);

		splitPane3.setLeftComponent(lblImageSize);

		mnNewMenuView.add(splitPane_1);
		holonBodySizeSlider.setValue(100);
		holonBodySizeSlider.setMinimum(1);

		holonBodySizeSlider.addChangeListener(changeEvent -> {
			controller.setHolonBodyScale(holonBodySizeSlider.getValue());
			tree.setRowHeight(50);
			canvas.repaint();
		});

		splitPane_1.setRightComponent(holonBodySizeSlider);

		splitPane_1.setLeftComponent(lblHolonBodySize);


		/**
		 * add Help Menu and its items
		 */
		menuBar.add(mnHelp);
		mnHelp.add(mntmIntroduction); 
		mnHelp.add(mntmUserManual); 
		mnHelp.add(mntmAlgorithmHelp); 
		mnHelp.add(mntmCodeDoc);
		mnHelp.add(mntmAboutUs);

		tabbedPaneOriginal.addChangeListener(changeEvent -> {
			if (tabbedPaneOriginal.getSelectedComponent() == null) {
				Component tempC = tabbedPaneSplit.getSelectedComponent();
				tabbedPaneSplit.setComponentAt(
						tabbedPaneOriginal.getSelectedIndex(), null);
				tabbedPaneOriginal.setComponentAt(
						tabbedPaneOriginal.getSelectedIndex(), tempC);
				tempC = tabbedPaneOriginal.getComponentAt((tabbedPaneOriginal
						.getSelectedIndex() + 1)
						% (tabbedPaneOriginal.getTabCount()));
				tabbedPaneOriginal.setComponentAt(
						(tabbedPaneOriginal.getSelectedIndex() + 1)
								% (tabbedPaneOriginal.getTabCount()), null);
				tabbedPaneSplit.setComponentAt(
						(tabbedPaneOriginal.getSelectedIndex() + 1)
								% (tabbedPaneOriginal.getTabCount()), tempC);
				tabbedPaneSplit.setSelectedIndex((tabbedPaneOriginal
						.getSelectedIndex() + 1)
						% (tabbedPaneOriginal.getTabCount()));
				contentPane.updateUI();
			}
		});

		tabbedPaneSplit.addChangeListener(changeEvent -> {
			if (tabbedPaneSplit.getSelectedComponent() == null && !initSplit) {
				Component tempC = tabbedPaneOriginal
						.getComponentAt(tabbedPaneSplit.getSelectedIndex());
				tabbedPaneOriginal.setComponentAt(
						tabbedPaneSplit.getSelectedIndex(), null);
				tabbedPaneSplit.setComponentAt(
						tabbedPaneSplit.getSelectedIndex(), tempC);

				for (int i = 0; i < tabbedPaneOriginal.getTabCount(); i++) {
					if (tabbedPaneSplit.getComponentAt(i) != null
							&& tabbedPaneSplit.getComponentAt(i) != tempC) {
						tempC = tabbedPaneSplit.getComponentAt(i);
						tabbedPaneSplit.setComponentAt(i, null);
						tabbedPaneOriginal.setComponentAt(i, tempC);
						break;
					}
				}
				if (tabbedPaneOriginal.getSelectedIndex() == tabbedPaneSplit
						.getSelectedIndex()) {
					tabbedPaneOriginal.setSelectedIndex((tabbedPaneSplit
							.getSelectedIndex() + 1)
							% tabbedPaneOriginal.getTabCount());
				}
				contentPane.updateUI();
			}
		});

		mnNewMenuOptions.add(mnLanguage);
		canvas.setBackground(Color.WHITE);
		canvas.setPreferredSize(new Dimension(model.getCanvasX(), model
				.getCanvasY()));
		holonCanvas.setBackground(Color.WHITE);
		holonCanvas.setPreferredSize(new Dimension(model.getCanvasX(), model
				.getCanvasY()));

		/********************
		 * RIGHT CONTAINER (INFORMATION)
		 **********************/
		// Set up of the HolonElements section
		// Two different Models: Multi for multi-selection mode and Single for
		// single-selection mode (CPS-Object)
		model.getMultiTable().setColumnIdentifiers(columnNamesMulti);
		model.getSingleTable().setColumnIdentifiers(columnNamesSingle);
		model.getTableHolonElement().setBorder(null);
		model.getTableHolonElement().setFillsViewportHeight(true);
		model.getTableHolonElement().setCellSelectionEnabled(true);
		model.getTableHolonElement().setColumnSelectionAllowed(true);
		/*
		 * Register Clicks on ColumNames for sorting:
		 */
		model.getTableHolonElement().getTableHeader()
				.addMouseListener(new MouseAdapter() {
					public void mouseClicked(MouseEvent e) {
						//TODO: sort
						//clicked column
						int col = model.getTableHolonElement().columnAtPoint(
								e.getPoint());
						//insert column into UpdateController
						updCon.setSortBy(col);
						//refresh HolonElementTable
						updCon.refreshTableHolonElement(model.getMultiTable(), model.getSingleTable());
					}
					

					@Override
					public void mouseExited(MouseEvent e) {
						/**
						 * Stop Editing, if mouse exits the Table
						 */
						JTable holElem = model.getTableHolonElement();
						JTableHeader holElemHead = holElem.getTableHeader();
						if(e.getX()<=0 || e.getX()>=holElemHead.getWidth() 
								|| e.getY() <= 0){
							CellEditor cellEditor = holElem.getCellEditor();
							if (cellEditor != null) {
							    if (cellEditor.getCellEditorValue() != null) {
							    	/** TODO: Maybe try to save current Data */
							        cellEditor.stopCellEditing();
							    } else {
							        cellEditor.cancelCellEditing();
							    }
							}
						}
						
					}
				});
		model.getTableHolonElement().getTableHeader().setReorderingAllowed(false);

		tableHolonElementScrollPane.setViewportView(model
				.getTableHolonElement());
		scrollElements.setLayout(new BorderLayout(0, 0));
		scrollElements.add(panelHolonEl, BorderLayout.NORTH);
		scrollElements.add(tableHolonElementScrollPane);
		panelHolonEl.setLayout(new BoxLayout(panelHolonEl, BoxLayout.X_AXIS));
		toolBarHolonEl.add(btnAddHolEL);
		toolBarHolonEl.add(btnDelHolEL);
		toolBarHolonEl.setFloatable(false);
		panelHolonEl.add(toolBarHolonEl);

		// Set up of the Properties section
		tableProperties.setModel(model.getPropertyTable());
		tableProperties.setFillsViewportHeight(true);
		tableProperties.setCellSelectionEnabled(true);
		tableProperties.setColumnSelectionAllowed(true);
		scrollProperties.setViewportView(tableProperties);

		// Set up of the Graph section
		tableGraph.setModel(tableModelGraph);
		tableGraph.setFillsViewportHeight(true);
		tableGraph.setCellSelectionEnabled(true);
		tableGraph.setColumnSelectionAllowed(true);
		scrollGraph.setViewportView(unitGraph);
		graphLabel.setLayout(new BorderLayout(0, 10));
		graphLabel.add(maxGraph, BorderLayout.NORTH);
		graphLabel.add(medGraph, BorderLayout.CENTER);
		graphLabel.add(minGraph, BorderLayout.SOUTH);

		
		
		
		
		toolBarGraph.setFloatable(false);
		toolBarGraph.setAlignmentY(Component.RIGHT_ALIGNMENT);	
		
		
		localPeriodButton.setToolTipText("Toggle Local/Global Mode");
		toolBarGraph.add(localPeriodButton);
		//ComboBox
		localPeriodInput.setEditable(true);
		localPeriodInput.setVisible(false);
		localPeriodInput.setMaximumSize(new Dimension(20,23));
		localPeriodInput.addItemListener(aListener->{
			if(aListener.getStateChange() == ItemEvent.DESELECTED) {
				validateInput(localPeriodInput.getEditor().getItem().toString(), true);
			}
			
		});
		
		toolBarGraph.add(localPeriodInput);
				
		//localPeriodButtonFunction
		localPeriodButton.addActionListener(actionEvent->{
			boolean newState= !localPeriodInput.isVisible();
			changeLocalPeriodButtonAppeareance(newState);
			unitGraph.setUseLocalPeriod(newState);
		});
		
		
		toolBarGraph.add(Box.createHorizontalGlue());
		resetButton.setToolTipText("Reset");
		resetButton.addActionListener(actionEvent ->  unitGraph.reset());
		toolBarGraph.add(resetButton);
		
		
		
		
		
		scrollGraph.setRowHeaderView(graphLabel);
		scrollGraph.setColumnHeaderView(toolBarGraph);

		tables.add(model.getSingleTable());
		tables.add(model.getMultiTable());
		/***********************
		 * HolonElement Table Actions
		 **********************/
		/*
		 * Add HolonElement to given HolonObject
		 */
		btnAddHolEL.addActionListener(actionEvent -> {
			if (model.getSelectedCpsObjects().size() == 1) {
				AbstractCanvasObject tempCpsObject = updCon.getActualCps();
				if (tempCpsObject != null
						&& tempCpsObject.getClass() == HolonObject.class
						&& tempCpsObject.getId() != 0) {
					addElementPopUp = new AddElementPopUp(holegJFrame, model);//TODO: I didn't even check
					addElementPopUp.setActualCps(updCon.getActualCps());
					addElementPopUp.setVisible(true);
					HolonElement ele = addElementPopUp.getElement();
					if (ele != null) {
						controller.addElementCanvasObject(
								tempCpsObject.getId(), ele.getEleName(),
								ele.getAmount(), ele.getEnergyPerElement(),
								ele.getId());
					}
					controller.calculateStateAndVisualForTimeStep(model
							.getCurIteration());
					triggerUpdateController(null);
					contentPane.updateUI();
				}
			}else
			{
				JOptionPane.showMessageDialog(contentPane, "No object selected.\nPlease select a object first." , "Message" , JOptionPane.INFORMATION_MESSAGE);
			}
		});
		/*
		 * Delete the chosen HolonElement of the selected HolonObject,
		 * Multi-Selection for CpsObjects as well as for HolonElements possible
		 */
		btnDelHolEL.addActionListener(actionEvent -> {
			// For Single Selection of CpsObject
				if (model.getSelectedCpsObjects().size() == 1) {
					if (updCon.getActualCps().getClass() == HolonObject.class) {
						HolonObject obj = (HolonObject) updCon.getActualCps();
						if(selectedElements.isEmpty())
						{
							JOptionPane.showMessageDialog(contentPane, "No element selectet.\nPlease select a element in the list first." , "Message" , JOptionPane.INFORMATION_MESSAGE);
						}
						for (HolonElement e : selectedElements) {
							controller.deleteElementCanvas(obj.getId(),
									e.getId());
							controller.calculateStateAndVisualForTimeStep(model
									.getCurIteration());
							triggerUpdateController(null);
							contentPane.updateUI();
							// Names displayed in graph are not updated
			}
			model.getEleToDelete().clear();
			selectedElements.clear();
		}
		// For MultiSelection of CpsObject
	} else if (model.getSelectedCpsObjects().size() > 1) {
		for (Integer i : model.getEleToDelete().keySet()) {
			for (HolonElement e : model.getEleToDelete().get(i)) {
				controller.deleteElementCanvas(i, e.getId());
			}
		}
		triggerUpdateController(null);
		model.getEleToDelete().clear();
		selectedElements.clear();
	}else
			{
				JOptionPane.showMessageDialog(contentPane, "No object selectet.\nPlease select a object first." , "No object selectet" , JOptionPane.INFORMATION_MESSAGE);
			}
	triggerUpdateController(null);
	elementGraph.setText(Languages.getLanguage()[25]);
	holonEleNamesDisplayed = Languages.getLanguage()[25];
})		;
		/*
		 * Communication between HolonElement Table and displayed Graph and
		 * Properties, as well as selection of different HolonElements
		 */
		model.getTableHolonElement().addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				HolonObject obj = null;
				if (model.getSelectedCpsObjects().size() == 1
						&& model.getSelectedCpsObjects().get(0) instanceof HolonObject) {
					obj = (HolonObject) updCon.getActualCps();
				}
				yValueElements = e.getY();
				HolonElement ele;
				// Search for current clicked HolonElement
				if (model.getSelectedCpsObjects().size() == 1) {
					ele = updCon.getActualHolonElement(obj, yValueElements, 0,
							tables);
				} else {
					ele = updCon.getActualHolonElement(null, yValueElements, 0,
							tables);
				}
				// Multi-Selection of HolonElements through control button +
				// mouse click
				if (ele != null) {
					// make energy-consumption graph visible
					showScrollGraph();

					if (e.isControlDown()) {
						if (!selectedElements.contains(ele)) {
							selectedElements.add(ele);
							if (!holonEleNamesDisplayed.equals(Languages
									.getLanguage()[25])) {
								holonEleNamesDisplayed = holonEleNamesDisplayed
										+ "; " + ele.getEleName() + " ";
							} else {
								holonEleNamesDisplayed = ele.getEleName() + " ";
							}
							updateUnitGraph((GraphEditable)selectedElements.get(selectedElements.size()-1));
						}
						updCon.getActualHolonElement(null, yValueElements, 2,
								tables);
					}
					// if no control-button pressed but a HolonElement chosen
					else {
						selectedElements.clear();
						selectedElements.add(ele);
						updCon.getActualHolonElement(null, yValueElements, 1,
								tables);
						holonEleNamesDisplayed = ele.getEleName() + " ";
						updateUnitGraph((GraphEditable)selectedElements.get(selectedElements.size()-1));
					}
				} else {
					elementGraph.setText(Languages.getLanguage()[25]);
					hideScrollGraph();
				}
				// if any HolonElement is double-clicked --> Edit-Mode started
				// for selected HolonElement
				if (e.getClickCount() == 2) {
					yThis = e.getY();
					xThis = e.getX();
				}
				// for single click and empty slot
				if (e.getClickCount() == 1 && ele == null) {
					selectedElements.clear();
					holonEleNamesDisplayed = Languages.getLanguage()[25];
				}
				elementGraph.setText(holonEleNamesDisplayed);
				yBTis = e.getY();
				xBThis = e.getX();

			}
			
			@Override
			public void mouseExited(MouseEvent e) {
				/**
				 * Stop Editing, if mouse exits the Table
				 */
				JTable holElem = model.getTableHolonElement();
				if(e.getX()<=0 || e.getX()>=holElem.getWidth() 
						/*|| e.getY() <= 0*/|| e.getY()>= holElem.getHeight()){
					CellEditor cellEditor = holElem.getCellEditor();
					if (cellEditor != null) {
					    if (cellEditor.getCellEditorValue() != null) {
					    	/** TODO: Maybe try to save current Data */
					        cellEditor.stopCellEditing();
					    } else {
					        cellEditor.cancelCellEditing();
					    }
					}
				}
				
			}
			
		});
		
		/*
		 * Triggered every time a change is made
		 */
		model.getTableHolonElement()
				.addPropertyChangeListener(propertyChangeEvent -> {
					try {
						int yMouse = yThis;
						int yBMouse = yBTis;
						int selectedValueY = (int) Math.floor(yMouse / 16);
						int selectedValueBY = (int) Math.floor(yBMouse / 16);
						// ------------------ multi-selection mode
						// ------------------
						if (model.getSelectedCpsObjects().size() > 1) {
							int selectedValueX = (int) Math
									.floor(xThis
											/ (model.getTableHolonElement()
													.getWidth() / 8));
							int selectedValueBX = (int) Math
									.floor(xBThis
											/ (model.getTableHolonElement()
													.getWidth() / 8));
							if (updCon.getHolonObj(yMouse,
									model.getMultiTable()) != null) {
								// For active column (boolean with a checkbox)
								if (selectedValueBX == 6) {
									System.out.println("selectedValueBX == 6");
									HolonElement eleBTemp = updCon
											.getActualHolonElement(null,
													yBMouse, 0, tables);
									String newBStuff = model
											.getMultiTable()
											.getValueAt(selectedValueBY,
													selectedValueBX).toString();
									Boolean bTemp = Boolean
											.parseBoolean(newBStuff);
									eleBTemp.setActive(bTemp);
								}
								// For activeFlex column (boolean with a
								// checkbox)
								else if (selectedValueBX == 7) {
									System.out.println("selectedValueBX == 7");
									HolonElement eleBTemp = updCon
											.getActualHolonElement(null,
													yBMouse, 0, tables);
									String newBStuff = model
											.getMultiTable()
											.getValueAt(selectedValueBY,
													selectedValueBX).toString();
									Boolean bTemp = Boolean
											.parseBoolean(newBStuff);
									eleBTemp.setActive(bTemp);
								} else {
									// Update of HolonElement
									HolonElement eleTemp = updCon
											.getActualHolonElement(null,
													yMouse, 0, tables);
									String newStuff = model
											.getMultiTable()
											.getValueAt(selectedValueY,
													selectedValueX).toString();
									// Name update
									if (selectedValueX == 2) {
										eleTemp.setEleName(newStuff);
									}
									// Energy Update
									else if (selectedValueX == 3) {
										System.out.println("selectedValueX == 3");
										Float ftemp = Float
												.parseFloat(newStuff);
										eleTemp.setEnergyPerElement(ftemp);
									}
									// Flexibility
									else if (selectedValueX == 4) {
										Float ftemp = Float
												.parseFloat(newStuff);
										//TODO and here
									}
									// Amount of Elements update
									else if (selectedValueX == 5) {
										Integer iTemp = Integer
												.parseInt(newStuff);
										eleTemp.setAmount(iTemp);
									}
									else if (selectedValueX == 6) {
										System.out.println("Test");
									}
								}
							}
						} // ------------------ single-selection mode
							// ------------------
						else if (model.getSelectedCpsObjects().size() == 1) {
							int selectedValueX = (int) Math
									.floor(xThis
											/ (model.getTableHolonElement()
													.getWidth() / 7));
							int selectedValueBX = (int) Math
									.floor(xBThis
											/ (model.getTableHolonElement()
													.getWidth() / 7));
							if (updCon.getActualCps() != null
									&& updCon.getActualCps().getClass() == HolonObject.class) {
								HolonElement eleTemp;

								// For active column (boolean with a checkbox)
								if (selectedValueBX == 5) {
									eleTemp = updCon.getActualHolonElement(
											(HolonObject) updCon.getActualCps(),
											yBMouse, 0, tables);
									String newBStuff = model
											.getSingleTable()
											.getValueAt(selectedValueBY,
													selectedValueBX).toString();
									Boolean bTemp = Boolean
											.parseBoolean(newBStuff);
									eleTemp.setActive(bTemp);

								} // For activeFlex column (boolean with a
									// checkbox)
								else if (selectedValueBX == 6) {
									eleTemp = updCon.getActualHolonElement(
											(HolonObject) updCon.getActualCps(),
											yBMouse, 0, tables);
									String newBStuff = model
											.getSingleTable()
											.getValueAt(selectedValueBY,
													selectedValueBX -1).toString();
									Boolean bTemp = Boolean
											.parseBoolean(newBStuff);
									eleTemp.setActive(bTemp);
									//TODO: delete Boolean bTemp = Boolean.parseBoolean(newBStuff);

								} else {
									// Update of HolonElement
									eleTemp = updCon.getActualHolonElement(
											(HolonObject) updCon.getActualCps(),
											yMouse, 0, tables);
									String newStuff = model
											.getSingleTable()
											.getValueAt(selectedValueY,
													selectedValueX).toString();
									// Name update
									if (selectedValueX == 1) {
										eleTemp.setEleName(newStuff);
									} // Energy Update
									else if (selectedValueX == 2) {
										Float ftemp = Float
												.parseFloat(newStuff);
										eleTemp.setEnergyPerElement(ftemp);
									} // Flexibility
									else if (selectedValueX == 3) {
										Float ftemp = Float
												.parseFloat(newStuff);
										//TODO ---

										// if this is a flexible device and the
										// flexibly available energy was
										// changed,
										// set used energy to 0, so that it can
										// be computed anew
									}
									// Amount of Elements update
									else if (selectedValueX == 4) {
										Integer iTemp = Integer
												.parseInt(newStuff);
										eleTemp.setAmount(iTemp);
									}
								}

								// set all cells anew, if anything was changed
								updateElementTableAfterChange(eleTemp,
										selectedValueBY);
							}
						}
						controller.calculateStateAndVisualForTimeStep(model
								.getCurIteration());
						model.getSingleTable().fireTableDataChanged();
						triggerUpdateController(null);
						contentPane.updateUI();
						unitGraph.repaint();

						// trigger update of table after UnitGraph was painted
						SwingUtilities.invokeLater(() -> {
							triggerUpdateController(null);
						});
					} catch (Exception e) {
					}
				});
		/***********************
		 * HolonElement Properties Actions
		 **********************/

		/*
		 * Update of the mouse coord for Edit-Mode
		 */
		tableProperties.addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				if (e.getClickCount() == 2) {
					yProThis = e.getY();
					xProThis = e.getX();
				}
				yProThisOneClick = e.getY();
				xProThisOneClick = e.getX();
			}
		});

		/*
		 * Update any change in the Property table
		 */
		tableProperties.addPropertyChangeListener(propertyChangeEvent -> {
			try {
				Object temp;
				Object btemp;
				int selValueY = (int) Math.floor(yProThis / 16);
				int selValueX = (int) Math.floor(xProThis
						/ (tableProperties.getWidth() / 2));
				int selValueYBool = (int) Math.floor(yProThisOneClick / 16);
				int selValueXBool = (int) Math.floor(xProThisOneClick
						/ (tableProperties.getWidth() / 2));
				if (updCon.getActualCps() != null) {
					temp = model.getPropertyTable().getValueAt(selValueY,
							selValueX);
					btemp = model.getPropertyTable().getValueAt(selValueYBool,
							selValueXBool);
					// Case: Switch selected

				if (updCon.getActualCps() instanceof HolonSwitch) {
					if (selValueY == 0 && selValueX != 0) {
						updCon.getActualCps().setName(temp.toString());
					}
					if (selValueYBool == 2) {
						Boolean bbTemp = Boolean.parseBoolean(btemp.toString());
						((HolonSwitch) updCon.getActualCps())
								.setManualMode(bbTemp);
						if (bbTemp) {
							model.getPropertyTable()
									.setCellEditable(3, 1, true);
						} else {
							model.getPropertyTable().setCellEditable(3, 1,
									false);
						}
					} else if (selValueYBool == 3) {
						if (((HolonSwitch) updCon.getActualCps())
								.getManualMode()) {
							model.getPropertyTable()
									.setCellEditable(3, 1, true);
							Boolean bTemp = Boolean.parseBoolean(btemp
									.toString());
							((HolonSwitch) updCon.getActualCps())
									.setManualState(bTemp);
						}
					}
				} // Case: UpperNode selected
				else if (updCon.getActualCps() instanceof GroupNode
						&& selValueX != 0) {
					// Name edition through double click
					updCon.getActualCps().setName(temp.toString());
					// Update of name on the tab in the tab section
					for (int index = 4; index < tabbedPaneOriginal
							.getTabCount(); index++) {
						tabTemp = tabbedPaneOriginal;
						JScrollPane scrollPane = getScrollPaneFromTabbedPane();

						GroupNodeCanvas unc = ((GroupNodeCanvas) scrollPane
								.getViewport().getComponent(0));

						if (unc.upperNode.getId() == updCon.getActualCps()
								.getId()) {
							tabbedPaneOriginal.setTitleAt(index,
									unc.upperNode.getName());
							tabbedPaneOriginal.updateUI();
							if (!initSplit) {
								tabbedPaneSplit.setTitleAt(index,
										unc.upperNode.getName());
								tabbedPaneSplit.updateUI();
							}
						}
					}
				} // Case: HolonObject is selected
				else if (updCon.getActualCps() instanceof HolonObject
						&& selValueX != 0) {
					// Name edition through double click
					updCon.getActualCps().setName(temp.toString());
				}
			} // Case: Edge is selected
			else {
				temp = model.getPropertyTable()
						.getValueAt(selValueY, selValueX);
				btemp = model.getPropertyTable().getValueAt(selValueYBool,
						selValueXBool);
				// Edit modus for capacity by double clicking
				if (selValueY == 2) {
					Float ftemp;
					if (Float.parseFloat(temp.toString()) >= 0.0) {
						ftemp = Float.parseFloat(temp.toString());
					} else {
						ftemp = model.getSelectedEdge().getCapacity();
					}
					model.getSelectedEdge().setCapacity(ftemp);
				}
				// Status edition through a check box
				if (selValueYBool == 3) {
					Boolean bbTemp = Boolean.parseBoolean(btemp.toString());
				}
			}
			canvas.repaint();
		} catch (Exception e) {
		}
	})	;

		/***********************
		 * HolonElement Graph Actions
		 **********************/
		
		/*
		 * Update Local Period of an Element Graph
		 */
		unitGraphLocalPeriod.addKeyListener(new KeyAdapter() {
			@Override
			 public void keyReleased(KeyEvent e) {
				try{
					int localLength = Integer.parseInt(unitGraphLocalPeriod.getText());
					unitGraphLocalPeriod.setBackground(Color.WHITE);
					/**
					 * set local graph Period
					 */
					if(e.getKeyCode() == KeyEvent.VK_ENTER)
						unitGraph.setLocalPeriod(localLength);						
				}catch(NumberFormatException ex){
					unitGraphLocalPeriod.setBackground(PALE_RED);
				}
				
			}
		});
		
		/*****************************
		 * RIGHT CONTAINER DONE
		 *****************************/

		holegJFrame.getContentPane().setLayout(new BorderLayout(0, 0));
		/****************
		 * Tree Stuff
		 ****************/

		// Override Key Actions
		inputMap = tree.getInputMap();
		inputMap.put(KeyStroke.getKeyStroke("control C"), cntrlCDown);
		inputMap.put(KeyStroke.getKeyStroke("control V"), cntrlVDown);
		inputMap.put(KeyStroke.getKeyStroke("control X"), cntrlXDown);
		inputMap.put(KeyStroke.getKeyStroke("control A"), cntrlADown);

		TreeCellRenderer customRenderer = new TreeCellRenderer() {
			@Override
			public Component getTreeCellRendererComponent(JTree tree,
					Object value, boolean selected, boolean expanded,
					boolean leaf, int row, boolean hasFocus) {
				JLabel label = new JLabel();
				Image imgR;
				if (leaf) {
					for (Category cat : model.getCategories()) {
						for (AbstractCanvasObject cps : cat.getObjects()) {
							if (value.toString().compareTo(cps.getObjName()) == 0) {
								imgR = ImageImport.loadImage(cps.getImage(), 50,
										50);
								if (imgR != null) {
									label.setIcon(new ImageIcon(imgR));
								}
								label.setText(cps.getName());
							}
						}
					}
				}
				tree.setRowHeight(50);
				if (hasFocus) {
					label.setForeground(new Color(0, 0, 255));
					label.setOpaque(true);
				}
				if (label.getText().length() == 0) {
					label.setText(value.toString());
					if (value.toString().compareTo("Categories") != 0) {
						label.setIcon(new ImageIcon(ImageImport.loadImage(
								"/Images/folder.png")));
					}
				}

				return label;

			}
		};
		
		tree.setCellRenderer(customRenderer);

		tree.addMouseMotionListener(new MouseMotionAdapter() {

			public void mouseDragged(MouseEvent e){
				checkForDragAndDrop(e);
			}
			
			/**
			 * checks if an object of the current Panel
			 * could be replaced by the dragged object
			 * @param e
			 */
			private void checkForDragAndDrop(MouseEvent e){
				try {
					/**
					 * if no object gets dragged -> finished
					 */
					if(!dragging)return;
					
					/**
					 * select the current Panel
					 */
					chooseTabTemp();				
					JScrollPane scrollPane = getScrollPaneFromTabbedPane();
					if(scrollPane == null)return;
					Component canvasOrUpperNodeCanvas = scrollPane
							.getViewport().getComponent(0);
					
					/**
					 * check for replacements on the canvas
					 */
					if (canvasOrUpperNodeCanvas instanceof GroupNodeCanvas) {
						GroupNodeCanvas unc = (GroupNodeCanvas) canvasOrUpperNodeCanvas;
						if(unc.getMousePosition()==null)return;
						int x = (int) unc.getMousePosition().getX()+16;
						int y = (int) unc.getMousePosition().getY()+16;
						
						/**
						 * if in upperNode
						 */
						if (x <= unc.upperNode.getLeftBorder()) return;
						
						/**
						 * check for replacement
						 */
						unc.checkForReplacement(x, y);
						
						/**
						 * repaint 
						 */
						unc.invalidate();
						unc.repaint();
					} else {
						if(canvas.getMousePosition()==null)return;
						int x = (int) canvas.getMousePosition().getX()+16;
						int y = (int) canvas.getMousePosition().getY()+16;
						
						/**
						 * check for replacement
						 */
						canvas.checkForReplacement(x, y);
						
						/**
						 * repaint
						 */
						canvas.invalidate();
						canvas.repaint();
					}
					contentPane.updateUI();
					
				} catch (Exception eex) {
					eex.printStackTrace();
				}
			}});

		
		tree.addMouseListener(new MouseAdapter() {
			
			public void mouseReleased(MouseEvent e) {
				try {
					if (dragging) {
						chooseTabTemp();
						JScrollPane scrollPane = getScrollPaneFromTabbedPane();
						Component canvasOrUpperNodeCanvas = scrollPane
								.getViewport().getComponent(0);

						if (canvasOrUpperNodeCanvas instanceof GroupNodeCanvas) {
							GroupNodeCanvas unc = (GroupNodeCanvas) canvasOrUpperNodeCanvas;
							int x = (int) unc.getMousePosition().getX() + 16;
							int y = (int) unc.getMousePosition().getY() + 16;

							if (x > unc.upperNode.getLeftBorder()) {

								AbstractCanvasObject h = null;
								if (tempCps instanceof HolonObject) {
									h = new HolonObject(tempCps);
								}
								if (tempCps instanceof HolonSwitch) {
									h = new HolonSwitch(tempCps);
								}
								if (tempCps instanceof HolonBattery)
								{
									h = new HolonBattery(tempCps);
								}
								h.setPosition(x, y);

								/**
								 * close UpperNodeTabs of replaced UpperNode
								 */
								if(unc.mayBeReplaced!=null &&unc.mayBeReplaced instanceof GroupNode){
									unc.closeUpperNodeTab(unc.mayBeReplaced.getId());
								}
								controller.addObjUpperNode(h, unc.upperNode);
								
								/**
								 * object would be replaced
								 */
								unc.mayBeReplaced = null; 
								unc.invalidate();
								controller.calculateStateAndVisualForCurrentTimeStep();
								unc.repaint();
								unc.setXY((int) canvas.getMousePosition()
										.getX(), (int) canvas
										.getMousePosition().getY());
							}
						} else {
							int x = (int) canvas.getMousePosition().getX() + 16;
							int y = (int) canvas.getMousePosition().getY() + 16;

							AbstractCanvasObject h = null;
							if (tempCps instanceof HolonObject) {
								h = new HolonObject(tempCps);
							}
							if (tempCps instanceof HolonSwitch) {
								h = new HolonSwitch(tempCps);
							}
							
							if (tempCps instanceof HolonBattery)
							{
								h = new HolonBattery(tempCps);
							}
							h.setPosition(x, y);
							
							/**
							 * close UpperNodeTabs of replaced UpperNode
							 */
							if(canvas.mayBeReplaced!=null &&canvas.mayBeReplaced instanceof GroupNode){
								canvas.closeUpperNodeTab(canvas.mayBeReplaced.getId());
							}
							controller.addObjectCanvas(h);
							/**
							 * no object should get replaced
							 */
							canvas.mayBeReplaced = null;
							canvas.invalidate();
							canvas.setXY(
									(int) canvas.getMousePosition().getX(),
									(int) canvas.getMousePosition().getY());
							canvas.repaint();
						}
						controller.calculateStateAndVisualForCurrentTimeStep();
						contentPane.updateUI();
						dragging = false;
					}
				} catch (Exception eex) {
				}
				holegJFrame.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
			}
		});
		

		popmenuEdit.add(editItem);
		popmenuEdit.add(removeItem);
		editItem.setEnabled(false);
		editItem.addActionListener(actionEvent -> {
		});
		tree.addMouseListener(new MouseAdapter() {
		
			public void mousePressed(MouseEvent e) {
				try {
					actualObjectClicked = tree
							.getPathForLocation(e.getX(), e.getY())
							.getLastPathComponent().toString();
					// if an Object was selected, the porperties are shown in
					// the table
					DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree
							.getPathForLocation(e.getX(), e.getY())
							.getLastPathComponent();
					if (selectedNode.getLevel() == 2) {
						controller.searchCategoryObject(selectedNode
								.getParent().toString(), selectedNode
								.toString());
						updCon.deleteRows(model.getSingleTable());
						updCon.deleteRows(model.getMultiTable());
						// if (selected instanceof HolonObject && selected !=
						// null) {
						// selected = (HolonObject) selected;
						// fillElementTable(((HolonObject)
						// selected).getElements());
						// }
					}
					if (SwingUtilities.isRightMouseButton(e)) {
						for (Category cat : model.getCategories()) {
							for (AbstractCanvasObject cps : cat.getObjects()) {
								if (actualObjectClicked.compareTo(cps
										.getObjName()) == 0
										&& !(cps instanceof HolonSwitch)) {
									editItem.setEnabled(true);
									popmenuEdit.show(e.getComponent(),
											e.getX(), e.getY());
									catOfObjToBeEdited = selectedNode
											.getParent().toString();
									tempCps = cps;
								}
							}
						}
					} else {
						for (Category cat : model.getCategories()) {
							for (AbstractCanvasObject cps : cat.getObjects()) {
								if (actualObjectClicked.compareTo(cps
										.getObjName()) == 0) {
									File checkPath = new File(cps.getImage());
									if (checkPath.exists()) {
										img = new ImageIcon(cps.getImage())
												.getImage()
												.getScaledInstance(
														32,
														32,
														java.awt.Image.SCALE_SMOOTH);
									} else {
										img = ImageImport.loadImage(
												cps.getImage(), 32, 32);
									}
									tempCps = cps;
									dragging = true;
									Cursor cursor = Toolkit.getDefaultToolkit()
											.createCustomCursor(img,
													new Point(0, 0), "Image");
									holegJFrame.setCursor(cursor);
								}
							}
						}
					}
				} catch (Exception eex) {
				}
			}
		});
		editItem.addActionListener(actionEvent -> {
			// Remove the selected Object object
			//AddObjectPopUp(boolean edit, AbstractCpsObject obj, String cat, JFrame parentFrame)
			System.out.println("Edit");
			addObjectPopUP = new AddObjectPopUp(true, tempCps,
					catOfObjToBeEdited, holegJFrame);
			addObjectPopUP.setCategory(catOfObjToBeEdited);
			addObjectPopUP.setController(controller);
			addObjectPopUP.setVisible(true);
		});
		removeItem.addActionListener(actionEvent -> {
			// Remove the selected Object object
			try {
				System.out.println("catOfObjToBeEdited:" + catOfObjToBeEdited + ", tempCps:" + tempCps);
				controller.delObjectCategory(catOfObjToBeEdited, tempCps.getName());				
			}catch(IOException e) {
				System.err.println("IOException");
				e.printStackTrace();
			}
		});
		scrollPane1.setViewportView(tree);

		scrollPane1.setColumnHeaderView(panel);
		panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
		toolBar.setAlignmentX(Component.LEFT_ALIGNMENT);
		toolBar.setFloatable(false);

		panel.add(toolBar);
		btnAddPopUp.add(mItemNew);
		mItemNew.addActionListener(actionEvent -> {
			new NewPopUp(controller, holegJFrame);
		});
		btnAddPopUp.addSeparator();
		btnAddPopUp.add(mItemCategory);
		mItemCategory.addActionListener(actionEvent -> {
			new NewPopUp(controller,Option.Category, holegJFrame);
		});
		btnAddPopUp.add(mItemObject);
		mItemObject.addActionListener(actionEvent -> {
			new NewPopUp(controller,Option.Object, holegJFrame);
		});
		btnAddPopUp.add(mItemSwitch);
		mItemSwitch.addActionListener(actionEvent -> {
			new NewPopUp(controller,Option.Switch, holegJFrame);
		});
		btnAddPopUp.add(mItemBattery);
		mItemBattery.addActionListener(actionEvent -> {
			new NewPopUp(controller,Option.Battery, holegJFrame);
		});
		btnAdd.addActionListener(actionEvent -> btnAddPopUp.show(btnAdd, -1, +20));
		btnAdd.setToolTipText("Add a new Category or Item to the library.");
		toolBar.add(btnAdd);
		/**
		 * Help Menu Action Listeners
		 */
		
		/**
		 * URL of the telecommunication git Wiki
		 */
		String tkWikiWebpage = "https://git.tk.informatik.tu-darmstadt.de/carlos.garcia/praktikum-holons/wiki/";
		
		/** open Introduction Web Page */
		mntmIntroduction.addMouseListener(new MouseAdapter() {
			@Override
			public void mousePressed(MouseEvent e){
				openWebpage(tkWikiWebpage + "Introduction+V2.1");
			}
		});
		
		/** open UserManual WebPage */
		mntmUserManual.addMouseListener(new MouseAdapter() {
			@Override
			public void mousePressed(MouseEvent e){
				openWebpage(tkWikiWebpage + "User+Manual+V2.1");
			}
		});
		
		/** open Algorithm Help Web Page*/
		mntmAlgorithmHelp.addMouseListener(new MouseAdapter() {
			@Override
			public void mousePressed(MouseEvent e){
				openWebpage(tkWikiWebpage + "Algorithms+V2.1");
			}
		});
		
		/** open Code Documentation Web Page */
		mntmCodeDoc.addMouseListener(new MouseAdapter() {
			@Override
			public void mousePressed(MouseEvent e){
				openWebpage(tkWikiWebpage + "Code+documentation+V2.1");
			}
		});
		
		/**
		 * Pop up - About Us with some important information about the
		 * developers, source and programming stuff
		 */
		mntmAboutUs.addMouseListener(new MouseAdapter() {
			@Override
			public void mousePressed(MouseEvent e) {
				aboutUsPopUp = new AboutUsPopUp(holegJFrame);
				aboutUsPopUp.setVisible(true);
			}
		});

		/**
		 * Update of every interaction between the user and the canvas (only on
		 * the canvas). Basically the update of all the information concerning
		 * the clicked HolonObject. For multi-selection, the propertyTable would
		 * be disabled
		 */
		canvas.addMouseListener(new MouseAdapter() {
			@Override
			public void mousePressed(MouseEvent e) {

			}

			@Override
			public void mouseReleased(MouseEvent e) {
				holonEleNamesDisplayed = Languages.getLanguage()[25];
				// If any empty space is clicked
				if (temp == null || temp.getId() != model.getSelectedObjectID()) {
					hideScrollGraph();
					elementGraph.setText(Languages.getLanguage()[25]);
				}
				temp = updCon.getActualCps();
				// Erase old data in the PropertyTable
				if (model.getPropertyTable().getRowCount() > 0) {
					for (int i = model.getPropertyTable().getRowCount() - 1; i > -1; i--) {
						model.getPropertyTable().removeRow(i);
					}
				}
				if (e.isControlDown() && temp != null) {
					if (model.getSelectedCpsObjects().contains(temp)) {
						controller.deleteSelectedObject(temp);
					} else {
						controller.addSelectedObject(temp);
					}
				}
				if (temp instanceof HolonSwitch) {
					showScrollGraph();
					updateUnitGraph((GraphEditable)temp);
				}
				// Write new data in the PropertyTable
				triggerUpdateController(temp);

				// New Tab with NodeOfNode
				if (doubleClick() && MouseEvent.BUTTON3 != e.getButton()
						&& temp instanceof GroupNode) {
					openNewUpperNodeTab();
					try {
						controller.autoSave();
					} catch (IOException e1) {
						e1.printStackTrace();
					}
				}
				if (model.getSelectedCpsObjects().size() > 1) {
					model.getTableHolonElement()
							.setModel(model.getMultiTable());
				} else if (model.getSelectedCpsObjects().size() == 1) {
					model.getTableHolonElement().setModel(
							model.getSingleTable());
				}

			}

		});

		holonCanvas.addMouseListener(new MouseAdapter() {
			@Override
			public void mousePressed(MouseEvent e) {
				hideScrollGraph();
				elementGraph.setText(Languages.getLanguage()[25]);
				if (model.getPropertyTable().getRowCount() > 0) {
					for (int i = model.getPropertyTable().getRowCount() - 1; i > -1; i--) {
						model.getPropertyTable().removeRow(i);
					}
				}
				updCon.deleteRows(model.getMultiTable());
				updCon.deleteRows(model.getSingleTable());
				updCon.paintHolonBody(model.getSelectedHolonBody());
			}
		});

		

		// Del Button
		btnDel.addActionListener(actionEvent -> {
			Object nodeInfo = tree.getLastSelectedPathComponent();
			if (nodeInfo != null) {
				DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) nodeInfo;
				String nodeName = selectedNode.getUserObject().toString();
				int depthOfNode = selectedNode.getLevel();
				try {
					switch (depthOfNode) {
					case 1:
						int dialogResult = JOptionPane.showConfirmDialog(
								holegJFrame, eraseCategory + nodeName
										+ "?", warningText,
								JOptionPane.YES_NO_OPTION);
						if (dialogResult == JOptionPane.YES_OPTION) {
							controller.deleteCategory(nodeName);
						}
						break;
					case 2:
						DefaultMutableTreeNode parent = (DefaultMutableTreeNode) selectedNode
								.getParent();
						controller.delObjectCategory(parent.getUserObject()
								.toString(), nodeName);
						break;

					default:
						JOptionPane.showMessageDialog(holegJFrame,
								selectObjBeforeErase);
					}
				} catch (Exception e2) {
				}

			} else {
				JOptionPane.showMessageDialog(holegJFrame,
						selectObjBeforeErase);
			}
			tree.repaint();
		});
		toolBar.add(btnDel);

		holegJFrame.getContentPane().add(splitPane);

		mntmNew.addActionListener(actionEvent -> {
			if (model.getObjectsOnCanvas().size() != 0) {
				int newWarning = JOptionPane.YES_NO_OPTION;
				int dialogForNewWarning = JOptionPane.showConfirmDialog(
						holegJFrame, saveBeforeNew, warningText,
						newWarning);
				if (dialogForNewWarning == JOptionPane.YES_OPTION) {
					mntmSave.doClick();
				}
			}

			model.getEdgesOnCanvas().removeAll(model.getEdgesOnCanvas());
			model.getObjectsOnCanvas().removeAll(model.getObjectsOnCanvas());
			controller.setSelectedObjectID(0);
			controller.setSelecteEdge(null);
			controller.setCurIteration(0);
			hideScrollGraph();
			elementGraph.setText(Languages.getLanguage()[25]);
			canvas.tempCps = null;
			canvas.repaint();
			IdCounter.resetCounter();
			IdCounterElem.resetCounter();
		});

		mntmOpen.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent evt) {
				menuFileExitActionPerformed();
			}

			private void menuFileExitActionPerformed() {
				JFileChooser fileChooser = new JFileChooser();
				fileChooser.setCurrentDirectory(new File(System.getProperty("user.dir")+"/exampleNetworks/"));
				FileNameExtensionFilter holonFilter = new FileNameExtensionFilter(
						"Holon Save File(*.holon)", "holon");
				fileChooser.setFileFilter(holonFilter);

				if (fileChooser.showOpenDialog(holegJFrame) == JFileChooser.APPROVE_OPTION) {
					File file = fileChooser.getSelectedFile();

					try {
						controller.loadFile(file.getAbsolutePath());
						canvas.repaint();
						unitGraph.update(model.getObjectsOnCanvas());
						tree.repaint();
						controller.calculateStateAndVisualForCurrentTimeStep();
						for (JsonObject json : model.getStatisticData()) {
							readStatistics(json);
						}
					} catch (IOException | ArchiveException e) {
						e.printStackTrace();
						JLabel message = new JLabel(
								"The savefile is corrupt and cannot be opened.");
						JOptionPane.showMessageDialog(holegJFrame,
								message, "", JOptionPane.ERROR_MESSAGE);
					}
				}
			}
		});

		mntmSave.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent evt) {
				menuSaveActionPerformed();
			}

			private void menuSaveActionPerformed() {
				JFileChooser fileChooser = new JFileChooser();
				FileNameExtensionFilter holonFilter = new FileNameExtensionFilter(
						"Holon Save File(*.holon)", "holon");
				fileChooser.setFileFilter(holonFilter);

				if (fileChooser.showSaveDialog(holegJFrame) == JFileChooser.APPROVE_OPTION) {
					File selectedFile = fileChooser.getSelectedFile();
					String fileName = selectedFile.getName();
					String fullPath = fileChooser.getSelectedFile().getPath();
					if (fileChooser.getFileFilter().equals(holonFilter)) {
						if (!fileName.contains("."))
							fullPath += ".holon";
					}
					if (!fullPath.endsWith(".holon")) {
						String suffix = fullPath.substring(fullPath.lastIndexOf("."),
								fullPath.length());
						String[] options = new String[] { "keep .holon",
								"use " + suffix };

						JLabel message = new JLabel(
								"Are you sure to use the extension \"" + suffix
										+ "\" instead of \".holon\"?");

						int response = JOptionPane.showOptionDialog(
								holegJFrame, message, "",
								JOptionPane.DEFAULT_OPTION,
								JOptionPane.QUESTION_MESSAGE, null, options,
								options[1]);

						if (response == 0)
							fullPath = fullPath.replace(suffix, ".holon");
					}

					try {
						controller.saveFile(new File(fullPath).getAbsolutePath());
					} catch (IOException | ArchiveException e) {
						e.printStackTrace();
					}
				}
			}
		});

		englishBtn.addActionListener(actionEvent -> {
			Languages.setLanguage(0);
			refreshLanguages();
			updCon.refreshTableProperties(model.getPropertyTable());
		});
		spanishBtn.addActionListener(actionEvent -> {
			Languages.setLanguage(1);
			refreshLanguages();
			updCon.refreshTableProperties(model.getPropertyTable());
		});
		germanBtn.addActionListener(actionEvent -> {
			Languages.setLanguage(2);
			refreshLanguages();
			updCon.refreshTableProperties(model.getPropertyTable());
		});
		czechBtn.addActionListener(actionEvent -> {
			Languages.setLanguage(3);
			refreshLanguages();
			updCon.refreshTableProperties(model.getPropertyTable());
		});
		chineseBtn.addActionListener(actionEvent -> {
			Languages.setLanguage(4);
			refreshLanguages();
			updCon.refreshTableProperties(model.getPropertyTable());
		});

		mntmUndo.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent evt) {
				menuUndoActionPerformed();
			}

			private void menuUndoActionPerformed() {
				try {
					controller.loadAutoSave(controller.getUndoSave());
					
					closeInvalidUpperNodeTabs();
					
					controller.calculateStateAndVisualForCurrentTimeStep();
					canvas.repaint();

					repaintGraphAfterUndoRedo();
					hideScrollGraph();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		});

		mntmRedo.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent evt) {
				menuRedoActionPerformed();
			}

			private void menuRedoActionPerformed() {
				try {
					controller.loadAutoSave(controller.getRedoSave());
					
					closeInvalidUpperNodeTabs();
					
					controller.calculateStateAndVisualForCurrentTimeStep();
					canvas.repaint();

					repaintGraphAfterUndoRedo();
					hideScrollGraph();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		});

		timePanel = new TimePanel(this,controller);
		timePanel.setBorder(null);
		timePanel.getTimeSlider()
				.addChangeListener(changeEvent -> {
					//TimeSliderChanged event
					controller.calculateStateAndVisualForTimeStep(timePanel.getTimeSlider().getValue());
					unitGraph.repaint();
					if (model.getIsSimRunning()) {
						controller.runAlgorithm(model, controller);
						statSplitPane.repaintGraphs();
					}
					contentPane.updateUI();
				});
		splitPane1.setMinimumSize(new Dimension(0, 25));
		splitPane.setRightComponent(splitPane1);
		splitPane.setDividerLocation(200);
		splitPane1.setDividerLocation(500);

		splitPane.setLeftComponent(scrollPane1);
		tabbedPaneOriginal.addTab("View", tabbedPaneInnerOriginal);
		
		
		myPanel.add(canvasSP, BorderLayout.CENTER);
		myPanel.add(lblHint, BorderLayout.PAGE_END);
		lblHint.setBackground(new Color(53, 178, 76, 100));
		lblHint.setOpaque(true);
		
		
		tabbedPaneInnerOriginal.addTab("Main Grid", myPanel);
		tabbedPaneOriginal.addTab("Statistics", statScrollPane);
		tabbedPaneOriginal.addTab("Holon", holonCanvas);
		FlexiblePane flexPane = new FlexiblePane(controller);
		controller.setFlexiblePane(flexPane);
		controller.getModel().getObjectListeners().add(flexPane);
		tabbedPaneOriginal.addTab("Flexibility", flexPane);
		splitPane1.setLeftComponent(tabbedPaneOriginal);
		splitPane1.setRightComponent(splitHolonElPro);

		splitPane1.setResizeWeight(0.9);

		splitHolonElPro.setDividerLocation(700);
		// containing the graph and the elements-list
		splitHolonElPro.setTopComponent(splitGraphHolonEl);
		// containing the object's properties
		splitHolonElPro.setBottomComponent(scrollProperties);

		splitGraphHolonEl.setDividerLocation(distanceBetweenElementsAndGraph);
		splitGraphHolonEl.setTopComponent(scrollElements);
		splitGraphHolonEl.setBottomComponent(scrollGraph);
		canvasSP.setViewportView(canvas);

		tabbedPaneOriginal.setBorder(null);
		scrollProperties.setBorder(null);
		scrollGraph.setBorder(null);
		scrollElements.setBorder(null);
		splitPane.setBorder(null);
		splitPane1.setBorder(null);
		splitHolonElPro.setBorder(null);
		splitGraphHolonEl.setBorder(null);
		panelHolonEl.setBorder(null);
		canvasSP.setBorder(null);
		hideScrollGraph();
		tableHolonElementScrollPane.setBorder(null);

		holegJFrame.getContentPane().add(timePanel, BorderLayout.SOUTH);



		try {
			controller.loadAutoSave(System.getProperty("user.home")
					+ "/.config/HolonGUI/Category/Category.json");
		} catch (IOException e1) {
		}

		String autoPath = System.getProperty("user.home")
				+ "/.config/HolonGUI/Autosave/";
		File dest = new File(autoPath);
		ArrayList<File> oldAutoSaves = controller.filterOldAutoSaveFiles();
		int nrOfOldSaves = oldAutoSaves.size();

		if (nrOfOldSaves > 0) {
			int dialogButton = JOptionPane.YES_NO_OPTION;
			int dialogResult = JOptionPane.showConfirmDialog(holegJFrame,
					"Old autosave file was found, should it be loaded?",
					warningText, dialogButton);
			if (dialogResult == JOptionPane.YES_OPTION) {
				if (dest.exists()) {
					model.setAutoSaveNr(nrOfOldSaves - 1);
					mntmRedo.doClick();
				} else {
					JOptionPane.showMessageDialog(holegJFrame,
							"Autosave could not be loaded.");
					setUpAutoSave(dest);
				}
			} else {
				setUpAutoSave(dest);
			}

			// after all: delete the obsolete/old autosave files from the
			// directory
			controller.deleteObsoleteAutoSaveFiles();
		}

		canvasSP.addComponentListener(new ComponentAdapter() {
			@Override
			public void componentResized(ComponentEvent e) {
				controller.setCanvasX(Math.max(model.getCanvasX(), canvasSP
						.getViewport().getWidth()));
				controller.setCanvasY(Math.max(model.getCanvasY(), canvasSP
						.getViewport().getHeight()));
				canvas.repaint();
			}
		});
	}

	private void initWindowMenu() {
		menuBar.add(menuWindow);
		//Algo
		JMenuItem openMenu =  new JMenuItem("Open Algorithm Panel", new ImageIcon(ImageImport.loadImage("/Button_Images/iconAlgo.png").getScaledInstance(20, 20, java.awt.Image.SCALE_SMOOTH)));
		openMenu.addActionListener(actionEvent -> {
			new AddOnWindow(holegJFrame, controller);
		});
		openMenu.setAccelerator(KeyStroke.getKeyStroke('N', Toolkit.getDefaultToolkit ().getMenuShortcutKeyMask()));
		menuWindow.add(openMenu);
		//Outliner
		JMenuItem openOutliner =  new JMenuItem("Open Outliner", new ImageIcon(ImageImport.loadImage("/Button_Images/iconOutliner.png").getScaledInstance(20, 20, java.awt.Image.SCALE_SMOOTH)));
		openOutliner.addActionListener(actionEvent -> {
			outlinerList.add(new Outliner(holegJFrame, model, controller));
		});
		openOutliner.setAccelerator(KeyStroke.getKeyStroke('O', Toolkit.getDefaultToolkit ().getMenuShortcutKeyMask()));
		menuWindow.add(openOutliner);
		//FlexWindow
		JMenuItem openFlexMenuItem =  new JMenuItem("Open Flexibility Panel", new ImageIcon(ImageImport.loadImage("/Button_Images/iconAlgo.png").getScaledInstance(20, 20, java.awt.Image.SCALE_SMOOTH)));
		openFlexMenuItem.addActionListener(actionEvent -> {
			flexList.add(new FlexWindow(holegJFrame, controller));
		});
		openFlexMenuItem.setAccelerator(KeyStroke.getKeyStroke('L', Toolkit.getDefaultToolkit ().getMenuShortcutKeyMask()));
		menuWindow.add(openFlexMenuItem);
	}


	public void updateOutliners(DecoratedState state)
	{
		//remove closed Outliner
		ListIterator<Outliner> iter = outlinerList.listIterator();
		while(iter.hasNext())
		{
			if(iter.next().isClosed) iter.remove();
		}
		//update open Outliner
		for(Outliner out : outlinerList) {
			out.repaintWithDecoratedState(state);
		}
	}
	public void updateFlexWindows()
	{
		//remove closed Outliner
		ListIterator<FlexWindow> iter = flexList.listIterator();
		while(iter.hasNext())
		{
			if(iter.next().isClosed) iter.remove();
		}
		//update open Flex
		for(FlexWindow out : flexList) {
			out.update();
		}
	}
	
	
	
	private void showScrollGraph() {
		scrollGraph.setVisible(true);
		splitGraphHolonEl.setBottomComponent(scrollGraph);
		splitGraphHolonEl.setDividerLocation(distanceBetweenElementsAndGraph);
	}

	private void hideScrollGraph() {
		scrollGraph.setVisible(false);
		splitGraphHolonEl.remove(scrollGraph);
		splitGraphHolonEl.setDividerLocation(0);
	}

	private boolean isUpperPanelInsideBounds() {
		int x = holegJFrame.getX();
		int y = holegJFrame.getY();
		int width = holegJFrame.getWidth();

		// get all connected screen devices
		GraphicsDevice[] screenDevices = GraphicsEnvironment
				.getLocalGraphicsEnvironment().getScreenDevices();
		boolean isUpperPanelVisible = false;

		// and check whether they contain the upper left or upper right point of
		// the frame
		for (GraphicsDevice device : screenDevices) {
			Rectangle bounds = device.getDefaultConfiguration().getBounds();
			if (bounds.contains(x, y) || bounds.contains(x + width, y)) {
				isUpperPanelVisible = true;
				break;
			}
		}

		return isUpperPanelVisible;
	}

	/**
	 * Sets up autosave if no old one is loaded at the beginning
	 *
	 * @param dest
	 *            path to save-folder
	 */
	private void setUpAutoSave(File dest) {
		dest.mkdirs();
		try {
			controller.autoSave();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
	}

	/**
	 * adds a specific object type to selected Category also handles input
	 * windows and illegal inputs.
	 *
	 * @param objType
	 *            type of the Object
	 * @param selectedNode
	 *            The selected Node
	 */
	private void addObjectAction(String objType,
			DefaultMutableTreeNode selectedNode) {
		if (selectedNode == null) {
			JOptionPane.showMessageDialog(holegJFrame,
					"Please select a Category first before adding " + objType
							+ ".");
		}
		// if selected node is a directory for Categories
		else {
			if (selectedNode.getLevel() == 1) {
				String objname = JOptionPane.showInputDialog(holegJFrame,
						"Please enter a Name for the " + objType);
				Category cat = controller.searchCategory(selectedNode
						.getUserObject().toString());

				if (objname.length() != 0) {
					try {
						switch (objType) {

						case "Switch":
							controller.addSwitch(cat, objname);
							break;
						case "Battery":
							controller.addBattery(cat, objname);
							break;
						}
					} catch (Exception e) {
					}

				}
			} else {
				JOptionPane
						.showMessageDialog(holegJFrame,
								"Objects can not be added to Objects. Please select a Category.");
			}
		}
	}

	/**
	 * reloads the Categories from Model.
	 *
	 * @param categories
	 *            the current categories
	 */
	private void updateCategories(final ArrayList<Category> categories) {
		DefaultTreeModel treemodel = new DefaultTreeModel(new DefaultMutableTreeNode(
				"Categories") {

			private static final long serialVersionUID = 1L;

			{
				DefaultMutableTreeNode node1;
				for (Category c : categories) {
					node1 = new DefaultMutableTreeNode(c.getName());
					
					for (AbstractCanvasObject obj : c.getObjects()) {
						node1.add(new DefaultMutableTreeNode(obj.getObjName()));
					}
					add(node1);
				}

			}
		});
		tree.setModel(treemodel);
	}

	/**
	 * When changes are made to the Categories.
	 *
	 * @param categories
	 *            the Categories
	 */
	public void onChange(ArrayList<Category> categories) {
		DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
		updateCategories(categories);
		model.reload();
	}

	/**
	 * Get the Frame.
	 *
	 * @return the Frame
	 */
	JFrame getFrmCyberPhysical() {
		return holegJFrame;
	}

	private void refreshLanguages() {
		String[] tempArray = Languages.getLanguage();
		// ToolBar
		mnNewMenu.setText(tempArray[0]);
		mntmNew.setText(tempArray[1]);
		mntmOpen.setText(tempArray[2]);
		mntmSave.setText(tempArray[3]);
		mnNewMenuEdit.setText(tempArray[4]);
		mntmUndo.setText(tempArray[5]);
		mntmRedo.setText(tempArray[6]);
		mntmFindReplace.setText(tempArray[7]);
		mntmEditShowedInformation.setText(tempArray[8]);
		mnNewMenuOptions.setText(tempArray[9]);
		mntmResetCategory.setText(tempArray[10]);
		mnNewMenuView.setText(tempArray[11]);
		mntmCanvasSize.setText(tempArray[12]);
		mnHelp.setText(tempArray[13]);
		mntmAboutUs.setText(tempArray[14]);
		mntmEditEdges.setText(tempArray[15]);
		mnLanguage.setText(tempArray[16]);
		canvas.updateLanguages();

		// Tables
		System.arraycopy(tempArray, 17, columnNamesMulti, 0,
				columnNamesMulti.length);
		model.getMultiTable().setColumnIdentifiers(columnNamesMulti);
		System.arraycopy(tempArray, 18, columnNamesSingle, 0,
				columnNamesSingle.length);
		model.getSingleTable().setColumnIdentifiers(columnNamesSingle);
		model.colNames[0] = tempArray[23];
		model.colNames[1] = tempArray[24];
		model.getPropertyTable().setColumnIdentifiers(model.colNames);
		// Graph
		elementGraph.setText(tempArray[25]);
		holonEleNamesDisplayed = tempArray[25];
		resetGraphBtn.setText(tempArray[26]);
		// Warning PopUps
		warningText = tempArray[27];
		saveBeforeNew = tempArray[28];
		eraseCategory = tempArray[29];
		selectObjBeforeErase = tempArray[30];
		// TimePanel
		timePanel.playBtn.setToolTipText(Languages.getLanguage()[89]);
		timePanel.timeResetBtn.setToolTipText(Languages.getLanguage()[90]);
		timePanel.timeForwardBtn.setToolTipText(Languages.getLanguage()[91]);
		timePanel.timeBackwardBtn.setToolTipText(Languages.getLanguage()[92]);
		timePanel.timeSlider.setToolTipText(Languages.getLanguage()[93]);
		// Image Size Slider
		lblImageSize.setText(Languages.getLanguage()[94]);
	}

	/**
	 * Checks if a double click was made.
	 *
	 * @return true if doublecklick, false if not
	 */
	private boolean doubleClick() {
		if (click) {
			click = false;
			return true;
		} else {
			click = true;
			Timer t = new Timer("doubleclickTimer", false);
			t.schedule(new TimerTask() {
				@Override
				public void run() {
					click = false;
				}
			}, 350);
		}
		return false;
	}

	/*
	 * Open a new Tab with an UpperNodeCanvas
	 */
	private void openNewUpperNodeTab() {
		chooseTabTemp();

		JScrollPane scrollPane = getScrollPaneFromTabbedPane();
		if (scrollPane.getViewport().getComponent(0) instanceof MyCanvas) {
			unc = new GroupNodeCanvas(model, controller, unitGraph,
					(GroupNode) temp, "", scrollPane.getViewport().getComponent(0));

		} else {
			unc = new GroupNodeCanvas(model, controller, unitGraph,
					(GroupNode) temp, ((GroupNodeCanvas) scrollPane
							.getViewport().getComponent(0)).path + " -> ", scrollPane.getViewport().getComponent(0));
		}
		unc.setShowedInformation(canvas.getShowedInformation());

		// check if tab already open for clicked NodeOfNode
		boolean dupl = false;

		for (int i = 1; i < tabbedPaneInnerOriginal.getTabCount(); i++) {
			JScrollPane paneOriginal = (JScrollPane) tabbedPaneInnerOriginal
					.getComponentAt(i);
			if (paneOriginal != null
					&& ((GroupNodeCanvas) paneOriginal.getViewport()
							.getComponent(0)).upperNode.getId() == temp.getId()) {
				dupl = true;
				// set selected component to view
				tabbedPaneOriginal
						.setSelectedComponent(tabbedPaneInnerOriginal);
				// set selected tab in view to found upper-node-canvas
				tabbedPaneInnerOriginal
						.setSelectedComponent(tabbedPaneInnerOriginal
								.getComponentAt(i));
			}

			if (tabbedPaneSplit.getTabCount() > 0) {
				JTabbedPane tabbedPaneInnerSplit = (JTabbedPane) tabbedPaneSplit
						.getComponentAt(0);
				if (tabbedPaneInnerSplit != null) {
					JScrollPane paneSplit = (JScrollPane) tabbedPaneInnerSplit
							.getComponentAt(i);
					if (!initSplit
							&& paneSplit != null
							&& ((GroupNodeCanvas) paneSplit.getViewport()
									.getComponent(0)).upperNode.getId() == temp
									.getId()) {
						dupl = true;
						// set selected component to view
						tabbedPaneSplit
								.setSelectedComponent(tabbedPaneInnerSplit);
						// set selected tab in view to found upper-node-canvas
						tabbedPaneInnerSplit
								.setSelectedComponent(tabbedPaneInnerSplit
										.getComponentAt(i));
					}
				}
			}

			// if we found a duplicate, break
			if (dupl) {
				break;
			}
		}
		if (!dupl) {
			unc.setBorder(null);
			unc.setBackground(Color.WHITE);
			unc.setPreferredSize(new Dimension(model.getCanvasX(), model
					.getCanvasY()));

			unc.addMouseListener(new MouseAdapter() {
				@Override
				public void mousePressed(MouseEvent e) {
					hideScrollGraph();
					holonEleNamesDisplayed = Languages.getLanguage()[25];
					elementGraph.setText(holonEleNamesDisplayed);

					chooseTabTemp();

					JScrollPane scrollPane1 = getScrollPaneFromTabbedPane();
					temp = ((GroupNodeCanvas) scrollPane1.getViewport()
							.getComponent(0)).tempCps;
					if (doubleClick() && MouseEvent.BUTTON3 != e.getButton()
							&& temp instanceof GroupNode) {
						openNewUpperNodeTab();
					}
					if (temp instanceof HolonSwitch) {
						updateUnitGraph((GraphEditable)temp);
					}
				}

			});

			JScrollPane sp = new JScrollPane(unc);
			sp.setBorder(null);

			// Selected tabbed Pane = tabbedPaneOriginal or tabbedPaneSplit
			if (tabTemp == tabbedPaneOriginal) {
				this.tabbedPaneInnerOriginal.add(temp.getName(), sp);
				this.tabbedPaneInnerOriginal.setSelectedComponent(sp);
				this.tabbedPaneInnerOriginal.setTabComponentAt(
						this.tabbedPaneInnerOriginal.getTabCount() - 1,
						new ButtonTabComponent(this.tabbedPaneInnerOriginal,
								tabbedPaneSplit));

			} else {
				JTabbedPane tabbedPaneInnerSplit = (JTabbedPane) tabbedPaneSplit
						.getComponentAt(0);
				tabbedPaneInnerSplit.add(temp.getName(), sp);
				Component tempC = tabbedPaneInnerSplit.getSelectedComponent();
				tabbedPaneInnerSplit.setComponentAt(
						tabbedPaneInnerSplit.getSelectedIndex(), null);
				tabbedPaneOriginal.setComponentAt(
						tabbedPaneInnerSplit.getSelectedIndex(), tempC);
				tabbedPaneInnerSplit.setSelectedComponent(sp);

				tabbedPaneInnerOriginal.add(temp.getName(), null);
				tabbedPaneInnerOriginal.setTabComponentAt(
						tabbedPaneInnerOriginal.getTabCount() - 1,
						new ButtonTabComponent(tabbedPaneInnerOriginal,
								tabbedPaneInnerSplit));
			}

			temp = null;
		}
	}

	private void updateUpperNodes() {
		for (Component c : tabbedPaneInnerOriginal.getComponents()) {
			if (!(c instanceof JScrollPane)) {
				continue;
			}
			Component pane = ((JScrollPane) c).getViewport().getComponent(0);
			if (pane instanceof GroupNodeCanvas) {
				temp = model.getHashcodeMap()
						.get(((GroupNodeCanvas) pane).code);
				((GroupNodeCanvas) pane).upperNode = (GroupNode) temp;
			}
		}
	}

	/**
	 * Removes UpperNodeTab if UpperNode was deleted
	 *
	 * @param cps
	 *            the CPS object that is currently selected
	 */
	private void removeUpperNodeTab(AbstractCanvasObject cps) {
		if (cps instanceof GroupNode) {
			boolean splitView = false;
			for (int i = 1; i < tabbedPaneInnerOriginal.getTabCount(); i++) {
				JScrollPane scrollPaneOriginal = (JScrollPane) tabbedPaneInnerOriginal
						.getComponentAt(i);

				if (scrollPaneOriginal == null) {
					splitView = true;
				} else if (((GroupNodeCanvas) scrollPaneOriginal.getViewport()
						.getComponent(0)).upperNode.getId() == cps.getId()) {
					((ButtonTabComponent) tabbedPaneInnerOriginal
							.getTabComponentAt(i)).removeTabs();
					break;
				}
			}
			// If SplitView is on and the view on
			// tabbedPaneSplit is the deleted upperNode
			if (splitView && tabbedPaneSplit.getComponentCount() > 0) {
				JTabbedPane tabbedPaneInnerSplit = (JTabbedPane) tabbedPaneSplit
						.getComponentAt(0);

				if (((GroupNodeCanvas) ((JScrollPane) tabbedPaneInnerSplit
						.getSelectedComponent()).getViewport().getComponent(0)).upperNode
						.getId() == cps.getId()) {
					((ButtonTabComponent) tabbedPaneInnerOriginal
							.getTabComponentAt(tabbedPaneInnerSplit
									.getSelectedIndex())).removeTabs();
				}
			}
		}
	}

	private void readStatistics(JsonObject json) {
		List<String> keys = json.entrySet().stream().map(i -> i.getKey())
				.collect(Collectors.toCollection(ArrayList::new));

		// Saved Values
		JsonObject obj;
		AbstractCanvasObject cps;
		int prop;
		Color color;

		StatisticGraphPanel stat = new StatisticGraphPanel(model, controller,//TODO
				json.get("KEY").getAsString(), model.getGraphTable());

		for (String k : keys) {
			if (!k.equals("KEY")) {
				obj = json.get(k).getAsJsonObject();
				cps = (obj.get("ID") == JsonNull.INSTANCE ? null : controller
						.searchTracked(obj.get("ID").getAsInt()));
				prop = obj.get("PROPERTY").getAsInt();
				color = model.getGson().fromJson(obj.get("COLOR"), Color.class);
				stat.addObject(new TrackedDataSet(cps, prop, color, model.getIterations()));
			}
			model.getGraphTable().put(json.get("KEY").getAsString(), stat);
			model.getStatPanel().getGraphPanel().add(stat);
		}
	}

	/**
	 * chooses whether to set the tabTemp to tabbedPaneOriginal or
	 * tabbedPaneSplit
	 */
	private void chooseTabTemp() {
		// is the uppernode on tabbedPaneOriginal or tabbedPaneSplit
		/* TODO: Fix or Remove SplitView */
		if (tabbedPaneOriginal.getMousePosition() != null || initSplit) {
			tabTemp = tabbedPaneOriginal;
		} else {
			tabTemp = tabbedPaneSplit;
		}
	}

	private JScrollPane getScrollPaneFromTabbedPane(JTabbedPane tabbedPane,
			int index) {
		tabTemp = tabbedPane;
		return getScrollPaneFromTabbedPane(index);
	}

	// private JScrollPane getScrollPaneFromTabbedPane(JTabbedPane tabbedPane) {
	// return getScrollPaneFromTabbedPane(tabbedPane, -1);
	// }

	private JScrollPane getScrollPaneFromTabbedPane() {
		return getScrollPaneFromTabbedPane(-1);
	}

	private JScrollPane getScrollPaneFromTabbedPane(int index) {
		Component upperLevelSelectedComponent;
		if(tabTemp == null)
		{
			return null;
		}
		if (index == -1) {
			upperLevelSelectedComponent = tabTemp.getSelectedComponent();
		} else {
			upperLevelSelectedComponent = tabTemp.getComponentAt(index);
		}
		if (upperLevelSelectedComponent instanceof JTabbedPane) {
			Component nextLevel = ((JTabbedPane) upperLevelSelectedComponent).getSelectedComponent();
			if(nextLevel instanceof JPanel)
				return (JScrollPane) ((JPanel)nextLevel).getComponent(0);
			else
				return (JScrollPane) nextLevel;
			
		} else if (upperLevelSelectedComponent instanceof JScrollPane) {
			return (JScrollPane) upperLevelSelectedComponent;
		} else {
			return null;
		}
	}

	private void repaintGraphAfterUndoRedo() {
		for (AbstractCanvasObject cps : model.getObjectsOnCanvas()) {
			unitGraph.repaintGraph(cps);
		}
	}

	/**
	 * if flexibility was turned on, then active needs to be turned off, the
	 * energy currently produced/consumed
	 *
	 * @param eleBTemp
	 *            element that needs to be updated
	 * @param selectedValueBY
	 *            the y value in the table
	 */
	private void updateElementTableAfterChange(HolonElement eleBTemp,
			int selectedValueBY) {
//		model.getSingleTable().setValueAt(false,
//				selectedValueBY, 6);
		model.getSingleTable().setValueAt(eleBTemp.isActive(), selectedValueBY,
				5);
		model.getSingleTable().setValueAt(eleBTemp.getAmount(),
				selectedValueBY, 4);
		model.getSingleTable().setValueAt(
				controller.getSimManager().getActualFlexManager().isAFlexInUseOfHolonElement(eleBTemp),
				selectedValueBY, 3);
		model.getSingleTable().setValueAt(eleBTemp.getEnergyPerElement(),
				selectedValueBY, 2);
	}

	public void triggerUpdateController(AbstractCanvasObject temp) {
		if(model != null) { return;}
		if (temp != null) {
			updCon.paintProperties(temp);
		}
		updCon.refreshTableHolonElement(model.getMultiTable(),
				model.getSingleTable());
		updCon.refreshTableProperties(model.getPropertyTable());
	}

	/**
	 * Custom Mouse adapter makes contentPane gain focus once mouse leaves this
	 * component so copy/paste/cut and "select all" works
	 */
	private class FocusCanvasMouseAdapter extends MouseAdapter {
		@Override
		public void mouseExited(MouseEvent e) {
			contentPane.requestFocus();
		}
	}
	/**
	 * This Method updates the UnitGraph, saves the old LocalModeState and load the new LocalModeState.
	 * @param element The new Element to load the UnitGraph
	 */
	private void updateUnitGraph(GraphEditable element){
		//SaveOld LocalMode State.
		if(localPeriodInput.isVisible())
		{
			//Save Old State
			validateInput(localPeriodInput.getEditor().getItem().toString(), false);
		}
		//Update UnitGraph
		unitGraph.initNewElement(element);
		//Load LocalMode State.
		changeLocalPeriodButtonAppeareance(unitGraph.isUsingLocalPeriod());
		localPeriodInput.getEditor().setItem(unitGraph.getLocalPeriod());
	}
	
	/**
	 * Displayed the actual LocalModeState.
	 * @param enabled
	 */
	private void changeLocalPeriodButtonAppeareance(boolean enabled) {
		localPeriodInput.setVisible(enabled);
		if(enabled)
		{
			localPeriodButtonImage.setImage(ImageImport.loadImage("/Images/Graph.png"));
		}else {
			localPeriodButtonImage.setImage(GrayFilter.createDisabledImage(ImageImport.loadImage("/Images/Graph.png")));
		}
	}
	/**
	 * Validate the LocalMode Input and when its valid save on the Element.
	 * @param text the inputText to validate. 
	 * @param bShowMessage when true, open a MessageDialog when text invalid.
	 */
	private void validateInput(String text, boolean bShowMessage) {
		int localPeriodInputValue;
		try {
		      localPeriodInputValue = Integer.parseInt(text);
		} catch (NumberFormatException e) {
			if(bShowMessage)
				JOptionPane.showMessageDialog(contentPane, '"' +text + '"'+ " is not a valid Input. \n Use whole numbers.");
			return;
		}
		unitGraph.setLocalPeriod(localPeriodInputValue);
	}
	
	public void updateIterations() {
		this.statSplitPane.updateIterations();
	}
	
	private void openWebpage(String URL){
		try {
			java.awt.Desktop.getDesktop().browse(new URI(URL));
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (URISyntaxException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	}
	/**
	 * Function to set the visibility for Hints
	 * @param enable true = show false = hide
	 */
	public void showHint(boolean enable){
		lblHint.setVisible(enable);
	}
	
	/**
	 * closes all UpperNodeTabs, that don't have a
	 * valid UpperNode (e.g. if it was ungrouped/deleted/replaced and so on)
	 */
	private void closeInvalidUpperNodeTabs() {
		/**
		 * close bugged Tabs
		 */
		for (int i = 1; i < tabbedPaneInnerOriginal.getTabCount(); i++) {
			JScrollPane scrollPaneOriginal = (JScrollPane) tabbedPaneInnerOriginal
					.getComponentAt(i);
			if (((GroupNodeCanvas) scrollPaneOriginal.getViewport()
					.getComponent(0)).upperNode == null) {
				((ButtonTabComponent) tabbedPaneInnerOriginal
						.getTabComponentAt(i)).removeTabs();
				break;
			}
		}
	}
	
	public void repaintCanvas() {
		tabbedPaneInnerOriginal.repaint();
	}
	
	/**
	 * Class should be reworked as soon as possible!
	 * @param state
	 */
	public void guiDisable(boolean state) {
		canvas.disabled = state;
		for (int i = 1; i < tabbedPaneInnerOriginal.getTabCount(); i++) {
			JScrollPane scrollPaneOriginal = (JScrollPane) tabbedPaneInnerOriginal
					.getComponentAt(i);
			if (((GroupNodeCanvas) scrollPaneOriginal.getViewport()
					.getComponent(0)).upperNode != null) {
				((GroupNodeCanvas) scrollPaneOriginal.getViewport()
						.getComponent(0)).disable = state;
			}
		}
	}
}
