package net.knarcraft.serverlauncher.userinterface;

import net.knarcraft.serverlauncher.profile.Collection;
import net.knarcraft.serverlauncher.server.Server;
import net.knarcraft.serverlauncher.profile.Profile;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Objects;
import java.util.Scanner;
import java.util.concurrent.Executors;

import static java.awt.Frame.NORMAL;
import static javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE;

/**
 * Generates a GUI.
 *
 * @author		Kristian Knarvik <kristian.knarvik@knett.no>
 * @version	0.0.0.1
 * @since		0.0.0.1
 */
public class GUI implements ActionListener {

    private JFrame frame;
    //Menu
    private JCheckBoxMenuItem chckbxmntmRunInBackground, chckbxmntmDelayStartup, chckbxmntmDownloadJars; //Options
    private JMenuItem mntmErrors, mntmSetup, mntmManualUpdate; //Help
    private JMenuItem mntmRunInBackground, mntmDelayStartup, mntmDownloadJars; //Info/options
    private JMenuItem mntmAbout, mntmStory; //Info/about
    //Basic controls
    private JButton btnStartServer, btnStopServer, addServer, backup, addProfile, delProfile;
    private JComboBox<String> profiles;
    private final JLabel lblStatuslabel = new JLabel("Servers are stopped");
    //Server controls
    private JComboBox<String> targetServer;
    private JComboBox<String> targetPlayer;
    private JButton btnKick, btnBan, btnOp, btnDeop, btnCustomCommand, btnSaveserver, btnReload, btnServerConsoles;
    private JTextField customCommand;
    //Text
    private String setupText;
    private String runInBackgroundText;
    private String delayStartupText;
    private String downloadJarsText;
    private String aboutText;

    private final ArrayList<String> globalPlayers;

    private JTabbedPane serversPane;

    private SystemTray tray;
    private TrayIcon trayIcon;


    /**
     * Create the application window.
     */
    public GUI() {
        initialize(440, 170);
        loadMessages();
        this.globalPlayers = new ArrayList<>();
    }

    public GUI(int width, int height) {
        initialize(width, height);
        loadMessages();
        this.globalPlayers = new ArrayList<>();
    }

    public JTabbedPane getPane() {
        return this.serversPane;
    }

    public void setStatus(String text) {
        this.lblStatuslabel.setText(text);
    }

    public void addPlayer(String name) {
        this.globalPlayers.add(name);
        this.updatePlayers();
    }

    public void removePlayer(String name) {
        for (int i = 0; i < this.globalPlayers.size(); i++) {
            if (this.globalPlayers.get(i).equals(name)) {
                this.globalPlayers.remove(i);
            }
        }
        this.updatePlayers();
    }

    public void updateProfiles() {
        this.profiles.removeAllItems();
        for (Profile profile : Profile.getProfiles()) {
            this.profiles.addItem(profile.getName());
        }
    }

    public Dimension getSize() {
        return frame.getContentPane().getSize();
    }

    /**
     * Updates GUI according to current settings.
     */
    public void update() {
        serversPane.removeAll();
        for (Collection collection : Profile.getCurrent().getCollections()) {
            serversPane.addTab(collection.getName(), collection.getServerTab().getPanel());
        }
        chckbxmntmRunInBackground.setState(Profile.getCurrent().getRunInBackground());
        chckbxmntmDelayStartup.setState(Profile.getCurrent().getDelayStartup() > 0);
        chckbxmntmDownloadJars.setState(Profile.getCurrent().getDownloadJars());
        this.targetServer.removeAllItems();
        this.targetServer.addItem("All");
        for (Collection collection : Profile.getCurrent().getCollections()) {
            this.targetServer.addItem(collection.getName());
        }
    }

    /**
     * Creates the GUI,
     */
    private void initialize(int width, int height) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException |
                UnsupportedLookAndFeelException |
                InstantiationException |
                IllegalAccessException e
                ) {
            e.printStackTrace();
        }

        frame = new JFrame("Minecraft server launcher");
        frame.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
        frame.getContentPane().setPreferredSize(new Dimension(width, height));
        ImageIcon img;
        try {
            img = new ImageIcon(ImageIO.read(GUI.class.getResourceAsStream("/files/GUIIcon.png")));
            } catch (IOException | IllegalArgumentException e) {
            img = new ImageIcon("files/GUIIcon.png");
        }
        frame.setIconImage(img.getImage());

        JMenuBar menuBar = new JMenuBar();
        frame.setJMenuBar(menuBar);

        JMenu mnOptions = new JMenu("Options");
        menuBar.add(mnOptions);

        chckbxmntmRunInBackground = new JCheckBoxMenuItem("Run in background on exit");
        mnOptions.add(chckbxmntmRunInBackground);
        chckbxmntmRunInBackground.addActionListener(this);

        chckbxmntmDelayStartup = new JCheckBoxMenuItem("Delay Startup");
        mnOptions.add(chckbxmntmDelayStartup);
        chckbxmntmDelayStartup.addActionListener(this);

        chckbxmntmDownloadJars = new JCheckBoxMenuItem("Download jars");
        mnOptions.add(chckbxmntmDownloadJars);
        chckbxmntmDownloadJars.addActionListener(this);

        JMenu mnHelp = new JMenu("Help");
        menuBar.add(mnHelp);

        mntmErrors = new JMenuItem("Errors");
        mnHelp.add(mntmErrors);
        mntmErrors.addActionListener(this);

        mntmSetup = new JMenuItem("Setup");
        mnHelp.add(mntmSetup);
        mntmSetup.addActionListener(this);

        mntmManualUpdate = new JMenuItem("Manual update");
        mnHelp.add(mntmManualUpdate);
        mntmManualUpdate.addActionListener(this);

        JMenu mnInfo = new JMenu("Info");
        menuBar.add(mnInfo);

        JMenu mnOptionsInfo = new JMenu("Options");
        mnInfo.add(mnOptionsInfo);

        mntmRunInBackground = new JMenuItem("Run in background on exit");
        mnOptionsInfo.add(mntmRunInBackground);
        mntmRunInBackground.addActionListener(this);

        mntmDelayStartup = new JMenuItem("Delay Startup");
        mnOptionsInfo.add(mntmDelayStartup);
        mntmDelayStartup.addActionListener(this);

        mntmDownloadJars = new JMenuItem("Download jars");
        mnOptionsInfo.add(mntmDownloadJars);
        mntmDownloadJars.addActionListener(this);

        JMenu mnAbout = new JMenu("About");
        mnInfo.add(mnAbout);

        mntmAbout = new JMenuItem("About");
        mnAbout.add(mntmAbout);
        mntmAbout.addActionListener(this);

        mntmStory = new JMenuItem("Story");
        mnAbout.add(mntmStory);
        mntmStory.addActionListener(this);

        JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
        frame.getContentPane().add(tabbedPane);

        JPanel panelBasic = new JPanel();
        tabbedPane.addTab("Control panel", null, panelBasic, null);
        SpringLayout sl_panel = new SpringLayout();
        panelBasic.setLayout(sl_panel);

        JLabel lblBasicControls = new JLabel("Basic controls");
        sl_panel.putConstraint(SpringLayout.NORTH, lblBasicControls, 10, SpringLayout.NORTH, panelBasic);
        panelBasic.add(lblBasicControls);

        btnStartServer = new JButton("Start servers");
        sl_panel.putConstraint(SpringLayout.WEST, lblBasicControls, 0, SpringLayout.WEST, btnStartServer);
        sl_panel.putConstraint(SpringLayout.NORTH, btnStartServer, 6, SpringLayout.SOUTH, lblBasicControls);
        sl_panel.putConstraint(SpringLayout.WEST, btnStartServer, 10, SpringLayout.WEST, panelBasic);
        panelBasic.add(btnStartServer);
        btnStartServer.addActionListener(this);

        btnStopServer = new JButton("Stop servers");
        sl_panel.putConstraint(SpringLayout.NORTH, btnStopServer, 0, SpringLayout.NORTH, btnStartServer);
        sl_panel.putConstraint(SpringLayout.WEST, btnStopServer, 6, SpringLayout.EAST, btnStartServer);
        panelBasic.add(btnStopServer);
        btnStopServer.addActionListener(this);

        JLabel lblProfile = new JLabel("Profile");
        sl_panel.putConstraint(SpringLayout.NORTH, lblProfile, 6, SpringLayout.SOUTH, btnStartServer);
        sl_panel.putConstraint(SpringLayout.WEST, lblProfile, 10, SpringLayout.WEST, panelBasic);
        panelBasic.add(lblProfile);

        addProfile = new JButton("+");
        sl_panel.putConstraint(SpringLayout.NORTH, addProfile, 6, SpringLayout.SOUTH, lblProfile);
        sl_panel.putConstraint(SpringLayout.WEST, addProfile, 10, SpringLayout.WEST, panelBasic);
        panelBasic.add(addProfile);
        addProfile.addActionListener(this);

        delProfile = new JButton("-");
        sl_panel.putConstraint(SpringLayout.NORTH, delProfile, 0, SpringLayout.NORTH, addProfile);
        sl_panel.putConstraint(SpringLayout.WEST, delProfile, 6, SpringLayout.EAST, addProfile);
        panelBasic.add(delProfile);
        delProfile.addActionListener(this);

        profiles = new JComboBox<>();
        sl_panel.putConstraint(SpringLayout.NORTH, profiles, 0, SpringLayout.NORTH, addProfile);
        sl_panel.putConstraint(SpringLayout.WEST, profiles, 6, SpringLayout.EAST, delProfile);
        sl_panel.putConstraint(SpringLayout.EAST, profiles, 124, SpringLayout.EAST, delProfile);
        panelBasic.add(profiles);
        profiles.addActionListener(this);

        sl_panel.putConstraint(SpringLayout.NORTH, lblStatuslabel, 6, SpringLayout.SOUTH, addProfile);
        sl_panel.putConstraint(SpringLayout.SOUTH, lblStatuslabel, -10, SpringLayout.SOUTH, panelBasic);
        sl_panel.putConstraint(SpringLayout.WEST, lblStatuslabel, 10, SpringLayout.WEST, panelBasic);
        sl_panel.putConstraint(SpringLayout.EAST, lblStatuslabel, -10, SpringLayout.EAST, panelBasic);
        panelBasic.add(lblStatuslabel);

        addServer = new JButton("Add server");
        sl_panel.putConstraint(SpringLayout.NORTH, addServer, 0, SpringLayout.NORTH, btnStartServer);
        sl_panel.putConstraint(SpringLayout.WEST, addServer, 6, SpringLayout.EAST, btnStopServer);
        panelBasic.add(addServer);
        addServer.addActionListener(this);

        backup = new JButton("Backup");
        sl_panel.putConstraint(SpringLayout.NORTH, backup, 0, SpringLayout.NORTH, btnStartServer);
        sl_panel.putConstraint(SpringLayout.WEST, backup, 6, SpringLayout.EAST, addServer);
        panelBasic.add(backup);
        backup.addActionListener(this);

        JPanel controlServers = new JPanel();
        tabbedPane.addTab("Control servers", null, controlServers, null);
        SpringLayout sl_panel_1 = new SpringLayout();
        controlServers.setLayout(sl_panel_1);

        targetServer = new JComboBox<>();
        sl_panel_1.putConstraint(SpringLayout.NORTH, targetServer, 10, SpringLayout.NORTH, controlServers);
        controlServers.add(targetServer);

        targetPlayer = new JComboBox<>();
        sl_panel_1.putConstraint(SpringLayout.NORTH, targetPlayer, 6, SpringLayout.SOUTH, targetServer);
        targetPlayer.setEditable(true);
        controlServers.add(targetPlayer);

        btnKick = new JButton("Kick");
        sl_panel_1.putConstraint(SpringLayout.NORTH, btnKick, 10, SpringLayout.NORTH, controlServers);
        sl_panel_1.putConstraint(SpringLayout.WEST, btnKick, 6, SpringLayout.EAST, targetServer);
        sl_panel_1.putConstraint(SpringLayout.EAST, btnKick, 104, SpringLayout.WEST, btnKick);
        sl_panel_1.putConstraint(SpringLayout.SOUTH, targetServer, 0, SpringLayout.SOUTH, btnKick);
        controlServers.add(btnKick);
        btnKick.addActionListener(this);

        btnBan = new JButton("Ban");
        sl_panel_1.putConstraint(SpringLayout.NORTH, btnBan, 6, SpringLayout.SOUTH, btnKick);
        sl_panel_1.putConstraint(SpringLayout.WEST, btnBan, 6, SpringLayout.EAST, targetPlayer);
        sl_panel_1.putConstraint(SpringLayout.EAST, btnBan, 104, SpringLayout.WEST, btnBan);
        sl_panel_1.putConstraint(SpringLayout.SOUTH, targetPlayer, 0, SpringLayout.SOUTH, btnBan);
        controlServers.add(btnBan);
        btnBan.addActionListener(this);

        btnOp = new JButton("OP");
        sl_panel_1.putConstraint(SpringLayout.NORTH, btnOp, 10, SpringLayout.NORTH, controlServers);
        sl_panel_1.putConstraint(SpringLayout.WEST, btnOp, 6, SpringLayout.EAST, btnKick);
        sl_panel_1.putConstraint(SpringLayout.EAST, btnOp, -10, SpringLayout.EAST, controlServers);
        controlServers.add(btnOp);
        btnOp.addActionListener(this);

        btnDeop = new JButton("DEOP");
        sl_panel_1.putConstraint(SpringLayout.WEST, btnDeop, 6, SpringLayout.EAST, btnBan);
        sl_panel_1.putConstraint(SpringLayout.NORTH, btnDeop, 5, SpringLayout.SOUTH, btnOp);
        sl_panel_1.putConstraint(SpringLayout.EAST, btnDeop, -10, SpringLayout.EAST, controlServers);
        controlServers.add(btnDeop);
        btnDeop.addActionListener(this);

        JLabel lblTargetServer = new JLabel("Target server");
        sl_panel_1.putConstraint(SpringLayout.WEST, targetServer, 6, SpringLayout.EAST, lblTargetServer);
        sl_panel_1.putConstraint(SpringLayout.EAST, targetServer, 121, SpringLayout.EAST, lblTargetServer);
        sl_panel_1.putConstraint(SpringLayout.NORTH, lblTargetServer, 10, SpringLayout.NORTH, controlServers);
        sl_panel_1.putConstraint(SpringLayout.SOUTH, lblTargetServer, 0, SpringLayout.SOUTH, targetServer);
        sl_panel_1.putConstraint(SpringLayout.WEST, lblTargetServer, 10, SpringLayout.WEST, controlServers);
        controlServers.add(lblTargetServer);

        JLabel lblTargetPlayer = new JLabel("Target player");
        sl_panel_1.putConstraint(SpringLayout.WEST, targetPlayer, 7, SpringLayout.EAST, lblTargetPlayer);
        sl_panel_1.putConstraint(SpringLayout.EAST, targetPlayer, 122, SpringLayout.EAST, lblTargetPlayer);
        sl_panel_1.putConstraint(SpringLayout.NORTH, lblTargetPlayer, 6, SpringLayout.SOUTH, lblTargetServer);
        sl_panel_1.putConstraint(SpringLayout.SOUTH, lblTargetPlayer, 0, SpringLayout.SOUTH, targetPlayer);
        sl_panel_1.putConstraint(SpringLayout.WEST, lblTargetPlayer, 0, SpringLayout.WEST, lblTargetServer);
        controlServers.add(lblTargetPlayer);

        btnCustomCommand = new JButton("Custom command");
        sl_panel_1.putConstraint(SpringLayout.WEST, btnCustomCommand, 250, SpringLayout.WEST, controlServers);
        sl_panel_1.putConstraint(SpringLayout.EAST, btnCustomCommand, 0, SpringLayout.EAST, btnOp);
        controlServers.add(btnCustomCommand);
        btnCustomCommand.addActionListener(this);
        frame.getRootPane().setDefaultButton(btnCustomCommand);

        customCommand = new JTextField();
        sl_panel_1.putConstraint(SpringLayout.WEST, customCommand, 10, SpringLayout.WEST, controlServers);
        sl_panel_1.putConstraint(SpringLayout.EAST, customCommand, -6, SpringLayout.WEST, btnCustomCommand);
        sl_panel_1.putConstraint(SpringLayout.NORTH, btnCustomCommand, 0, SpringLayout.NORTH, customCommand);
        sl_panel_1.putConstraint(SpringLayout.SOUTH, customCommand, 0, SpringLayout.SOUTH, btnCustomCommand);
        controlServers.add(customCommand);
        customCommand.setColumns(10);

        btnSaveserver = new JButton("Save server");
        sl_panel_1.putConstraint(SpringLayout.NORTH, customCommand, 6, SpringLayout.SOUTH, btnSaveserver);
        sl_panel_1.putConstraint(SpringLayout.NORTH, btnSaveserver, 6, SpringLayout.SOUTH, btnBan);
        sl_panel_1.putConstraint(SpringLayout.WEST, btnSaveserver, 0, SpringLayout.WEST, btnKick);
        sl_panel_1.putConstraint(SpringLayout.EAST, btnSaveserver, 104, SpringLayout.WEST, btnKick);
        sl_panel_1.putConstraint(SpringLayout.EAST, btnSaveserver, 104, SpringLayout.WEST, btnKick);
        controlServers.add(btnSaveserver);
        btnSaveserver.addActionListener(this);

        btnReload = new JButton("Reload");
        sl_panel_1.putConstraint(SpringLayout.NORTH, btnReload, 6, SpringLayout.SOUTH, btnDeop);
        sl_panel_1.putConstraint(SpringLayout.WEST, btnReload, 0, SpringLayout.WEST, btnDeop);
        sl_panel_1.putConstraint(SpringLayout.EAST, btnReload, 0, SpringLayout.EAST, btnOp);
        controlServers.add(btnReload);
        btnReload.addActionListener(this);

        btnServerConsoles = new JButton("View server consoles");
        sl_panel_1.putConstraint(SpringLayout.NORTH, btnServerConsoles, 0, SpringLayout.NORTH, btnSaveserver);
        sl_panel_1.putConstraint(SpringLayout.WEST, btnServerConsoles, 0, SpringLayout.WEST, lblTargetServer);
        sl_panel_1.putConstraint(SpringLayout.EAST, btnServerConsoles, 0, SpringLayout.EAST, targetServer);
        controlServers.add(btnServerConsoles);
        btnServerConsoles.addActionListener(this);

        JPanel panel_2 = new JPanel();
        tabbedPane.addTab("Servers", null, panel_2, null);
        SpringLayout sl_panel_2 = new SpringLayout();
        panel_2.setLayout(sl_panel_2);

        JTabbedPane tabbedPane_1 = new JTabbedPane(JTabbedPane.TOP);
        sl_panel_2.putConstraint(SpringLayout.NORTH, tabbedPane_1, 0, SpringLayout.NORTH, panel_2);
        sl_panel_2.putConstraint(SpringLayout.WEST, tabbedPane_1, 0, SpringLayout.WEST, panel_2);
        sl_panel_2.putConstraint(SpringLayout.SOUTH, tabbedPane_1, 0, SpringLayout.SOUTH, panel_2);
        sl_panel_2.putConstraint(SpringLayout.EAST, tabbedPane_1, 0, SpringLayout.EAST, panel_2);
        panel_2.add(tabbedPane_1);

        this.serversPane = tabbedPane_1;
        tabbedPane_1.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);

        frame.validate();
        frame.pack();
        frame.setVisible(true);
        tray();
    }

    /**
     * Prepares the system tray if available.
     */
    private void tray() {
        if (SystemTray.isSupported()) {
            tray = SystemTray.getSystemTray();
            Image trayImage = Toolkit.getDefaultToolkit().getImage("files/GUIIcon.png");
            PopupMenu popup = new PopupMenu();
            trayIcon = new TrayIcon(trayImage, "Minecraft Server Launcher", popup);
            trayIcon.setImageAutoSize(true);
            ActionListener exitListener= e -> {
                try {
                    Profile.getCurrent().save();
                } catch (FileNotFoundException e1) {
                    e1.printStackTrace();
                }
                System.exit(0);
            };

            MenuItem restoreItem = new MenuItem("Restore");
            popup.add(restoreItem);
            restoreItem.addActionListener(e -> {
                frame.setExtendedState(NORMAL);
                tray.remove(trayIcon);
                frame.setVisible(true);
            });
            MenuItem exitItem = new MenuItem("Exit");
            exitItem.addActionListener(exitListener);
            popup.add(exitItem);
            frame.addWindowStateListener(e -> {
                if (e.getNewState() == NORMAL) {
                    tray.remove(trayIcon);
                    frame.setVisible(true);
                }
            });

            frame.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    if (Profile.getCurrent().getRunInBackground() && SystemTray.isSupported()) {
                        try {
                            tray.add(trayIcon);
                            frame.setVisible(false);
                        } catch (AWTException e1) {
                            e1.printStackTrace();
                        }
                    } else {
                        try {
                            Profile.getCurrent().save();
                        } catch (FileNotFoundException e1) {
                            e1.printStackTrace();
                        }
                        stop();
                        System.exit(0);
                    }
                }
            });

            trayIcon.addMouseListener(new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent e) {
                    if(e.getClickCount() >= 1 && e.getButton() == MouseEvent.BUTTON1){
                        frame.setExtendedState(NORMAL);
                        tray.remove(trayIcon);
                        frame.setVisible(true);
                    }
                }
            });
        } else {
            frame.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    try {
                        Profile.getCurrent().save();
                    } catch (FileNotFoundException e1) {
                        e1.printStackTrace();
                    }
                    stop();
                    System.exit(0);
                }
            });
        }
    }

    /**
     * Hides the gui to the tray,
     */
    public void hide() {
        frame.setVisible(false);
        try {
            tray.add(trayIcon);
        } catch (AWTException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        String selectedServerValue = null, selectedPlayerValue = null;
        Object selectedServer = targetServer.getSelectedItem();
        if (selectedServer != null) {
            selectedServerValue = selectedServer.toString();
        }
        Object selectedPlayer = targetPlayer.getSelectedItem();
        if (selectedPlayer != null) {
            selectedPlayerValue = selectedPlayer.toString();
        }
        if (e.getSource() == chckbxmntmRunInBackground) {
            background();
        } else if (e.getSource() == chckbxmntmDelayStartup) {
            delay();
        } else if (e.getSource() == chckbxmntmDownloadJars) {
            downloadJars();
        } else if (e.getSource() == mntmErrors) {
            goToURL("https://knarcraft.net/Bungeeminecraftserverlauncher/Info/");
        } else if (e.getSource() == mntmSetup) {
            JOptionPane.showMessageDialog(
                    null,
                    setupText,
                    "Setup",
                    JOptionPane.INFORMATION_MESSAGE
            );
        } else if (e.getSource() == mntmManualUpdate) {
            goToURL("https://knarcraft.net/Downloads/Bungeeminecraftserverlauncher/");
        } else if (e.getSource() == mntmRunInBackground) {
            JOptionPane.showMessageDialog(
                    null,
                    runInBackgroundText,
                    "Run in background",
                    JOptionPane.INFORMATION_MESSAGE
            );
        } else if (e.getSource() == mntmDelayStartup) {
            JOptionPane.showMessageDialog(
                    null,
                    delayStartupText,
                    "Delay startup",
                    JOptionPane.INFORMATION_MESSAGE
            );
        } else if (e.getSource() == mntmDownloadJars) {
            JOptionPane.showMessageDialog(
                    null,
                    downloadJarsText,
                    "Download jars",
                    JOptionPane.INFORMATION_MESSAGE
            );
        } else if (e.getSource() == mntmAbout) {
            JOptionPane.showMessageDialog(
                    null,
                    aboutText,
                    "About",
                    JOptionPane.INFORMATION_MESSAGE
            );
        } else if (e.getSource() == mntmStory) {
            goToURL("https://knarcraft.net/Bungeeminecraftserverlauncher/Story/");
        } else if (e.getSource() == btnStartServer) {
            try {
                Profile.getCurrent().save();
            } catch (FileNotFoundException e1) {
                e1.printStackTrace();
            }
            Executors.newSingleThreadExecutor().execute(Server::startServers);
        } else if (e.getSource() == btnStopServer) {
            stop();
        } else if (e.getSource() == addServer) {
            String serverName = JOptionPane.showInputDialog("Name of server: ");
            Profile.getCurrent().addCollection(serverName);
            this.update();
            Profile.getCurrent().updateConsoles();
        } else if (e.getSource() == backup) {
            backup();
        } else if (e.getSource() == addProfile) {
            Profile.addProfile(JOptionPane.showInputDialog("Profile name: "));
            updateProfiles();
        } else if (e.getSource() == delProfile) {
            Object selected = profiles.getSelectedItem();
            if (selected != null) {
                Profile.removeProfile(selected.toString());
                updateProfiles();
            }
        } else if (e.getSource() == profiles) {
            try {
                changeProfile();
            } catch (FileNotFoundException e1) {
                e1.printStackTrace();
            }
        } else if (e.getSource() == btnKick) {
            if (selectedServerValue != null && selectedPlayerValue != null) {
                Profile.getCurrent().sendCommand(selectedServerValue, "kick " + selectedPlayerValue);
            }
        } else if (e.getSource() == btnBan) {
            if (selectedServerValue != null && selectedPlayerValue != null) {
                Profile.getCurrent().sendCommand(selectedServerValue, "ban " + selectedPlayerValue);
            }
        } else if (e.getSource() == btnOp) {
            if (selectedServerValue != null && selectedPlayerValue != null) {
                Profile.getCurrent().sendCommand(selectedServerValue, "op " + selectedPlayerValue);
            }
        } else if (e.getSource() == btnDeop) {
            if (selectedServerValue != null && selectedPlayerValue != null) {
                Profile.getCurrent().sendCommand(selectedServerValue, "deop " + selectedPlayerValue);
            }
        } else if (e.getSource() == btnCustomCommand) {
            if (selectedServerValue != null) {
                Profile.getCurrent().sendCommand(selectedServerValue, customCommand.getText());
                customCommand.setText("");
            }
        } else if (e.getSource() == btnSaveserver) {
            if (selectedServerValue != null) {
                Profile.getCurrent().sendCommand(selectedServerValue, "save-all");
            }
        } else if (e.getSource() == btnReload) {
            if (selectedServerValue != null) {
                Profile.getCurrent().sendCommand(selectedServerValue, "reload");
            }
        } else if (e.getSource() == btnServerConsoles) {
            ServerConsoles.show();
        }
    }

    /**
     * Saves the previous profile and loads data from the new profile.
     */
    private void changeProfile() throws FileNotFoundException {
        Profile.getCurrent().save();
        Object current = this.profiles.getSelectedItem();
        if (current != null) {
            Profile.setCurrent(current.toString());
        }
        this.update();
        Profile.getCurrent().updateConsoles();
    }

    /**
     * Stops all servers
     */
    private void stop() {
        try {
            setStatus("Servers are stopping");
            Server.stop();
            setStatus("Servers are stopped");
        } catch (IOException e1) {
            JOptionPane.showMessageDialog(
                    null,
                    "Could not stop server.",
                    "Error",
                    JOptionPane.ERROR_MESSAGE
            );
            e1.printStackTrace();
        }
    }

    /**
     * Asks the user for a delay if checked, and sets the value to the current profile.
     */
    private void delay() {
        Object selected = profiles.getSelectedItem();
        if (selected != null) {
            Profile profile = Profile.getProfile(selected.toString());
            if (chckbxmntmDelayStartup.isSelected()) {
                Objects.requireNonNull(profile).setDelayStartup(
                        Integer.parseInt(JOptionPane.showInputDialog("Seconds to delay: "))
                );
            } else {
                Objects.requireNonNull(profile).setDelayStartup(0);
            }
        } else {
            JOptionPane.showMessageDialog(
                    null,
                    "No profile selected",
                    "Error",
                    JOptionPane.ERROR_MESSAGE
            );
        }
    }

    /**
     * Saves the runInBackground setting to the current profile.
     */
    private void background() {
        Object selected = profiles.getSelectedItem();
        if (selected != null) {
            Profile profile = Profile.getProfile(selected.toString());
            Objects.requireNonNull(profile).setRunInBackground(chckbxmntmRunInBackground.isSelected());
        } else {
            JOptionPane.showMessageDialog(
                    null,
                    "No profile selected",
                    "Error",
                    JOptionPane.ERROR_MESSAGE
            );
        }
    }

    /**
     * Saves the downloadJars setting to the current profile.
     */
    private void downloadJars() {
        Object selected = profiles.getSelectedItem();
        if (selected != null) {
            Profile profile = Profile.getProfile(selected.toString());
            Objects.requireNonNull(profile).setDownloadJars(chckbxmntmDownloadJars.isSelected());
        } else {
            JOptionPane.showMessageDialog(
                    null,
                    "No profile selected",
                    "Error",
                    JOptionPane.ERROR_MESSAGE
            );
        }
    }

    /**
     * Copies all server directories to a folder specified by the user.
     */
    private void backup() {
        JFileChooser chooser = new JFileChooser();
        chooser.setCurrentDirectory(new java.io.File("."));
        chooser.setDialogTitle("Backup folder");
        chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        chooser.setAcceptAllFileFilterUsed(false);

        if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
            File path = chooser.getSelectedFile();
            for (Collection collection : Profile.getCurrent().getCollections()) {
                if (!collection.getServer().getPath().equals("") && collection.getServer().isEnabled()) {
                    String name = collection.getServer().getName();
                    File srcFolder = new File(collection.getServer().getPath());
                    File destFolder = new File(path, name);
                    if (!destFolder.exists()) {
                        if (destFolder.mkdirs()) {
                            try {
                                copyFolder(srcFolder, destFolder);
                            } catch (IOException e) {
                                e.printStackTrace();
                                return;
                            }
                        } else {
                            return;
                        }
                    }
                }
            }
        }
    }

    /**
     * Updates the list of players currently online on the selected server,
     */
    private void updatePlayers() {
        String selectedServerValue;
        Object selectedServer = targetServer.getSelectedItem();
        if (selectedServer != null) {
            targetPlayer.removeAllItems();
            selectedServerValue = selectedServer.toString();
            if (selectedServerValue.equals("All")) {
                for (String player : this.globalPlayers) targetPlayer.addItem(player);
            } else {
                for (String player : Profile.getCurrent().getCollection(selectedServerValue).getServer().getPlayers()) {
                    targetPlayer.addItem(player);
                }
            }
        }
    }

    /**
     * Opens an url in the user's default application.
     *
     * @param url   URL to open
     */
    private void goToURL(String url) {
        java.awt.Desktop desktop = java.awt.Desktop.getDesktop();
        try {
            desktop.browse(new URI(url));
        } catch (URISyntaxException | IOException e1) {
            e1.printStackTrace();
        }
    }

    /**
     * Loads popup messages from a text file.
     */
    private void loadMessages() {
        Scanner file;
        try {
            file = new Scanner(new File("config/menumsg.csv"));
        } catch (FileNotFoundException e) {
            file = new Scanner(GUI.class.getResourceAsStream("/config/menumsg.csv"));
        }
        while (file.hasNextLine()) {
            String[] line = file.nextLine().split("=");
            String content = line[1].replaceAll("_BREAK_", System.getProperty("line.separator"));
            switch (line[0]) {
                case "setup":
                    setupText = content;
                    break;
                case "runinbk":
                    runInBackgroundText = content;
                    break;
                case "delaystartup":
                    delayStartupText = content;
                    break;
                case "downloadjars":
                    downloadJarsText = content;
                    break;
                case "about":
                    aboutText = content;
            }
        }
    }

    /**
     * Recursivly copies a folder to another location
     *
     * @param src           The folder to copy
     * @param dest          Target destination
     * @throws IOException  If we can't start a file stream
     */
    private void copyFolder(File src, File dest) throws IOException{
        if (!src.isDirectory()) {
            InputStream in = new FileInputStream(src);
            OutputStream out = new FileOutputStream(dest);
            byte[] buffer = new byte[1024];
            int length;
            while ((length = in.read(buffer)) > 0){
                out.write(buffer, 0, length);
            }
            in.close();
            out.close();
            this.setStatus("File copied from " + src + " to " + dest);
        } else {
            if(!dest.exists()){
                if (dest.mkdir()) {
                    this.setStatus("Directory copied from " + src + "  to " + dest);
                } else {
                    return;
                }
            }
            String files[] = src.list();
            if (files != null) {
                for (String file : files) {
                    File srcFile = new File(src, file);
                    File destFile = new File(dest, file);
                    copyFolder(srcFile, destFile);
                }
            }
        }
    }
}