package ui.view;

import java.awt.*;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.stream.Collectors;
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.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
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.JToolBar;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;
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 org.apache.commons.compress.archivers.ArchiveException;

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

import classes.AbstractCpsObject;
import classes.Category;
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;

import javax.swing.SwingConstants;
import javax.swing.Box;

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

    // for doubleclick
    private boolean click = false;

    private JFrame frmCyberPhysical;

    private final AlgorithmMenu algorithmMenu;

    private JTabbedPane tabTemp; // tabbedPane or tabbedPane2
    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 JCheckBox consoleLogCheckBox = new JCheckBox("Show program console log");
    private final JMenuItem mntmOpen = new JMenuItem("Open");
    private final JMenuItem mntmNew = new JMenuItem("New");
    private final JMenuItem mntmSave = new JMenuItem("Save");
    private final JMenuItem mntmAboutUs = new JMenuItem("About Us");
    private final JMenuItem mntmCanvasSize = new JMenuItem("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();
    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 JTabbedPane tabbedPane2 = new JTabbedPane(JTabbedPane.TOP);
    private JSplitPane tempSplit;
    private boolean initSplit = true;

    private final JPopupMenu popmenuEdit = new JPopupMenu();
    private final JMenuItem editItem = new JMenuItem("Edit Object");
    private String catOfObjToBeEdited;
    private FlexiblePane flexPane;
    private final StatisticPanel statSplitPane;
    private final JScrollPane statScrollPane;
    private UpperNodeCanvas unc;
    private JPanel contentPane;

    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 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 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);
            }
        }
    };
    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;

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

    // 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 final Console console = new Console();
    private final MyCanvas canvas;
    private final HolonCanvas holonCanvas;
    private final 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 int yProThisOneClick;
    private int xProThisOneClick;
    private AbstractCpsObject temp = null;
    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 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", "Quantity", "Activated",
            "Flex. activated"};
    private final String[] columnNamesSingle = {"Nr.", "Device", "Energy", "Flexibility", "Quantity", "Activated",
            "Flex. activated"};
    private final ArrayList<PropertyTable> tables = new ArrayList<>();
    private final 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 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: ");
    private Component horizontalStrut = Box.createHorizontalStrut(20);

    /**
     * Create the application.
     *
     * @param control the Controller
     */
    public GUI(Control control) {
        this.controller = control;
        this.model = control.getModel();
        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);
        controller.setCanvas(canvas);
        model.setConsole(console);
        algorithmMenu = new AlgorithmMenu(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.setExtendedState(JFrame.MAXIMIZED_BOTH);
        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") + "/.config/HolonGUI/Autosave"));
                    System.exit(0);
                }
            }
        });

        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.loadAutoSave(controller.getUndoSave());
                    canvas.repaint();
                    unitGraph.update(model.getObjectsOnCanvas());
                    updateUpperNodes();
                } 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.loadAutoSave(controller.getRedoSave());
                    canvas.repaint();
                    unitGraph.update(model.getObjectsOnCanvas());
                    updateUpperNodes();
                } catch (IOException ex) {
                    // TODO Auto-generated catch block
                    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) {

                if (tabbedPane.getMousePosition() != null) {
                    tabTemp = tabbedPane;
                } else if (tabbedPane2.getMousePosition() != null) {
                    tabTemp = tabbedPane2;
                }
                model.getSelectedCpsObjects().clear();
                // Uppernode Canvas?
                if (((JScrollPane) tabTemp.getSelectedComponent()).getViewport()
                        .getComponent(0) instanceof UpperNodeCanvas) {
                    UpperNodeCanvas uNC = (UpperNodeCanvas) ((JScrollPane) tabTemp.getSelectedComponent()).getViewport()
                            .getComponent(0);
                    for (AbstractCpsObject cps : uNC.upperNode.getNodes()) {
                        controller.addSelectedObject(cps);
                    }
                    uNC.repaint();
                    // or Canvas?
                } else if (((JScrollPane) tabTemp.getSelectedComponent()).getViewport()
                        .getComponent(0) instanceof MyCanvas) {
                    for (AbstractCpsObject 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) {
                if (tabbedPane.getMousePosition() != null) {
                    tabTemp = tabbedPane;
                } else if (tabbedPane2.getMousePosition() != null) {
                    tabTemp = tabbedPane2;
                }
                // Uppernode Canvas?
                if (((JScrollPane) tabTemp.getSelectedComponent()).getViewport()
                        .getComponent(0) instanceof UpperNodeCanvas) {
                    UpperNodeCanvas uNC = (UpperNodeCanvas) ((JScrollPane) tabTemp.getSelectedComponent()).getViewport()
                            .getComponent(0);
                    for (AbstractCpsObject 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
                            if (cps instanceof CpsUpperNode) {
                                boolean splitView = false;
                                for (int i = 4; i < tabbedPane.getTabCount(); i++) {
                                    if (tabbedPane.getComponentAt(i) == null) {
                                        splitView = true;
                                    } else if (((UpperNodeCanvas) ((JScrollPane) tabbedPane.getComponentAt(i))
                                            .getViewport().getComponent(0)).upperNode.getId() == cps.getId()) {
                                        ((ButtonTabComponent) tabbedPane.getTabComponentAt(i)).removeTabs();
                                        break;
                                    }
                                }
                                // If SplitView is on and the view on
                                // tabbedPane2 is the deleted upperNode
                                try {
                                    if (splitView
                                            && ((UpperNodeCanvas) ((JScrollPane) tabbedPane2.getSelectedComponent())
                                            .getViewport().getComponent(0)).upperNode.getId() == cps.getId()) {
                                        ((ButtonTabComponent) tabbedPane
                                                .getTabComponentAt(tabbedPane2.getSelectedIndex())).removeTabs();
                                    }
                                } catch (Exception e2) {
                                }
                            }
                        }
                    }
                    uNC.repaint();

                    // or Canvas?
                } else if (((JScrollPane) tabTemp.getSelectedComponent()).getViewport()
                        .getComponent(0) instanceof MyCanvas) {
                    boolean save = false;
                    for (int j = 0; j < model.getSelectedCpsObjects().size(); j++) {
                        AbstractCpsObject 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
                        if (cps instanceof CpsUpperNode) {
                            boolean splitView = false;
                            for (int i = 4; i < tabbedPane.getTabCount(); i++) {
                                if (tabbedPane.getComponentAt(i) == null) {
                                    splitView = true;
                                } else if (((UpperNodeCanvas) ((JScrollPane) tabbedPane.getComponentAt(i)).getViewport()
                                        .getComponent(0)).upperNode.getId() == cps.getId()) {
                                    ((ButtonTabComponent) tabbedPane.getTabComponentAt(i)).removeTabs();
                                    break;
                                }
                            }
                            // If SplitView is on and the view on
                            // tabbedPane2 is the deleted upperNode
                            try {
                                if (splitView && ((UpperNodeCanvas) ((JScrollPane) tabbedPane2.getSelectedComponent())
                                        .getViewport().getComponent(0)).upperNode.getId() == cps.getId()) {
                                    ((ButtonTabComponent) tabbedPane.getTabComponentAt(tabbedPane2.getSelectedIndex()))
                                            .removeTabs();
                                }
                            } catch (Exception e2) {
                            }
                        }
                    }
                    canvas.repaint();
                }
                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);
                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) {
                if (tabbedPane.getMousePosition() != null) {
                    tabTemp = tabbedPane;
                } else {
                    tabTemp = tabbedPane2;
                }
                if (!model.getSelectedCpsObjects().isEmpty()) {
                    if (((JScrollPane) tabTemp.getSelectedComponent()).getViewport()
                            .getComponent(0) instanceof UpperNodeCanvas)
                        controller.copy(((UpperNodeCanvas) ((JScrollPane) tabTemp.getSelectedComponent()).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 (tabbedPane.getMousePosition() != null) {
                        tabTemp = tabbedPane;
                    } else {
                        if (!initSplit) {
                            tabTemp = tabbedPane2;
                        }
                    }
                    if (tabTemp != null && ((JScrollPane) tabTemp.getSelectedComponent()).getViewport()
                            .getComponent(0) instanceof UpperNodeCanvas) {

                        controller.paste(
                                ((UpperNodeCanvas) ((JScrollPane) tabTemp.getSelectedComponent()).getViewport()
                                        .getComponent(0)).upperNode,
                                ((JScrollPane) tabTemp.getSelectedComponent()).getViewport().getComponent(0)
                                        .getMousePosition());
                        unitGraph.update(model.getSelectedCpsObjects());
                        ((JScrollPane) tabTemp.getSelectedComponent()).getViewport().getComponent(0).repaint();
                    } else {
                        controller.paste(null, canvas.getMousePosition());
                        unitGraph.update(model.getSelectedCpsObjects());
                        canvas.repaint();
                    }
                } catch (HeadlessException | JsonParseException | UnsupportedFlavorException | IOException e1) {
                    // TODO Auto-generated catch block
                    JLabel message = new JLabel("The Clipboard information cannot be pasted into Application.");
                    JOptionPane.showMessageDialog(null, 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) {
                if (tabbedPane.getMousePosition() != null) {
                    tabTemp = tabbedPane;
                } else {
                    tabTemp = tabbedPane2;
                }
                if (!model.getSelectedCpsObjects().isEmpty()) {
                    if (((JScrollPane) tabTemp.getSelectedComponent()).getViewport()
                            .getComponent(0) instanceof UpperNodeCanvas)
                        controller.cut(((UpperNodeCanvas) ((JScrollPane) tabTemp.getSelectedComponent()).getViewport()
                                .getComponent(0)).upperNode);
                    else
                        controller.cut(null);
                    if (!model.getClipboradObjects().isEmpty()) {
                        canvas.itemPaste.setEnabled(true);
                    }
                    canvas.repaint();
                }
            }
        };
        actionMap.put(cntrlXDown, controlX);

        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(actionEvent -> {
            try {
                SearchPopUp dialog = new SearchPopUp(controller, canvas);
                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);
                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();
            edgePopUp.setCanvas(canvas);
            edgePopUp.setController(controller);
            edgePopUp.setVisible(true);
        });

        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) {
                // TODO: handle exception
            }

            tree.repaint();
        });
        mnNewMenuOptions.add(consoleLogCheckBox);
        consoleLogCheckBox.setSelected(true);
        consoleLogCheckBox.addActionListener(arg0 -> controller.setShowConsoleLog(consoleLogCheckBox.isSelected()));

        menuBar.add(mnNewMenuView);

        mnNewMenuView.add(mntmCanvasSize);
        mntmCanvasSize.addActionListener(actionEvent -> {
            CanvasResizePopUp popUp = new CanvasResizePopUp(model, controller, canvas, tabbedPane, tabbedPane2);
            popUp.setVisible(true);
        });

        mnNewMenuView.add(splitPane3);

        sizeSlider.setMinimum(15);
        sizeSlider.setMaximum(115);
        sizeSlider.addChangeListener(changeEvent -> {
            controller.setScale(sizeSlider.getValue());
            if (((JScrollPane) tabbedPane.getSelectedComponent()).getViewport()
                    .getComponent(0) instanceof UpperNodeCanvas) {
                ((JScrollPane) tabbedPane.getSelectedComponent()).getViewport().getComponent(0).repaint();
            } else {
                canvas.repaint();
            }
            if (!initSplit && ((JScrollPane) tabbedPane2.getSelectedComponent()).getViewport()
                    .getComponent(0) instanceof UpperNodeCanvas) {
                ((JScrollPane) tabbedPane2.getSelectedComponent()).getViewport().getComponent(0).repaint();
            } else {
                canvas.repaint();
            }
        });

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

        // Split View
        mntmSplitView.addActionListener(actionEvent -> {
            if (splitPaneCanvasConsole.getLeftComponent() instanceof JSplitPane) {
                initSplit = true;
                Component tempC = tabbedPane2.getSelectedComponent();
                tabbedPane.setComponentAt(tabbedPane2.getSelectedIndex(), tempC);
                tabbedPane2.removeAll();
                splitPaneCanvasConsole.setLeftComponent(tabbedPane);
            } else {
                for (int i = 0; i < tabbedPane.getTabCount(); i++) {
                    tabbedPane2.addTab(tabbedPane.getTitleAt(i), null);
                    if (i >= 4) {
                        // tabbedPane2.setTabComponentAt(tabbedPane.getTabCount()
                        // - 1,
                        // new ButtonTabComponent(tabbedPane, tabbedPane2));
                    }
                }
                if (tabbedPane.getSelectedComponent() == statScrollPane) {
                    tabbedPane.setComponentAt(0, null);
                    tabbedPane2.setComponentAt(0, canvasSP);
                    tabbedPane2.setSelectedIndex(0);
                } else {
                    tabbedPane.setComponentAt(1, null);
                    tabbedPane2.setComponentAt(1, statScrollPane);
                    tabbedPane2.setSelectedIndex(1);
                }
                tempSplit = new JSplitPane();
                tempSplit.setBorder(null);
                tempSplit.setRightComponent(tabbedPane2);
                tempSplit.setLeftComponent(tabbedPane);
                tempSplit.setDividerLocation(tabbedPane.getWidth() / 2);
                tempSplit.setResizeWeight(0.9);
                splitPaneCanvasConsole.setLeftComponent(tempSplit);
                initSplit = false;
            }
            contentPane.updateUI();
        });
        mnNewMenuView.add(mntmBackground);

        mntmBackground.addActionListener(actionEvent -> {
            if (((JScrollPane) tabbedPane.getSelectedComponent()).getViewport()
                    .getComponent(0) instanceof MyCanvas) {
                BackgroundPopUp backgroundDialog = new BackgroundPopUp(model, controller, canvas, null);
                backgroundDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
                backgroundDialog.setVisible(true);
            } else if (((JScrollPane) tabbedPane.getSelectedComponent()).getViewport()
                    .getComponent(0) instanceof UpperNodeCanvas) {
                UpperNodeCanvas uNodeCanvas = (UpperNodeCanvas) (((JScrollPane) tabbedPane.getSelectedComponent())
                        .getViewport().getComponent(0));
                BackgroundPopUp backgroundDialog = new BackgroundPopUp(model, controller, null,
                        uNodeCanvas.upperNode);
                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);

        menuBar.add(algorithmMenu);

        menuBar.add(mnHelp);

        mnHelp.add(mntmAboutUs);

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

        tabbedPane2.addChangeListener(changeEvent -> {
            if (tabbedPane2.getSelectedComponent() == null && !initSplit) {
                Component tempC = tabbedPane.getComponentAt(tabbedPane2.getSelectedIndex());
                tabbedPane.setComponentAt(tabbedPane2.getSelectedIndex(), null);
                tabbedPane2.setComponentAt(tabbedPane2.getSelectedIndex(), tempC);
                for (int i = 0; i < tabbedPane.getTabCount(); i++) {
                    if (tabbedPane2.getComponentAt(i) != null && tabbedPane2.getComponentAt(i) != tempC) {
                        tempC = tabbedPane2.getComponentAt(i);
                        tabbedPane2.setComponentAt(i, null);
                        tabbedPane.setComponentAt(i, tempC);
                        break;
                    }
                }
                if (tabbedPane.getSelectedIndex() == tabbedPane2.getSelectedIndex()) {
                    tabbedPane.setSelectedIndex((tabbedPane2.getSelectedIndex() + 1) % tabbedPane.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);
        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(lblSelectedElement);
        toolBarGraph.add(elementGraph);
        horizontalStrut = Box.createHorizontalStrut(toolBarGraph.getWidth() - resetGraphBtn.getWidth());

        toolBarGraph.add(horizontalStrut);
        resetGraphBtn.setHorizontalAlignment(SwingConstants.RIGHT);

        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(actionEvent -> {
            if (model.getSelectedCpsObjects().size() == 1) {
                AbstractCpsObject tempCpsObject = updCon.getActualCps();
                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());
                    contentPane.updateUI();
                }
            }
        });
        /*
         * 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();
                    for (HolonElement e : selectedElements) {
                        controller.deleteElementCanvas(obj.getId(), e.getId());
                        updCon.refreshTableHolonElement(model.getMultiTable(), model.getSingleTable());
                        updCon.refreshTableProperties(model.getPropertyTable());
                        controller.calculateStateForTimeStep(model.getCurIteration());
                        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());
                    }
                }
                updCon.refreshTableHolonElement(model.getMultiTable(), model.getSingleTable());
                updCon.refreshTableProperties(model.getPropertyTable());
                model.getEleToDelete().clear();
                selectedElements.clear();
            }
            updCon.refreshTableProperties(model.getPropertyTable());
            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() + " ";
                            }
                            unitGraph.repaintWithNewElement(selectedElements);
                        }
                        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() + " ";
                        unitGraph.repaintWithNewElement(selectedElements);
                    }
                } 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();

            }
        });

		/*
         * 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);
                // for 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) {
                            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) {
                            HolonElement eleBTemp = updCon.getActualHolonElement(null, yBMouse, 0, tables);
                            String newBStuff = model.getMultiTable().getValueAt(selectedValueBY, selectedValueBX)
                                    .toString();
                            Boolean bTemp = Boolean.parseBoolean(newBStuff);
                            eleBTemp.setActiveFlex(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);
                            }
                            // Flexibility
                            else if (selectedValueX == 4) {
                                Float ftemp = Float.parseFloat(newStuff);
                                eleTemp.setFlexibility(ftemp);
                            }
                            // Amount of Elements update
                            else if (selectedValueX == 5) {
                                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() / 7));
                    int selectedValueBX = (int) Math.floor(xBThis / (model.getTableHolonElement().getWidth() / 7));
                    if (updCon.getActualCps() != null && updCon.getActualCps().getClass() == HolonObject.class) {
                        // For active column (boolean with a checkbox)
                        if (selectedValueBX == 5) {
                            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);
                        } // For activeFlex column (boolean with a checkbox)
                        else if (selectedValueBX == 6) {
                            HolonElement eleBTemp = updCon
                                    .getActualHolonElement((HolonObject) updCon.getActualCps(), yBMouse, 0, tables);
                            String newBStuff = model.getSingleTable().getValueAt(selectedValueBY, selectedValueBX)
                                    .toString();
                            Boolean bTemp = Boolean.parseBoolean(newBStuff);
                            eleBTemp.setActiveFlex(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);
                            } // Flexibility
                            else if (selectedValueX == 3) {
                                Float ftemp = Float.parseFloat(newStuff);
                                eleTemp.setFlexibility(ftemp);
                            }
                            // Amount of Elements update
                            else if (selectedValueX == 4) {
                                Integer iTemp = Integer.parseInt(newStuff);
                                eleTemp.setAmount(iTemp);
                            }
                        }
                    }
                }
                updCon.refreshTableProperties(model.getPropertyTable());
                model.getSingleTable().fireTableDataChanged();
                controller.calculateStateForTimeStep(model.getCurIteration());
                contentPane.updateUI();
                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();
                }
                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 CpsUpperNode && 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 < tabbedPane.getTabCount(); index++) {
                            UpperNodeCanvas unc = ((UpperNodeCanvas) ((JScrollPane) tabbedPane.getComponent(index))
                                    .getViewport().getComponent(0));
                            if (unc.upperNode.getId() == updCon.getActualCps().getId()) {
                                tabbedPane.setTitleAt(index, unc.upperNode.getName());
                                tabbedPane.updateUI();
                                if (!initSplit) {
                                    tabbedPane2.setTitleAt(index, unc.upperNode.getName());
                                    tabbedPane2.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());
                        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(actionEvent -> unitGraph.reset());
        /*****************************
         * RIGHT CONTAINER DONE
         *****************************/

        frmCyberPhysical.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 (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 (tabbedPane.getMousePosition() != null) {
                            tabTemp = tabbedPane;
                        } else {
                            tabTemp = tabbedPane2;
                        }
                        if (((JScrollPane) tabTemp.getSelectedComponent()).getViewport()
                                .getComponent(0) instanceof UpperNodeCanvas) {
                            UpperNodeCanvas unc = ((UpperNodeCanvas) ((JScrollPane) tabTemp.getSelectedComponent())
                                    .getViewport().getComponent(0));

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

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

                                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();
                                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;

                            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.setXY((int) canvas.getMousePosition().getX(),
                                    (int) canvas.getMousePosition().getY());
                            canvas.repaint();
                        }
                        controller.calculateStateForCurrentTimeStep();
                        contentPane.updateUI();
                        dragging = false;
                    }
                } catch (Exception eex) {
                }
                frmCyberPhysical.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
            }
        });

        popmenuEdit.add(editItem);
        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 (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(32, 32,
                                                java.awt.Image.SCALE_SMOOTH);
                                    } else {
                                        img = new ImageIcon(this.getClass().getResource(cps.getImage())).getImage()
                                                .getScaledInstance(32, 32, 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(actionEvent -> {
            // 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.setAlignmentX(Component.LEFT_ALIGNMENT);
        toolBar.setFloatable(false);

        panel.add(toolBar);
        comboBox.setMaximumSize(new Dimension(100, 20));
        toolBar.add(comboBox);
        comboBox.setModel(new DefaultComboBoxModel(comboBoxCat));
        // Add Buttonnew DefaultComboBoxModel(comboBoxCat)
        btnAdd.addActionListener(actionEvent -> {
            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
         */
        mntmAboutUs.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) {

            }

            @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();
                    unitGraph.repaintWithNewSwitch((HolonSwitch) temp);
                    unitGraph.fillArrayofBooleans();
                }
                // Write new data in the PropertyTable
                updCon.paintProperties(temp);
                updCon.refreshTableHolonElement(model.getMultiTable(), model.getSingleTable());

                // New Tab with NodeOfNode
                if (doubleClick() && MouseEvent.BUTTON3 != e.getButton() && temp instanceof CpsUpperNode) {
                    openNewUpperNodeTab();
                    try {
                        controller.autoSave();
                    } catch (IOException e1) {
                        // TODO Auto-generated catch block
                        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());
            }
        });

        toolBar.add(btnAdd);

        // 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(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);
                    }
                } catch (Exception e2) {
                    // TODO: handle exception
                }

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

        frmCyberPhysical.getContentPane().add(splitPane);

        mntmNew.addActionListener(actionEvent -> {
            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);
            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(evt);
            }

            private void menuFileExitActionPerformed(ActionEvent evt) {
                JFileChooser fileChooser = new JFileChooser();
                JFrame test = new JFrame();
                FileNameExtensionFilter holonFilter = new FileNameExtensionFilter("Holon Save File(*.holon)", "holon");
                fileChooser.setFileFilter(holonFilter);

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

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

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

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

                if (fileChooser.showSaveDialog(test) == JFileChooser.APPROVE_OPTION) {
                    String file = fileChooser.getSelectedFile().getPath();
                    if (fileChooser.getFileFilter().equals(holonFilter)) {
                        if (!file.contains("."))
                            file += ".holon";
                    }
                    if (!file.endsWith(".holon")) {
                        String suffix = file.substring(file.lastIndexOf("."), file.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(null, message, "", JOptionPane.DEFAULT_OPTION,
                                JOptionPane.QUESTION_MESSAGE, null, options, options[1]);

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

                    try {
                        controller.saveFile(new File(file).getAbsolutePath());
                    } catch (IOException | ArchiveException e) {
                        // TODO Auto-generated catch block
                        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(evt);
            }

            private void menuUndoActionPerformed(ActionEvent evt) {
                try {
                    controller.loadAutoSave(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();
                        }
                    }
                    hideScrollGraph();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });

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

            private void menuRedoActionPerformed(ActionEvent evt) {
                try {
                    controller.loadAutoSave(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();
                        }
                    }
                    hideScrollGraph();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });

        timePanel = new TimePanel(model, controller);
        timePanel.setBorder(null);
        ((JSlider) (timePanel.getComponent(1))).addChangeListener(changeEvent -> {
            int i = model.getCurIteration();
            controller.calculateStateForTimeStep(i);
            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);
        splitPaneCanvasConsole.setDividerLocation(550);
        splitPaneCanvasConsole.setResizeWeight(0.9);

        splitPane.setLeftComponent(scrollPane1);
        splitPaneCanvasConsole.setLeftComponent(tabbedPane);
        tabbedPane.addTab("View", canvasSP);
        tabbedPane.addTab("Statistics", statScrollPane);
        tabbedPane.addTab("Holon", holonCanvas);
        flexPane = new FlexiblePane(controller);
        controller.setFlexiblePane(flexPane);
        controller.getModel().getObjectListeners().add(flexPane);
        tabbedPane.addTab("Flexibility", flexPane);

        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);
        algorithmMenu.setBackground(new Color(240, 240, 240));

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

        tableHolonElementScrollPane.setBorder(null);

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

        MouseAdapter focusCanvasAdapter = new FocusCanvasMouseAdapter();
        model.getTableHolonElement().addMouseListener(focusCanvasAdapter);
        tableProperties.addMouseListener(focusCanvasAdapter);
        console.getConsoleText().addMouseListener(focusCanvasAdapter);

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

        String autoPath = System.getProperty("user.home") + "/.config/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);
            }
        }

        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 showScrollGraph() {
        scrollGraph.setVisible(true);
        splitGraphHolonEl.setTopComponent(scrollGraph);
        splitGraphHolonEl.setDividerLocation(150);
    }

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

    /**
     * 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(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) {
                    try {
                        switch (objType) {

                            case "Switch":
                                controller.addSwitch(cat, objname);
                                break;
                        }
                    } catch (Exception e) {
                        // TODO: handle exception
                    }

                }
            } 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
     */
    private 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]);
        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];
        // SimMenu
        algorithmMenu.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 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() {
        // is the uppernode on tabbedPane or tabbedPane2
        if (tabbedPane.getMousePosition() != null) {
            tabTemp = tabbedPane;
        } else {
            tabTemp = tabbedPane2;
        }
        if (((JScrollPane) tabTemp.getSelectedComponent()).getViewport().getComponent(0) instanceof MyCanvas) {
            unc = new UpperNodeCanvas(model, controller, unitGraph, (CpsUpperNode) temp, "");

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

        // check if tab already open for clicked NodeOfNode
        boolean dupl = false;
        for (int i = 4; i < tabbedPane.getTabCount() && !dupl; i++) {
            if (tabbedPane.getComponentAt(i) != null && ((UpperNodeCanvas) ((JScrollPane) tabbedPane.getComponentAt(i))
                    .getViewport().getComponent(0)).upperNode.getId() == temp.getId()) {
                dupl = true;
                tabbedPane.setSelectedComponent(tabbedPane.getComponentAt(i));
            }
            if (!initSplit && tabbedPane2.getComponentAt(i) != null
                    && ((UpperNodeCanvas) ((JScrollPane) tabbedPane2.getComponentAt(i)).getViewport()
                    .getComponent(0)).upperNode.getId() == temp.getId()) {
                dupl = true;
                tabbedPane2.setSelectedComponent(tabbedPane2.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) {
                    hideScrollGraph();
                    holonEleNamesDisplayed = Languages.getLanguage()[25];
                    elementGraph.setText(holonEleNamesDisplayed);
                    if (tabbedPane.getMousePosition() != null) {
                        tabTemp = tabbedPane;
                    } else {
                        tabTemp = tabbedPane2;
                    }
                    temp = ((UpperNodeCanvas) ((JScrollPane) tabTemp.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);
            // Selected tabbed Pane = tabbedPane or tabbedPane2
            if (tabTemp == tabbedPane) {
                tabbedPane.add(temp.getName(), sp);
                tabbedPane.setSelectedComponent(sp);
                tabbedPane.setTabComponentAt(tabbedPane.getTabCount() - 1,
                        new ButtonTabComponent(tabbedPane, tabbedPane2));
                if (!initSplit) {
                    tabbedPane2.add(temp.getName(), null);
                    // tabbedPane2.setTabComponentAt(tabbedPane2.getTabCount() -
                    // 1,
                    // new ButtonTabComponent(tabbedPane, tabbedPane2));
                }
            } else {
                tabbedPane2.add(temp.getName(), sp);
                Component tempC = tabbedPane2.getSelectedComponent();
                tabbedPane2.setComponentAt(tabbedPane2.getSelectedIndex(), null);
                tabbedPane.setComponentAt(tabbedPane2.getSelectedIndex(), tempC);
                tabbedPane2.setSelectedComponent(sp);

                // tabbedPane2.setTabComponentAt(tabbedPane2.getTabCount() - 1,
                // new ButtonTabComponent(tabbedPane, tabbedPane2));

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

            temp = null;
        }
    }

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

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

        StatisticGraphPanel stat = new StatisticGraphPanel(model, controller, 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.getGraphTable().put(json.get("KEY").getAsString(), stat);
            model.getStatPanel().getGraphPanel().add(stat);
        }
    }

    private void updateUpperNodes() {
        for (Component comp : tabbedPane.getComponents()) {
            if (!(comp instanceof JScrollPane))
                continue;
            Component pane = ((JScrollPane) comp).getViewport().getComponent(0);
            if (pane instanceof UpperNodeCanvas) {
                temp = model.getHashcodeMap().get(((UpperNodeCanvas) pane).code);
                ((UpperNodeCanvas) pane).upperNode = (CpsUpperNode) temp;
            }
        }

    }

    /**
     * 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();
        }
    }
}
