package ui.view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.BoxLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.DefaultTableModel;
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 classes.AbstractCpsObject;
import classes.Category;
import classes.CpsEdge;
import classes.CpsUpperNode;
import classes.HolonElement;
import classes.HolonObject;
import classes.HolonSwitch;
import classes.HolonTransformer;
import classes.IdCounter;
import classes.IdCounterElem;
import classes.TrackedDataSet;
import interfaces.CategoryListener;
import ui.controller.Control;
import ui.controller.UpdateController;
import ui.model.Model;

/**
 * Graphical User Interface.
 * 
 * @author Gruppe14
 * 
 * @param <E>
 *            Generic
 */
public class GUI<E> implements CategoryListener {

	// for doubleclick
	private boolean click = false;

	private JFrame frmCyberPhysical;

	private final SimulationMenu simMenu;

	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 mnHelp = new JMenu("Help");
	private final JMenuItem mntmOpen = new JMenuItem("Open");
	private final JMenuItem mntmNew = new JMenuItem("New");
	private final JMenuItem mntmSave = new JMenuItem("Save");
	private final JMenuItem aboutUs = new JMenuItem("About Us");
	private final JMenuItem canvasSize = new JMenuItem("View Size");
	private final JSplitPane splitPane = new JSplitPane();
	private final JSplitPane splitPane1 = new JSplitPane();
	private final JSplitPane splitPaneCanvasConsole = new JSplitPane(JSplitPane.VERTICAL_SPLIT);

	private final JScrollPane canvasSP = new JScrollPane();
	private final JScrollPane scrollPane1 = new JScrollPane();
	// private final JScrollPane holonSP = new JScrollPane();
	private final JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
	private final JPanel panelTapped_SimMenu = new JPanel();
	private JPopupMenu popmenuEdit = new JPopupMenu();
	private JMenuItem editItem = new JMenuItem("Edit Object");
	private String catOfObjToBeEdited;
	private final JScrollPane statTab = new JScrollPane();

	private splitPane statSplitPane;
	private JScrollPane statScrollPane;
	private UpperNodeCanvas unc;

	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<HolonElement>();
	private String holonEleNamesDisplayed = "None ";
	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);

	// In this section are all the Holonelements that correspond to the clicked
	// HolonObject with consumption/production, name and amount.

	// Model for single or multi selection
	private final JPanel scrollElements = new JPanel();
	private 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 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);
			}
		}
	};
	private 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 JTable tableGraph = new JTable();
	private DefaultTableModel tableModelGraph = new DefaultTableModel();
	private final JScrollPane scrollGraph = new JScrollPane();

	private Model model;
	private final Control controller;

	// Pop up Windows
	private AddObjectPopUp addObjectPopUP;
	private AboutUsPopUp aboutUsPopUp;
	private AddElementPopUp addElementPopUp;

	private final JPanel panel = new JPanel();
	private final JPanel panelHolonEl = new JPanel();
	private final JComboBox comboBox = new JComboBox();
	// private final JComboBox comboBoxGraph = new JComboBox();

	// Buttons
	private final JButton btnAdd = new JButton("+");
	private final JButton btnDel = new JButton("-");
	private final JButton btnAddHolEL = new JButton("+");
	private final JButton btnDelHolEL = new JButton("-");
	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();

	// private final Languages languages = new Languages();

	// 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");

	// variables
	private boolean dragging = false;
	private String actualObjectClicked;
	private Image img = null;
	private AbstractCpsObject tempCps = null;
	private int yValueElements = 0;

	private Console console = new Console();
	private MyCanvas canvas;
	private HolonCanvas holonCanvas;
	private UnitGraph unitGraph;
	private final JSplitPane splitPane3 = new JSplitPane();
	private final JSlider sizeSlider = new JSlider();
	private final JLabel lblImageSize = new JLabel(Languages.getLanguage()[94]);
	// Time Stuff
	private TimePanel 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 AbstractCpsObject temp = null;
	private final JMenuItem mntmUndo = new JMenuItem("Undo");
	private final JMenuItem mntmRedo = new JMenuItem("Redo");
	private final JMenuItem mntmEditEdges = new JMenuItem("Edit Edges");
	private final JMenuItem mntmFindReplace = new JMenuItem("Find/ Replace");
	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 String[] columnNamesMulti = { "Object", "Nr.", "Device", "Energy", "Quantity", "Activated" };
	private String[] columnNamesSingle = { "Nr.", "Device", "Energy", "Quantity", "Activated" };
	private ArrayList<PropertyTable> tables = new ArrayList<PropertyTable>();
	private String[] comboBoxCat = { "Category", "Object", "Switch" };
	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 order to delete something.";

	private UpdateController updCon;

	/**
	 * Create the application.
	 * 
	 * @param control
	 *            the Controller
	 */
	public GUI(Control control) {
		this.controller = control;
		this.model = control.getModel();
		statSplitPane = new splitPane(controller);
		model.addGraphListener(statSplitPane);
		statScrollPane = new JScrollPane(statSplitPane);
		this.canvas = new MyCanvas(model, control);
		this.holonCanvas = new HolonCanvas(model, control);
		this.unitGraph = new UnitGraph(model, control);
		control.initListener(this);
		controller.setCanvas(canvas);
		model.setConsole(console);
		simMenu = new SimulationMenu(model, control);
		initialize();
		updateCategories(model.getCategories());
		updCon = new UpdateController(model, controller);
	}

	/**
	 * Initialize the contents of the frame.
	 */
	@SuppressWarnings({ "serial", "unchecked" })
	private void initialize() {
		frmCyberPhysical = new JFrame();
		frmCyberPhysical.setTitle("Cyber Physical Systems Model");
		frmCyberPhysical.setBounds(100, 100, 1000, 800);
		frmCyberPhysical.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		frmCyberPhysical.addWindowListener(new java.awt.event.WindowAdapter() {
			@Override
			public void windowClosing(java.awt.event.WindowEvent windowEvent) {
				if (JOptionPane.showConfirmDialog(frmCyberPhysical, Languages.getLanguage()[88],
						"Cyber Physical Systems Model", JOptionPane.YES_NO_OPTION,
						JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
					controller.deleteDirectory(new File(System.getProperty("user.home") + "/HolonGUI/Autosave"));
					System.exit(0);
				}
			}
		});

		JPanel contentPane = (JPanel) frmCyberPhysical.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.loadFile(controller.getUndoSave());
					canvas.repaint();
					ArrayList<HolonElement> tempList = new ArrayList<>();
					for (AbstractCpsObject cps : model.getObjectsOnCanvas()) {
						if (cps instanceof HolonObject) {
							for (HolonElement h : ((HolonObject) cps).getElements()) {
								tempList.add(h);
								unitGraph.repaintWithNewElement(tempList);
								unitGraph.fillArrayofValue();
								tempList.remove(0);
							}
						} else if (cps instanceof HolonSwitch) {
							unitGraph.repaintWithNewSwitch((HolonSwitch) cps);
							unitGraph.fillArrayofBooleans();
						}
					}
					unitGraph.empty();
				} catch (IOException eex) {
					// TODO Auto-generated catch block
					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.loadFile(controller.getRedoSave());
					canvas.repaint();
					ArrayList<HolonElement> tempList = new ArrayList<>();
					for (AbstractCpsObject cps : model.getObjectsOnCanvas()) {
						if (cps instanceof HolonObject) {
							for (HolonElement h : ((HolonObject) cps).getElements()) {
								tempList.add(h);
								unitGraph.repaintWithNewElement(tempList);
								unitGraph.fillArrayofValue();
								tempList.remove(0);
							}
						} else if (cps instanceof HolonSwitch) {
							unitGraph.repaintWithNewSwitch((HolonSwitch) cps);
							unitGraph.fillArrayofBooleans();
						}
					}
					unitGraph.empty();
				} catch (IOException ex) {
					// TODO Auto-generated catch block
					ex.printStackTrace();
				}
			}
		});

		String cntrlADown = "controlA";
		inputMap.put(KeyStroke.getKeyStroke("control A"), cntrlADown);
		actionMap.put(cntrlADown, new AbstractAction() {

			private static final long serialVersionUID = 1L;

			@Override
			public void actionPerformed(ActionEvent e) {

				model.getSelectedCpsObjects().clear();
				// Uppernode Canvas?
				if (((JScrollPane) tabbedPane.getSelectedComponent()).getViewport()
						.getComponent(0) instanceof UpperNodeCanvas) {
					UpperNodeCanvas uNC = (UpperNodeCanvas) ((JScrollPane) tabbedPane.getSelectedComponent())
							.getViewport().getComponent(0);
					for (AbstractCpsObject cps : uNC.upperNode.getNodes()) {
						controller.addSelectedObject(cps);
					}
					uNC.repaint();
					// or Canvas?
				} else if (((JScrollPane) tabbedPane.getSelectedComponent()).getViewport()
						.getComponent(0) instanceof MyCanvas) {
					for (AbstractCpsObject cps : model.getObjectsOnCanvas()) {
						controller.addSelectedObject(cps);
					}
					canvas.repaint();
				}

			}
		});

		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) {
				// Uppernode Canvas?
				if (((JScrollPane) tabbedPane.getSelectedComponent()).getViewport()
						.getComponent(0) instanceof UpperNodeCanvas) {
					UpperNodeCanvas uNC = (UpperNodeCanvas) ((JScrollPane) tabbedPane.getSelectedComponent())
							.getViewport().getComponent(0);
					for (AbstractCpsObject cps : model.getSelectedCpsObjects()) {
						if (uNC.upperNode.getNodes().contains(cps)) {
							controller.delObjUpperNode(cps, uNC.upperNode);
							// Remove UpperNodeTab if UpperNode deleted
							if (cps instanceof CpsUpperNode) {
								for (int i = 3; i < tabbedPane.getTabCount(); i++) {
									if (((UpperNodeCanvas) ((JScrollPane) tabbedPane.getComponentAt(i)).getViewport()
											.getComponent(0)).upperNode.getID() == cps.getID()) {
										tabbedPane.remove(i);
										i = tabbedPane.getTabCount();
									}
								}
							}
						}
					}
					uNC.repaint();

					// or Canvas?
				} else if (((JScrollPane) tabbedPane.getSelectedComponent()).getViewport()
						.getComponent(0) instanceof MyCanvas) {
					for (AbstractCpsObject cps : model.getSelectedCpsObjects()) {
						controller.delCanvasObject(cps);
						// Remove UpperNodeTab if UpperNode deleted
						if (cps instanceof CpsUpperNode) {
							for (int i = 3; i < tabbedPane.getTabCount(); i++) {
								if (((UpperNodeCanvas) ((JScrollPane) tabbedPane.getComponentAt(i)).getViewport()
										.getComponent(0)).upperNode.getID() == cps.getID()) {
									tabbedPane.remove(i);
									i = tabbedPane.getTabCount();
								}
							}
						}
					}
					canvas.repaint();
				}
				model.getSelectedCpsObjects().clear();
				unitGraph.empty();
			}
		});

		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);
				dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
				dialog.setVisible(true);
			}
		});

		String cntrlCDown = "controlC";
		inputMap.put(KeyStroke.getKeyStroke("control C"), cntrlCDown);
		actionMap.put(cntrlCDown, new AbstractAction() {

			private static final long serialVersionUID = 1L;

			@Override
			public void actionPerformed(ActionEvent e) {
				if (!model.getSelectedCpsObjects().isEmpty()) {
					controller.copyObjects();
					if (!model.getClipboradObjects().isEmpty()) {
						canvas.itemPaste.setEnabled(true);
					}
				}
			}
		});

		String cntrlVDown = "controlV";
		inputMap.put(KeyStroke.getKeyStroke("control V"), cntrlVDown);
		actionMap.put(cntrlVDown, new AbstractAction() {

			private static final long serialVersionUID = 1L;

			@Override
			public void actionPerformed(ActionEvent e) {
				controller.pasteObjects(canvas.getMousePosition());
				canvas.repaint();
			}
		});

		String cntrlXDown = "controlX";
		inputMap.put(KeyStroke.getKeyStroke("control X"), cntrlXDown);
		actionMap.put(cntrlXDown, new AbstractAction() {

			private static final long serialVersionUID = 1L;

			@Override
			public void actionPerformed(ActionEvent e) {
				if (!model.getSelectedCpsObjects().isEmpty()) {
					controller.cutObjects();
					if (!model.getClipboradObjects().isEmpty()) {
						canvas.itemPaste.setEnabled(true);
					}
					canvas.repaint();
				}
			}
		});

		frmCyberPhysical.setJMenuBar(menuBar);

		frmCyberPhysical.setIconImage(new ImageIcon(this.getClass().getResource("/Images/Dummy_House.png")).getImage()
				.getScaledInstance(30, 30, Image.SCALE_SMOOTH));

		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(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {

					SearchPopUp dialog = new SearchPopUp(controller, canvas);
					dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
					dialog.setVisible(true);
				} catch (Exception ex) {
					ex.printStackTrace();
				}
			}
		});

		mnNewMenuEdit.add(mntmFindReplace);
		mntmEditShowedInformation.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					ShowedInformationPopUp dialog = new ShowedInformationPopUp(canvas);
					dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
					dialog.setVisible(true);
				} catch (Exception ex) {
					ex.printStackTrace();
				}
			}
		});

		mnNewMenuEdit.add(mntmEditShowedInformation);

		menuBar.add(mnNewMenuOptions);
		mntmEditEdges.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				EditEdgesPopUp edgePopUp = new EditEdgesPopUp();
				edgePopUp.setCanvas(canvas);
				edgePopUp.setController(controller);
				edgePopUp.setVisible(true);
			}
		});

		mnNewMenuOptions.add(mntmEditEdges);

		mnNewMenuOptions.add(mntmResetCategory);
		mntmResetCategory.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				ArrayList<Category> cat = model.getCategories();
				while (!cat.isEmpty()) {
					controller.deleteCategory(cat.get(0).getName());
					;
				}
				controller.resetCategorys();
				tree.repaint();
			}
		});

		menuBar.add(mnNewMenuView);

		mnNewMenuView.add(canvasSize);
		canvasSize.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				JPanel myPanel = new JPanel();
				JTextField field1 = new JTextField("" + canvas.getWidth() + "");
				JTextField field2 = new JTextField("" + canvas.getHeight() + "");
				myPanel.add(field1);
				myPanel.add(field2);
				JOptionPane.showMessageDialog(null, myPanel);
				controller.setCanvasX(Integer.parseInt(field1.getText()));
				controller.setCanvasY(Integer.parseInt(field2.getText()));
				for (int i = 3; i < tabbedPane.getTabCount(); i++) {
					tabbedPane.getComponentAt(i)
							.setPreferredSize(new Dimension(model.getCanvasX(), model.getCanvasY()));
					tabbedPane.getComponentAt(i).repaint();
				}
				canvas.setPreferredSize(new Dimension(model.getCanvasX(), model.getCanvasY()));
				canvas.repaint();
			}
		});

		mnNewMenuView.add(splitPane3);

		sizeSlider.setMinimum(15);
		sizeSlider.setMaximum(115);
		sizeSlider.addChangeListener(new ChangeListener() {
			@Override
			public void stateChanged(ChangeEvent e) {
				controller.setScale(sizeSlider.getValue());
				tree.setRowHeight(50);
				canvas.repaint();
			}
		});
		splitPane3.setRightComponent(sizeSlider);

		splitPane3.setLeftComponent(lblImageSize);

		menuBar.add(mnHelp);

		mnHelp.add(aboutUs);

		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);
		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.add(elementGraph);
		toolBarGraph.add(resetGraphBtn);
		toolBarGraph.setFloatable(false);
		scrollGraph.setRowHeaderView(graphLabel);
		scrollGraph.setColumnHeaderView(toolBarGraph);

		tables.add(model.getSingleTable());
		tables.add(model.getMultiTable());
		/***********************
		 * HolonElement Table Actions
		 **********************/
		/*
		 * Add HolonElement to given HolonObject
		 */
		btnAddHolEL.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if (model.getSelectedCpsObjects().size() == 1) {
					AbstractCpsObject tempCpsObject = updCon.getActualCps();
					System.out.println(tempCpsObject.getName());
					if (tempCpsObject != null && tempCpsObject.getClass() == HolonObject.class
							&& tempCpsObject.getID() != 0) {
						addElementPopUp = new AddElementPopUp();
						addElementPopUp.setActualCps(updCon.getActualCps());
						addElementPopUp.setVisible(true);
						HolonElement ele = addElementPopUp.getElement();
						if (ele != null) {
							controller.addElementCanvasObject(tempCpsObject.getID(), ele.getEleName(), ele.getAmount(),
									ele.getEnergy());
						}
						updCon.refreshTableHolonElement(model.getMultiTable(), model.getSingleTable());
						updCon.refreshTableProperties(model.getPropertyTable());
						controller.calculateStateForTimeStep(model.getCurIteration());
					}
				}
			}
		});
		/*
		 * Delete the chosen HolonElement of the selected HolonObject,
		 * Multi-Selection for CpsObjects as well as for HolonElements possible
		 */
		btnDelHolEL.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				// For Single Selection of CpsObject
				if (model.getSelectedCpsObjects().size() == 1) {
					if (updCon.getActualCps().getClass() == HolonObject.class) {
						HolonObject obj = (HolonObject) updCon.getActualCps();
						for (HolonElement e : selectedElements) {
							controller.deleteElementCanvas(obj.getID(), e.getId());
							updCon.refreshTableHolonElement(model.getMultiTable(), model.getSingleTable());
							updCon.refreshTableProperties(model.getPropertyTable());
							controller.calculateStateForTimeStep(model.getCurIteration());
							// 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());
						}
					}
					updCon.refreshTableHolonElement(model.getMultiTable(), model.getSingleTable());
					updCon.refreshTableProperties(model.getPropertyTable());
					model.getEleToDelete().clear();
					selectedElements.clear();
				}
				updCon.refreshTableProperties(model.getPropertyTable());
				elementGraph.setText("None ");
				holonEleNamesDisplayed = "None ";
			}
		});
		/*
		 * 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 = null;
				// 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 (e.isControlDown() && ele != null) {
					if (!selectedElements.contains(ele)) {
						selectedElements.add(ele);
						if (!holonEleNamesDisplayed.equals("None ")) {
							holonEleNamesDisplayed = holonEleNamesDisplayed + "; " + ele.getEleName() + " ";
						} else {
							holonEleNamesDisplayed = ele.getEleName() + " ";
						}
						unitGraph.repaintWithNewElement(selectedElements);
					}
					updCon.getActualHolonElement(null, yValueElements, 2, tables);
				} // if no control-button pressed but a HolonElement choose
				else if (ele != null) {
					selectedElements.clear();
					selectedElements.add(ele);
					updCon.getActualHolonElement(null, yValueElements, 1, tables);
					holonEleNamesDisplayed = ele.getEleName() + " ";
					unitGraph.repaintWithNewElement(selectedElements);
				} // If any empty space is clicked
				else {
					elementGraph.setText(Languages.getLanguage()[25]);
					unitGraph.empty();
				}
				// 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();

			}
		});

		/*
		 * Triggered every time a change is made
		 */
		model.getTableHolonElement().addPropertyChangeListener(new PropertyChangeListener() {
			@Override
			public void propertyChange(PropertyChangeEvent evt) {
				try {
					int yMouse = yThis;
					int yBMouse = yBTis;
					int selectedValueY = (int) Math.floor(yMouse / 16);
					int selectedValueBY = (int) Math.floor(yBMouse / 16);
					// for multi-selection mode
					if (model.getSelectedCpsObjects().size() > 1) {
						int selectedValueX = (int) Math.floor(xThis / (model.getTableHolonElement().getWidth() / 6));
						int selectedValueBX = (int) Math.floor(xBThis / (model.getTableHolonElement().getWidth() / 6));
						if (updCon.getHolonObj(yMouse, model.getMultiTable()) != null) {
							// For last column (boolean with a checkbox)
							if (selectedValueBX == 5) {
								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) {
									Float ftemp = Float.parseFloat(newStuff);
									eleTemp.setEnergy(ftemp);
								}
								// Amount of Elements update
								else if (selectedValueX == 4) {
									Integer iTemp = Integer.parseInt(newStuff);
									eleTemp.setAmount(iTemp);
								}
							}
						}
					} // For single-selection mode
					else if (model.getSelectedCpsObjects().size() == 1) {
						int selectedValueX = (int) Math.floor(xThis / (model.getTableHolonElement().getWidth() / 5));
						int selectedValueBX = (int) Math.floor(xBThis / (model.getTableHolonElement().getWidth() / 5));
						if (updCon.getActualCps() != null && updCon.getActualCps().getClass() == HolonObject.class) {
							// For last column (boolean with a checkbox)
							if (selectedValueBX == 4) {
								HolonElement eleBTemp = updCon
										.getActualHolonElement((HolonObject) updCon.getActualCps(), yBMouse, 0, tables);
								String newBStuff = model.getSingleTable().getValueAt(selectedValueBY, selectedValueBX)
										.toString();
								Boolean bTemp = Boolean.parseBoolean(newBStuff);
								eleBTemp.setActive(bTemp);
							} else {
								// Update of HolonElement
								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.setEnergy(ftemp);
								} // Amount of Elements update
								else if (selectedValueX == 3) {
									Integer iTemp = Integer.parseInt(newStuff);
									eleTemp.setAmount(iTemp);
								}
							}
						}
					}
					updCon.refreshTableProperties(model.getPropertyTable());
					model.getSingleTable().fireTableDataChanged();
					controller.calculateStateForTimeStep(model.getCurIteration());
					unitGraph.repaint();
				} 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();
				}

			}
		});

		/*
		 * Update any change in the Property table
		 */
		tableProperties.addPropertyChangeListener(new PropertyChangeListener() {
			@Override
			public void propertyChange(PropertyChangeEvent evt) {
				try {
					Object temp;
					Object btemp;
					Point mousePos = tableProperties.getMousePosition();
					int selValueY = (int) Math.floor(yProThis / 16);
					int selValueX = (int) Math.floor(xProThis / (tableProperties.getWidth() / 2));
					if (updCon.getActualCps() != null) {
						temp = model.getPropertyTable().getValueAt(selValueY, selValueX);
						if (updCon.getActualCps() instanceof HolonSwitch) {
							btemp = model.getPropertyTable().getValueAt(mousePos.y / tableProperties.getRowHeight(),
									mousePos.x / (tableProperties.getWidth() / 2));
							if (mousePos.y / tableProperties.getRowHeight() == 0) {
								updCon.getActualCps().setName(btemp.toString());
							} else if (mousePos.y / tableProperties.getRowHeight() == 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 (mousePos.y / tableProperties.getRowHeight() == 3) {
								if (((HolonSwitch) updCon.getActualCps()).getManualMode()) {
									model.getPropertyTable().setCellEditable(3, 1, true);
									Boolean bTemp = Boolean.parseBoolean(temp.toString());
									((HolonSwitch) updCon.getActualCps()).setManualState(bTemp);
								}
							}
						} // else if (getActualCps() instanceof
							// AbstractCpsObject) {
						updCon.getActualCps().setName(temp.toString());
						// }
					} else {
						temp = model.getPropertyTable().getValueAt(selValueY, selValueX);
						btemp = model.getPropertyTable().getValueAt(mousePos.y / tableProperties.getRowHeight(),
								mousePos.x / (tableProperties.getWidth() / 2));
						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);
						} else if (mousePos.y / tableProperties.getRowHeight() == 3) {
							Boolean bbTemp = Boolean.parseBoolean(btemp.toString());
							model.getSelectedEdge().setState(bbTemp);
						}
					}
					canvas.repaint();
				} catch (Exception e) {
				}
			}
		});

		/***********************
		 * HolonElement Graph Actions
		 **********************/
		/*
		 * Reset the graph of the selected HolonElement
		 */
		resetGraphBtn.setBorder(new LineBorder(Color.BLACK));
		resetGraphBtn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				unitGraph.reset();
			}
		});
		/*****************************
		 * RIGHT CONTAINER DONE
		 *****************************/

		frmCyberPhysical.getContentPane().setLayout(new BorderLayout(0, 0));

		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 = null;
				if (leaf) {
					for (Category cat : model.getCategories()) {
						for (AbstractCpsObject cps : cat.getObjects()) {
							if (value.toString().compareTo(cps.getObjName()) == 0) {
								File checkPath = new File(cps.getImage());
								if (checkPath.exists()) {
									imgR = new ImageIcon(cps.getImage()).getImage().getScaledInstance(50, 50,
											java.awt.Image.SCALE_SMOOTH);
								} else {
									imgR = new ImageIcon(this.getClass().getResource(cps.getImage())).getImage()
											.getScaledInstance(50, 50, java.awt.Image.SCALE_SMOOTH);
								}
								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(this.getClass().getResource("/Images/folder.png")));
					}
				}

				return label;

			}
		};

		tree.setCellRenderer(customRenderer);

		tree.addMouseListener(new MouseAdapter() {
			public void mouseReleased(MouseEvent e) {
				try {
					if (dragging) {
						if (((JScrollPane) tabbedPane.getSelectedComponent()).getViewport()
								.getComponent(0) instanceof UpperNodeCanvas) {
							UpperNodeCanvas unc = ((UpperNodeCanvas) ((JScrollPane) tabbedPane.getSelectedComponent())
									.getViewport().getComponent(0));

							int x = (int) unc.getMousePosition().getX();
							int y = (int) unc.getMousePosition().getY();

							if (x > unc.borderPos) {

								AbstractCpsObject h = null;
								if (tempCps instanceof HolonObject) {
									h = new HolonObject(tempCps);
								}
								if (tempCps instanceof HolonSwitch) {
									h = new HolonSwitch(tempCps);
								}
								if (tempCps instanceof HolonTransformer) {
									h = new HolonTransformer(tempCps);
								}

								h.setPosition(x, y);

								controller.addObjUpperNode(h, unc.upperNode);
								unc.invalidate();
								unc.repaint();
							}
						} else {
							int x = (int) canvas.getMousePosition().getX();
							int y = (int) canvas.getMousePosition().getY();

							AbstractCpsObject h = null;
							if (tempCps instanceof HolonObject) {
								h = new HolonObject(tempCps);
							}
							if (tempCps instanceof HolonSwitch) {
								h = new HolonSwitch(tempCps);
							}
							if (tempCps instanceof HolonTransformer) {
								h = new HolonTransformer(tempCps);
							}

							h.setPosition(x, y);

							controller.addObjectCanvas(h);
							canvas.invalidate();
							canvas.repaint();
						}
						controller.calculateStateForCurrentTimeStep();
						dragging = false;
					}
				} catch (Exception eex) {
				}
				frmCyberPhysical.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
			}
		});

		popmenuEdit.add(editItem);
		editItem.setEnabled(false);
		editItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
			}
		});
		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 (AbstractCpsObject 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 (AbstractCpsObject 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(50, 50,
												java.awt.Image.SCALE_SMOOTH);
									} else {
										img = new ImageIcon(this.getClass().getResource(cps.getImage())).getImage()
												.getScaledInstance(50, 50, java.awt.Image.SCALE_SMOOTH);
									}
									tempCps = cps;
									dragging = true;
									Cursor cursor = Toolkit.getDefaultToolkit().createCustomCursor(img, new Point(0, 0),
											"Image");
									frmCyberPhysical.setCursor(cursor);
								}
							}
						}
					}
				} catch (Exception eex) {
				}
			}
		});
		editItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				// Remove the selected Object object
				addObjectPopUP = new AddObjectPopUp(true, tempCps, catOfObjToBeEdited);
				addObjectPopUP.setCategory(catOfObjToBeEdited);
				addObjectPopUP.setController(controller);
				addObjectPopUP.setVisible(true);
			}
		});
		scrollPane1.setViewportView(tree);

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

		panel.add(toolBar);
		toolBar.add(comboBox);
		comboBox.setModel(new DefaultComboBoxModel(comboBoxCat));
		// Add Buttonnew DefaultComboBoxModel(comboBoxCat)
		btnAdd.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {

				Object nodeInfo = tree.getLastSelectedPathComponent();
				String selectedOption = comboBox.getSelectedItem().toString();
				DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) nodeInfo;
				try {

					switch (selectedOption) {

					case "Category":
						String catName = JOptionPane.showInputDialog(Languages.getLanguage()[56]);
						if (catName.length() != 0) {
							controller.addCategory(catName);
						}
						break;
					case "Object":
						if (selectedNode == null) {
							JOptionPane.showMessageDialog(new JFrame(),
									Languages.getLanguage()[57] + selectedOption + ".");
						}
						if (selectedNode.getLevel() == 1) {
							AbstractCpsObject tmp = new HolonObject("");
							addObjectPopUP = new AddObjectPopUp(false, tmp, null);
							addObjectPopUP.setVisible(true);
							addObjectPopUP.setController(controller);
							addObjectPopUP.setCategory(selectedNode.toString());
						}
						break;

					default:
						addObjectAction(selectedOption, selectedNode);
						break;
					}
				} catch (Exception e) {
					// TODO: handle exception
				}
				tree.repaint();
			}
		});
		/**
		 * Pop up - About Us with some important information about the
		 * developers, source and programming stuff
		 */
		aboutUs.addMouseListener(new MouseAdapter() {
			@Override
			public void mousePressed(MouseEvent e) {
				aboutUsPopUp = new AboutUsPopUp();
				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) {
				selectedElements.clear();
				holonEleNamesDisplayed = Languages.getLanguage()[25];
				// If any empty space is clicked
				if (temp == null || temp.getID() != model.getSelectedObjectID()) {
					unitGraph.empty();
					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) {
					unitGraph.repaintWithNewSwitch((HolonSwitch) temp);
					unitGraph.fillArrayofBooleans();
				}
				// Write new data in the PropertyTable
				updCon.paintProperties(temp);
				// New Tab with NodeOfNode
				if (doubleClick() && MouseEvent.BUTTON3 != e.getButton() && temp instanceof CpsUpperNode) {
					openNewUpperNodeTab();
				}
			}

			@Override
			public void mouseReleased(MouseEvent e) {
				updCon.refreshTableHolonElement(model.getMultiTable(), model.getSingleTable());
				updCon.refreshTableProperties(model.getPropertyTable());
				if (model.getSelectedCpsObjects().size() > 1) {
					model.getTableHolonElement().setModel(model.getMultiTable());
				} else if (model.getSelectedCpsObjects().size() == 1) {
					model.getTableHolonElement().setModel(model.getSingleTable());
				}
			}

		});

		toolBar.add(btnAdd);

		// Del Button
		btnDel.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {

				Object nodeInfo = tree.getLastSelectedPathComponent();
				if (nodeInfo != null) {
					DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) nodeInfo;
					String nodeName = selectedNode.getUserObject().toString();
					int depthOfNode = selectedNode.getLevel();

					switch (depthOfNode) {
					case 1:
						int dialogResult = JOptionPane.showConfirmDialog(null, 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(new JFrame(), selectObjBeforeErase);
					}
				} else {
					JOptionPane.showMessageDialog(new JFrame(), selectObjBeforeErase);
				}
				tree.repaint();
			}
		});
		toolBar.add(btnDel);

		frmCyberPhysical.getContentPane().add(splitPane);

		mntmNew.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				if (model.getObjectsOnCanvas().size() != 0) {
					int newWarning = JOptionPane.YES_NO_OPTION;
					int dialogForNewWarning = JOptionPane.showConfirmDialog(null, 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);
				unitGraph.empty();
				elementGraph.setText(Languages.getLanguage()[25]);
				canvas.tempCps = null;
				canvas.repaint();
				IdCounter.resetCounter();
				IdCounterElem.resetCounter();
			}
		});

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

			}

			private void menuFileExitActionPerformed(java.awt.event.ActionEvent evt) {
				JFileChooser fileChooser = new JFileChooser();
				JFrame test = new JFrame();
				FileNameExtensionFilter jsonFilter = new FileNameExtensionFilter("*.json", "json");
				fileChooser.setFileFilter(jsonFilter);

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

					try {
						controller.loadFile(file.getAbsolutePath());
						canvas.repaint();
						ArrayList<HolonElement> tempList = new ArrayList<>();
						for (AbstractCpsObject cps : model.getObjectsOnCanvas()) {
							if (cps instanceof HolonObject) {
								for (HolonElement h : ((HolonObject) cps).getElements()) {
									tempList.add(h);
									unitGraph.repaintWithNewElement(tempList);
									unitGraph.fillArrayofValue();
									tempList.remove(0);
								}
							} else if (cps instanceof HolonSwitch) {
								unitGraph.repaintWithNewSwitch((HolonSwitch) cps);
								unitGraph.fillArrayofBooleans();
							}
						}
						unitGraph.empty();
						tree.repaint();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		});

		mntmSave.addActionListener(new java.awt.event.ActionListener() {
			@Override
			public void actionPerformed(java.awt.event.ActionEvent evt) {

				menuSaveActionPerformed(evt);

			}

			private void menuSaveActionPerformed(java.awt.event.ActionEvent evt) {
				JFileChooser fileChooser = new JFileChooser();
				JFrame test = new JFrame();
				FileNameExtensionFilter jsonFilter = new FileNameExtensionFilter("*.json", "json");
				fileChooser.setFileFilter(jsonFilter);

				if (fileChooser.showSaveDialog(test) == JFileChooser.APPROVE_OPTION) {
					String file = fileChooser.getSelectedFile().getPath();
					if (!file.endsWith(".json"))
						file += ".json";
					try {
						controller.saveFile(new File(file).getAbsolutePath());
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		});
		englishBtn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				Languages.setLanguage(0);
				refreshLanguages();
				updCon.refreshTableProperties(model.getPropertyTable());
			}
		});
		spanishBtn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				Languages.setLanguage(1);
				refreshLanguages();
				updCon.refreshTableProperties(model.getPropertyTable());
			}
		});
		germanBtn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				Languages.setLanguage(2);
				refreshLanguages();
				updCon.refreshTableProperties(model.getPropertyTable());
			}
		});
		czechBtn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				Languages.setLanguage(3);
				refreshLanguages();
				updCon.refreshTableProperties(model.getPropertyTable());
			}
		});
		chineseBtn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				Languages.setLanguage(4);
				refreshLanguages();
				updCon.refreshTableProperties(model.getPropertyTable());
				;
			}
		});

		mntmUndo.addActionListener(new java.awt.event.ActionListener() {

			@Override
			public void actionPerformed(java.awt.event.ActionEvent evt) {

				menuUndoActionPerformed(evt);

			}

			private void menuUndoActionPerformed(java.awt.event.ActionEvent evt) {
				try {
					controller.loadFile(controller.getUndoSave());
					canvas.repaint();
					ArrayList<HolonElement> tempList = new ArrayList<>();
					for (AbstractCpsObject cps : model.getObjectsOnCanvas()) {
						if (cps instanceof HolonObject) {
							for (HolonElement h : ((HolonObject) cps).getElements()) {
								tempList.add(h);
								unitGraph.repaintWithNewElement(tempList);
								unitGraph.fillArrayofValue();
								tempList.remove(0);
							}
						} else if (cps instanceof HolonSwitch) {
							unitGraph.repaintWithNewSwitch((HolonSwitch) cps);
							unitGraph.fillArrayofBooleans();
						}
					}
					unitGraph.empty();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}

		});

		mntmRedo.addActionListener(new java.awt.event.ActionListener() {

			@Override
			public void actionPerformed(java.awt.event.ActionEvent evt) {

				menuRedoActionPerformed(evt);

			}

			private void menuRedoActionPerformed(java.awt.event.ActionEvent evt) {
				try {
					controller.loadFile(controller.getRedoSave());
					canvas.repaint();
					ArrayList<HolonElement> tempList = new ArrayList<>();
					for (AbstractCpsObject cps : model.getObjectsOnCanvas()) {
						if (cps instanceof HolonObject) {
							for (HolonElement h : ((HolonObject) cps).getElements()) {
								tempList.add(h);
								unitGraph.repaintWithNewElement(tempList);
								unitGraph.fillArrayofValue();
								tempList.remove(0);
							}
						} else if (cps instanceof HolonSwitch) {
							unitGraph.repaintWithNewSwitch((HolonSwitch) cps);
							unitGraph.fillArrayofBooleans();
						}
					}
					unitGraph.empty();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}

		});

		timePanel = new TimePanel(model, controller);
		timePanel.setBorder(null);
		((JSlider) (timePanel.getComponent(1))).addChangeListener(new ChangeListener() {

			@Override
			public void stateChanged(ChangeEvent e) {
				int i = model.getCurIteration();
				controller.calculateStateForTimeStep(i);
				unitGraph.repaint();
				statSplitPane.repaintGraphs();
			}
		});
		splitPane.setRightComponent(splitPane1);
		splitPane.setDividerLocation(200);
		splitPane1.setDividerLocation(500);
		splitPaneCanvasConsole.setDividerLocation(500);

		splitPane.setLeftComponent(scrollPane1);
		splitPaneCanvasConsole.setLeftComponent(panelTapped_SimMenu);
		tabbedPane.addTab("View", canvasSP);
		tabbedPane.addTab("Statistics", statScrollPane);
		tabbedPane.addTab("Holon", holonCanvas);

		splitPaneCanvasConsole.setRightComponent(console);
		splitPane1.setLeftComponent(splitPaneCanvasConsole);
		splitPane1.setRightComponent(splitHolonElPro);

		splitPane1.setResizeWeight(0.9);

		splitHolonElPro.setDividerLocation(400);
		splitHolonElPro.setTopComponent(splitGraphHolonEl);
		splitHolonElPro.setBottomComponent(scrollProperties);
		splitGraphHolonEl.setDividerLocation(150);
		splitGraphHolonEl.setTopComponent(scrollGraph);
		splitGraphHolonEl.setBottomComponent(scrollElements);
		canvasSP.setViewportView(canvas);
		// holonSP.setViewportView(holonCanvas);
		panelTapped_SimMenu.setLayout(new BorderLayout());
		panelTapped_SimMenu.add(simMenu, BorderLayout.NORTH);
		panelTapped_SimMenu.add(tabbedPane);
		simMenu.setBackground(new Color(240, 240, 240));

		panelTapped_SimMenu.setBorder(null);
		tabbedPane.setBorder(null);
		scrollProperties.setBorder(null);
		scrollGraph.setBorder(null);
		scrollElements.setBorder(null);
		splitPane.setBorder(null);
		splitPane1.setBorder(null);
		splitPaneCanvasConsole.setBorder(null);
		splitHolonElPro.setBorder(null);
		splitGraphHolonEl.setBorder(null);
		panelHolonEl.setBorder(null);
		canvasSP.setBorder(null);
		// holonSP.setBorder(null);

		tableHolonElementScrollPane.setBorder(null);

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

		String autoPath = System.getProperty("user.home") + "/HolonGUI/Autosave/";
		File dest = new File(autoPath);
		if (dest.listFiles().length > 1) {
			int dialogButton = JOptionPane.YES_NO_OPTION;
			int dialogResult = JOptionPane.showConfirmDialog(null, "Old autosave file was found, should it be loaded?",
					warningText, dialogButton);
			if (dialogResult == JOptionPane.YES_OPTION) {
				if (dest.exists()) {
					model.setAutoSaveNr(dest.listFiles().length - 1);
					mntmRedo.doClick();
				} else {
					JOptionPane.showMessageDialog(frmCyberPhysical, "Autosave could not be loaded.");
					setUpAutoSave(dest);
				}
			} else {
				setUpAutoSave(dest);
			}
		}
	}

	/**
	 * Sets up autosave if no old one is loaded at the beginning
	 * 
	 * @param dest
	 *            path to save-folder
	 */
	public void setUpAutoSave(File dest) {
		controller.deleteDirectory(dest);
		dest.mkdirs();
		try {
			controller.autoSave();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			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
	 */
	public void addObjectAction(String objType, DefaultMutableTreeNode selectedNode) {
		if (selectedNode == null) {
			JOptionPane.showMessageDialog(new JFrame(),
					"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("Please enter a Name for the " + objType);
				Category cat = controller.searchCategory(selectedNode.getUserObject().toString());

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

					case "Switch":
						controller.addSwitch(cat, objname);
						break;
					}
				}
			} else {
				JOptionPane.showMessageDialog(new JFrame(),
						"Objects can not be added to Objects. Please select a Category.");
			}
		}
	}

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

			private static final long serialVersionUID = 1L;

			{
				DefaultMutableTreeNode node1;
				for (Category c : categories) {
					node1 = new DefaultMutableTreeNode(c.getName());

					// kann eventuell umgeändert werden
					for (AbstractCpsObject obj : c.getObjects()) {
						node1.add(new DefaultMutableTreeNode(obj.getObjName()));
					}
					add(node1);
				}

			}
		}));
	}

	/**
	 * 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
	 */
	public JFrame getFrmCyberPhysical() {
		return frmCyberPhysical;
	}

	/**
	 * Adds a Popup.
	 * 
	 * @param component
	 *            Component
	 * @param popup
	 *            PopupMenu
	 */
	private static void addPopup(Component component, final JPopupMenu popup) {
		component.addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				if (e.isPopupTrigger()) {
					showMenu(e);
				}
			}

			public void mouseReleased(MouseEvent e) {
				if (e.isPopupTrigger()) {
					showMenu(e);
				}
			}

			private void showMenu(MouseEvent e) {
				popup.show(e.getComponent(), e.getX(), e.getY());
			}

		});
	}

	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]);
		canvasSize.setText(tempArray[12]);
		mnHelp.setText(tempArray[13]);
		aboutUs.setText(tempArray[14]);
		mntmEditEdges.setText(tempArray[15]);
		mnLanguage.setText(tempArray[16]);

		// Tables
		for (int i = 0; i < columnNamesMulti.length; i++) {
			columnNamesMulti[i] = tempArray[i + 17];
		}
		model.getMultiTable().setColumnIdentifiers(columnNamesMulti);
		for (int i = 0; i < columnNamesSingle.length; i++) {
			columnNamesSingle[i] = tempArray[i + 18];
		}
		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];
		// SimMenu
		simMenu.simButton.setText(Languages.getLanguage()[83]);
		simMenu.simSpeedLabel.setText(Languages.getLanguage()[84]);
		simMenu.algoFolderButton.setText(Languages.getLanguage()[85]);
		// 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
	 * 
	 * @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() {

		if (((JScrollPane) tabbedPane.getSelectedComponent()).getViewport().getComponent(0) instanceof MyCanvas) {
			unc = new UpperNodeCanvas(model, controller, (CpsUpperNode) temp, "");
		} else {
			unc = new UpperNodeCanvas(model, controller, (CpsUpperNode) temp,
					((UpperNodeCanvas) ((JScrollPane) tabbedPane.getSelectedComponent()).getViewport()
							.getComponent(0)).path + " -> ");
		}
		unc.setShowedInformation(canvas.getShowedInformation());

		// check if tab already open for clicked NodeOfNode
		boolean dupl = false;
		for (int i = 3; i < tabbedPane.getTabCount() && dupl == false; i++) {
			if (((UpperNodeCanvas) ((JScrollPane) tabbedPane.getComponentAt(i)).getViewport().getComponent(0)).upperNode
					.getID() == temp.getID()) {
				dupl = true;
				tabbedPane.setSelectedComponent(tabbedPane.getComponentAt(i));
			}
		}
		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) {
					unitGraph.empty();
					holonEleNamesDisplayed = "None ";
					elementGraph.setText(holonEleNamesDisplayed);
					temp = ((UpperNodeCanvas) ((JScrollPane) tabbedPane.getSelectedComponent()).getViewport()
							.getComponent(0)).tempCps;
					if (doubleClick() && MouseEvent.BUTTON3 != e.getButton() && temp instanceof CpsUpperNode) {
						openNewUpperNodeTab();
					}
					if (temp instanceof HolonSwitch) {
						unitGraph.repaintWithNewSwitch((HolonSwitch) temp);
						unitGraph.fillArrayofBooleans();
					}
				}
			});

			JScrollPane sp = new JScrollPane(unc);
			sp.setBorder(null);
			tabbedPane.add(temp.getName(), sp);
			tabbedPane.setSelectedComponent(sp);
			tabbedPane.setTabComponentAt(tabbedPane.getTabCount() - 1, new ButtonTabComponent(tabbedPane));
			temp = null;
		}
	}

}
