package vermilion;

import JSSPF.*;
import relative.*;

import java.awt.Container;
import java.awt.Font;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import javax.swing.Box;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.filechooser.FileFilter;

/**
 * A main window into which an extensible interface can be loaded.
 */
public class MainFrame extends JFrame
{
    /**
     * The file extension for documents for the program during load/save.
     */
    public static final String DOC_FILE_EXTENSION = ".ufm";

    /**
     * A description for the file extension we use for documents.
     */
    public static final String DOC_FILE_DESCRIPTION = "*.UFM - Useful File MOD";

    // The scaling layout manager we use.
    private RelativeLayout mainLayout;

    // Private components of the preferences tab, which we handle ourselves.
    private JPanel prefsPanel;

    private DefaultListModel pluginList;
    private JList pluginListC;
    private DefaultListModel startupList;
    private JList startupListC;

    // Protected components, which are accessed by the window handlers.
    protected JComboBox sampleRateCombo;
    protected JComboBox bufferSizeCombo;
    protected JComboBox audioDeviceCombo;
    protected JButton audioTestButton;

    protected JMenuItem newItem;
    protected JMenuItem loadItem;
    protected JMenuItem saveItem;
    protected JMenuItem saveAsItem;
    protected JMenuItem helpItem;
    protected JMenuItem exitItem;

    protected JButton addStartupButton;
    protected JButton remStartupButton;

    protected JButton reloadFrameworkButton;
    protected JButton showHelpButton;

    protected JCheckBox startPopupCheckBox;
    protected JCheckBox loadDemoCheckBox;

    private MainFrameListener mainListener;

    // Publicly accessible parts of the main window, which plugins create
    // their own interface on.

    /**
     * The program's main tab control, where a plugin can create its own tab.
     */
    public JTabbedPane mainTabs;

    /**
     * The program's menu bar, which plugins can add menus to.
     */
    public JMenuBar mainMenu;

    /**
     * Creates a main frame including basic controls for handling
     * the user's document and preferences for what plugins are loaded
     * at startup.
     */
    public MainFrame()
    {
        super("Vermilion");

        setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        addWindowListener(new MainFrameCloseListener());


        setMinimumSize(new java.awt.Dimension(600, 450));
        setSize(new java.awt.Dimension(780, 560));

        setExtendedState(getExtendedState()|JFrame.MAXIMIZED_BOTH);

        mainLayout = new RelativeLayout(this);
        setLayout(mainLayout);

        setupInterface();
    }

    /**
     * Sets up the basic interface of the main window such as the File menu
     * and the main tab control, including the preferences tab. This is done
     * prior to the creation of other systems, during construction of the
     * window.
     */
    public void setupInterface()
    {
        Container panel = getContentPane();

        // Action listener for the main interface.
        mainListener = new MainFrameListener(this);

        // The 'File' menu.
        JMenu fileMenu = new JMenu("File");
        mainLayout.registerForFontSizeChanges(fileMenu);

        // 'New' menu item on the file menu.
        newItem = new JMenuItem("New");
        newItem.addActionListener(mainListener);
        mainLayout.registerForFontSizeChanges(newItem);
        fileMenu.add(newItem);

        // 'Load' menu item on the file menu.
        loadItem = new JMenuItem("Load...");
        loadItem.addActionListener(mainListener);
        mainLayout.registerForFontSizeChanges(loadItem);
        fileMenu.add(loadItem);

        // 'Save' menu item on the file menu.
        saveItem = new JMenuItem("Save");
        saveItem.addActionListener(mainListener);
        mainLayout.registerForFontSizeChanges(saveItem);
        fileMenu.add(saveItem);

        // 'Save as' menu item on the file menu.
        saveAsItem = new JMenuItem("Save As...");
        saveAsItem.addActionListener(mainListener);
        mainLayout.registerForFontSizeChanges(saveAsItem);
        fileMenu.add(saveAsItem);

        // 'Save as' menu item on the file menu.
        helpItem = new JMenuItem("Help");
        helpItem.addActionListener(mainListener);
        mainLayout.registerForFontSizeChanges(helpItem);
        fileMenu.add(helpItem);

        // 'Exit' menu item on the file menu.
        exitItem = new JMenuItem("Exit");
        exitItem.addActionListener(mainListener);
        mainLayout.registerForFontSizeChanges(exitItem);
        fileMenu.add(exitItem);


        mainMenu = new JMenuBar();
        mainMenu.add(Box.createHorizontalGlue());
        mainMenu.add(fileMenu);
        panel.add(mainMenu, new RelativePlacement(0, 0, 1000, 40));

        // The main tab of the program, where extensions will display themselves.
        mainTabs = new JTabbedPane();
        mainLayout.registerForFontSizeChanges(mainTabs);
        panel.add(mainTabs, new RelativePlacement(0, 40, 1000, 960));

        // The panel on which we will draw preferences.
        prefsPanel = new JPanel();
        prefsPanel.setLayout(new RelativeLayout(null));


        // List of all available plugins.
        pluginList = new DefaultListModel();
        pluginListC = new JList(pluginList);
        mainLayout.registerForFontSizeChanges(pluginListC);
        prefsPanel.add(pluginListC, new RelativePlacement(10, 10, 150, 300));


        // List of plugins loaded at startup.
        startupList = new DefaultListModel();
        startupListC = new JList(startupList);
        mainLayout.registerForFontSizeChanges(startupListC);
        prefsPanel.add(startupListC, new RelativePlacement(260, 10, 150, 300));


        // Add startup plugin button.
        addStartupButton = new JButton(">>>");
        addStartupButton.addActionListener(mainListener);
        mainLayout.registerForFontSizeChanges(addStartupButton, 1.5f);
        prefsPanel.add(addStartupButton, new RelativePlacement(170, 110, 80, 50));


        // Remove startup plugin button.
        remStartupButton = new JButton("<<<");
        remStartupButton.addActionListener(mainListener);
        mainLayout.registerForFontSizeChanges(remStartupButton, 1.5f);
        prefsPanel.add(remStartupButton, new RelativePlacement(170, 160, 80, 50));


        // Labels for the plugin lists.
        JLabel tLabel = new JLabel("Available Plugins", JLabel.CENTER);
        mainLayout.registerForFontSizeChanges(tLabel, 1.0f, "", Font.BOLD);
        prefsPanel.add(tLabel,  new RelativePlacement(10, 310, 150, 40));
        tLabel = new JLabel("Startup Plugins", JLabel.CENTER);
        mainLayout.registerForFontSizeChanges(tLabel, 1.0f, "", Font.BOLD);
        prefsPanel.add(tLabel,  new RelativePlacement(260, 310, 150, 40));


        // Audio device preference drop-down.
        audioDeviceCombo = new JComboBox();
        audioDeviceCombo.addActionListener(mainListener);
        mainLayout.registerForFontSizeChanges(audioDeviceCombo);
        prefsPanel.add(audioDeviceCombo, new RelativePlacement(110, 400, 200, 40));
        tLabel = new JLabel("Sound Device", JLabel.CENTER);
        mainLayout.registerForFontSizeChanges(tLabel, 1.0f, "", Font.BOLD);
        prefsPanel.add(tLabel,  new RelativePlacement(10, 400, 100, 40));


        // Audio device preference test button.
        audioTestButton = new JButton("Test");
        audioTestButton.addActionListener(mainListener);
        mainLayout.registerForFontSizeChanges(audioTestButton);
        prefsPanel.add(audioTestButton, new RelativePlacement(320, 420, 90, 100));


        // Audio samplerate preference drop-down.
        String[] sampleRates = new String[] { "22050", "32000", "44010", "48000", "64000", "96000" };
        sampleRateCombo = new JComboBox(sampleRates);
        sampleRateCombo.addActionListener(mainListener);
        mainLayout.registerForFontSizeChanges(sampleRateCombo);
        prefsPanel.add(sampleRateCombo, new RelativePlacement(110, 450, 200, 40));
        tLabel = new JLabel("Sample Rate", JLabel.CENTER);
        mainLayout.registerForFontSizeChanges(tLabel, 1.0f, "", Font.BOLD);
        prefsPanel.add(tLabel,  new RelativePlacement(10, 450, 100, 40));


        // Audio buffer size preference drop-down.
        String[] bufferSizes = new String[] { "1", "2", "3", "4", "6", "8", "12", "16" };
        bufferSizeCombo = new JComboBox(bufferSizes);
        bufferSizeCombo.addActionListener(mainListener);
        mainLayout.registerForFontSizeChanges(bufferSizeCombo);
        prefsPanel.add(bufferSizeCombo, new RelativePlacement(110, 500, 200, 40));
        tLabel = new JLabel("Buffer Size", JLabel.CENTER);
        mainLayout.registerForFontSizeChanges(tLabel, 1.0f, "", Font.BOLD);
        prefsPanel.add(tLabel, new RelativePlacement(10, 500, 100, 40));


        //Startup popup checkbox
        startPopupCheckBox = new JCheckBox("Show news on startup?");
        mainLayout.registerForFontSizeChanges(startPopupCheckBox);
        startPopupCheckBox.addActionListener(mainListener);
        prefsPanel.add(startPopupCheckBox, new RelativePlacement(10, 720, 300, 25));
        UsefulFileObjectSimple popupPref = (UsefulFileObjectSimple) Main.settings.getValue("Startup Popup Setting");
        if (popupPref != null && popupPref.longValue == 0)
            startPopupCheckBox.setSelected(false);
        else
            startPopupCheckBox.setSelected(true);


        //Startup demo song checkbox
        loadDemoCheckBox = new JCheckBox("Load demo on startup?");
        mainLayout.registerForFontSizeChanges(loadDemoCheckBox);
        loadDemoCheckBox.addActionListener(mainListener);
        prefsPanel.add(loadDemoCheckBox, new RelativePlacement(10, 750, 300, 25));
        UsefulFileObjectSimple demoPref = (UsefulFileObjectSimple) Main.settings.getValue("Startup Sound Setting");
        if (demoPref != null && demoPref.longValue == 0)
            loadDemoCheckBox.setSelected(false);
        else
            loadDemoCheckBox.setSelected(true);



        // Framework reload button.
        tLabel = new JLabel("** Save Your Composition Before Reinitialising **", JLabel.CENTER);
        mainLayout.registerForFontSizeChanges(tLabel, 1.0f, "", Font.BOLD);
        prefsPanel.add(tLabel, new RelativePlacement(10, 600, 400, 40));

        reloadFrameworkButton = new JButton("Reinitialise Framework");
        reloadFrameworkButton.addActionListener(mainListener);
        mainLayout.registerForFontSizeChanges(reloadFrameworkButton);
        prefsPanel.add(reloadFrameworkButton, new RelativePlacement(10, 650, 400, 40));


        // Help button.
        showHelpButton = new JButton("HELP");
        showHelpButton.addActionListener(mainListener);
        mainLayout.registerForFontSizeChanges(showHelpButton, 1.3f, "", Font.BOLD);
        prefsPanel.add(showHelpButton, new RelativePlacement(890, 10, 100, 60));

/*        JLabel helpPane = new JLabel();
        JScrollPane scrolly = new JScrollPane(helpPane);
        prefsPanel.add(scrolly, new RelativePlacement(420, 10, 570, 980));
        mainLayout.registerForFontSizeChanges(helpPane, 0.9f);

        // Read the help file.
        try
        {
            FileReader rdr = new FileReader("help/help.html");
            BufferedReader buf = new BufferedReader(rdr);

            String str = "";
            while (buf.ready())
            {
                str += buf.readLine();
            }

            rdr.close();

            helpPane.setText(str);
        }
        catch (Exception ex) {}
        */
        // Place the preferences tab.
        mainTabs.addTab("Preferences", prefsPanel);
    }

    /**
     * This method is called by plugins that wish to add an interface to the
     * main window.
     * @param name A title for the tab being added.
     * @param panel A panel on which the plugin can construct any interface it wishes.
     */
    public void addTab(String name, JPanel panel)
    {
        mainTabs.setVisible(false);
        mainTabs.insertTab(name, null, panel, name, 0);
        mainTabs.setVisible(true);

        mainTabs.setSelectedIndex(0);
    }

    /**
     * Allows a plugin to remove its tab from the interface when it is unloaded.
     * @param panel The panel passed to the window when the tab was added.
     */
    public void removeTab(JPanel panel)
    {
        for (int x = 0; x < mainTabs.getTabCount(); x++)
        {
            if (panel == mainTabs.getComponentAt(x))
            {
                mainTabs.removeTabAt(x);
                return;
            }
        }
    }

    /**
     * Allows a startup plugin to add a menu to the main window title bar.
     */
    public void addMenu(JMenu menu)
    {
        mainMenu.add(menu);
    }

    /**
     * Allows a startup plugin to remove its menu from the main window. This is
     * used during reinitialisation (and closing) of the framework.
     */
    public void removeMenu(JMenu menu)
    {
        mainMenu.remove(menu);
    }

    /**
     * Sets up options and initialises the preferences tab. This is done once
     * the other system componenets have been created.
     */
    public void initialise()
    {
        // Set up preferences tab using info from main components.
        ArrayList<PluginClassDef> allPlugins = Main.plugins.getPluginList();

        for (int x = 0; x < allPlugins.size(); x++)
        {
            PluginClassDef cls = allPlugins.get(x);
            if (cls.classType.equals("STARTUP"))
            {
                pluginList.addElement(cls.className);
            }
        }

        UsefulFileObjectList startupPlugins = (UsefulFileObjectList) Main.settings.getValue(SystemPluginManager.STARTUP_PLUGINS_PREF);
        if (startupPlugins != null)
        {
            for (UsefulFileObject obj : startupPlugins.arrayValue)
            {
                String str = ((UsefulFileObjectSimple) obj).strValue;
                startupList.addElement(str);
            }
        }


        // Pause automatic saving of preferences while we initialise the combos.
        mainListener.pauseSaving = true;

        try
        {
            int sampleRate = (int) ((UsefulFileObjectSimple) Main.settings.getValue("Audio/SampleRate")).longValue;
            for (int x = 0; x < sampleRateCombo.getItemCount(); x++)
            {
                if (sampleRateCombo.getItemAt(x).equals("" + sampleRate)) sampleRateCombo.setSelectedIndex(x);
            }
        }
        catch (Exception e) {}

        try
        {
            int bufferSize = (int) ((UsefulFileObjectSimple) Main.settings.getValue("Audio/BufferSize")).longValue;
            for (int x = 0; x < bufferSizeCombo.getItemCount(); x++)
            {
                if (bufferSizeCombo.getItemAt(x).equals("" + bufferSize)) bufferSizeCombo.setSelectedIndex(x);
            }
        }
        catch (Exception e) {}
        
        String[] devs = AudioThread.getDeviceNames();
        DefaultComboBoxModel m = new DefaultComboBoxModel(devs);
        audioDeviceCombo.setModel(m);

        try
        {
            String devName = ((UsefulFileObjectSimple) Main.settings.getValue("Audio/SoundDevice")).strValue;
            for (int x = 0; x < audioDeviceCombo.getItemCount(); x++)
            {
                if (audioDeviceCombo.getItemAt(x).equals("" + devName)) audioDeviceCombo.setSelectedIndex(x);
            }
        }
        catch (Exception e) {}

        mainListener.pauseSaving = false;
    }

    // Removes a plugin from the list of startup plugins.
    protected void remStartup()
    {
        String str = (String) startupListC.getSelectedValue();

        if (str != null)
        {
            UsefulFileObjectList startupPlugins = (UsefulFileObjectList) Main.settings.getValue(SystemPluginManager.STARTUP_PLUGINS_PREF);
            startupList.clear();

            for (int x = 0; x < startupPlugins.size(); x++)
            {
                UsefulFileObjectSimple obj = (UsefulFileObjectSimple) startupPlugins.get(x);

                if (str.equals(obj.strValue))
                {
                    startupPlugins.remove(x);
                    x--;
                }
                else
                {
                    startupList.addElement(obj.strValue);
                }
            }

            Main.settings.setValue(SystemPluginManager.STARTUP_PLUGINS_PREF, startupPlugins);
        }
    }

    // Adds a plugin to the list of startup plugins.
    protected void addStartup()
    {
        String str = (String) pluginListC.getSelectedValue();

        if (str != null)
        {
            UsefulFileObjectList startupPlugins = (UsefulFileObjectList) Main.settings.getValue(SystemPluginManager.STARTUP_PLUGINS_PREF);
            if (startupPlugins == null) startupPlugins = new UsefulFileObjectList();

            startupPlugins.add(new UsefulFileObjectSimple(str));
            startupList.addElement(str);

            Main.settings.setValue(SystemPluginManager.STARTUP_PLUGINS_PREF, startupPlugins);
        }
    }

    // Shows a file loading dialog, loading a file if one is chosen.
    protected void load()
    {
        JFileChooser jfd = new JFileChooser();
        jfd.setFileSelectionMode(JFileChooser.FILES_ONLY);
        jfd.setFileFilter(new FileFilter() {

            @Override
            public boolean accept(File f) {
                return (f.getName().endsWith(DOC_FILE_EXTENSION) || f.isDirectory());
            }

            @Override
            public String getDescription() {
                return DOC_FILE_DESCRIPTION;
            }
        });
        int result = jfd.showOpenDialog(Main.window);

        if (result == JFileChooser.APPROVE_OPTION)
        {
            if (jfd.getSelectedFile().exists())
            {
                Main.load(jfd.getSelectedFile().getAbsolutePath());
            }
        }
    }

    // Shows a file saving dialog, saving the file if one is chosen.
    protected boolean saveAs()
    {
        JFileChooser jfd = new JFileChooser();
        jfd.setFileSelectionMode(JFileChooser.FILES_ONLY);
        jfd.setFileFilter(new FileFilter() {
            @Override
            public boolean accept(File f) {
                return (f.getName().toLowerCase().endsWith(DOC_FILE_EXTENSION) || f.isDirectory());
            }

            @Override
            public String getDescription() {
                return DOC_FILE_DESCRIPTION;
            }
        });
        int result = jfd.showSaveDialog(Main.window);

        if (result == JFileChooser.APPROVE_OPTION)
        {
            String fileName = jfd.getSelectedFile().getAbsolutePath();
            if (!fileName.toLowerCase().endsWith(DOC_FILE_EXTENSION)) fileName += DOC_FILE_EXTENSION;

            boolean okSave = true;
            if (new File(fileName).exists())
            {
                okSave = false;
                int approve = JOptionPane.showConfirmDialog(jfd, "Overwrite the existing file?", "Are you sure?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);

                if (approve == JOptionPane.YES_OPTION) okSave = true;
            }

            if (okSave)
            {
                Main.document.saveAs(fileName);
                return true;
            }

            return false;
        }

        return false;
    }

    // Checks whether the document needs saving, showing saveas dialog if a name
    // is needed, and returning true if the document is saved or the changes are
    // discarded (ie if it returns true we can load a new document etc. otherwise
    // we cancel the operation).
    protected boolean checkSaving()
    {
        if (Main.document == null) return true;

        Main.plugins.documentSaving();
        if (Main.document.needsSaving == false) return true;

        //System.out.println("Checking doc save");

        int value = JOptionPane.showConfirmDialog(this, "Would you like to save your changes before continuing?", "Save?", JOptionPane.YES_NO_CANCEL_OPTION);

        if (value == JOptionPane.YES_OPTION)
        {
            return doSave(false);
        }
        else if (value == JOptionPane.NO_OPTION)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    // Does a save operation, showing the saveas dialog if the current document
    // is 'new' and has no association filename yet.
    protected boolean doSave(boolean saveAs)
    {
        if (Main.document.currentFilename.length() == 0 || saveAs)
        {
            Main.plugins.documentSaving();
            if (saveAs()) return true;
            return false;
        }
        else
        {
            Main.plugins.documentSaving();
            Main.document.save();
            return true;
        }
    }

    // Closes machine parameter windows and other dialogs when the main window
    // is going to close.
    protected void closeAllDialogs()
    {
        Window[] windows = getOwnedWindows();

        for (Window window : windows)
        {
            window.setVisible(false);
            window.getToolkit().getSystemEventQueue().postEvent(new WindowEvent(window, WindowEvent.WINDOW_CLOSING));
            window.dispose();
        }
    }
}

/**
 * An action listener for the main window. Handles events to do with the 'File'
 * menu and the preferences tab.
 */
class MainFrameListener implements ActionListener
{
    public boolean pauseSaving = false;
    private MainFrame frame;

    public MainFrameListener(MainFrame owner)
    {
        frame = owner;
    }

    @Override
    public void actionPerformed(ActionEvent e)
    {
        if (e.getSource() == frame.newItem)
        {
            if (!frame.checkSaving()) return;
            frame.closeAllDialogs();
            Main.load(null);
        }
        else if (e.getSource() == frame.loadItem)
        {
            if (!frame.checkSaving()) return;
            frame.closeAllDialogs();
            frame.load();
        }
        else if (e.getSource() == frame.saveItem)
        {
            frame.doSave(false);
        }
        else if (e.getSource() == frame.saveAsItem)
        {
            frame.doSave(true);
        }
        else if (e.getSource() == frame.helpItem || e.getSource() == frame.showHelpButton)
        {
            try
            {
                File helpFile = new File("help/help.html");
                URI helpURI = helpFile.toURI();
                java.awt.Desktop.getDesktop().browse(helpURI);
            }
            catch (Exception ex) {}
        }
        else if (e.getSource() == frame.exitItem)
        {
            Main.closeFramework();
        }
        else if (e.getSource() == frame.addStartupButton)
        {
            frame.addStartup();
        }
        else if (e.getSource() == frame.remStartupButton)
        {
            frame.remStartup();
        }
        else if (e.getSource() == frame.audioTestButton)
        {
            try
            {
                AudioThread testThread = new AudioThread();
                testThread.start();
                Thread.sleep(5000);
                testThread.stop();
            }
            catch (Exception ex) {}
        }
        else if (e.getSource() == frame.reloadFrameworkButton)
        {
            if (!frame.checkSaving()) return;
            Main.stopFramework();
            Main.startFramework();
        }


        if (pauseSaving) return;

        if (e.getSource() == frame.audioDeviceCombo)
        {
            String deviceName = (String) frame.audioDeviceCombo.getSelectedItem();
            Main.settings.setValue("Audio/SoundDevice", new UsefulFileObjectSimple(deviceName));
        }
        else if (e.getSource() == frame.sampleRateCombo)
        {
            int sampleRate = Integer.parseInt((String) frame.sampleRateCombo.getSelectedItem());
            Main.settings.setValue("Audio/SampleRate", new UsefulFileObjectSimple(sampleRate));
        }
        else if (e.getSource() == frame.bufferSizeCombo)
        {
            int bufferSize = Integer.parseInt((String) frame.bufferSizeCombo.getSelectedItem());
            Main.settings.setValue("Audio/BufferSize", new UsefulFileObjectSimple(bufferSize));
        }
        else if (e.getSource () == frame.startPopupCheckBox)
        {
            changeCheckBoxSetting(frame.startPopupCheckBox , "Startup Popup Setting");
        }
        else if (e.getSource () == frame.loadDemoCheckBox)
        {
            changeCheckBoxSetting(frame.loadDemoCheckBox , "Startup Sound Setting");
        }
    }

    protected void changeCheckBoxSetting(JCheckBox cBox, String settingName)
    {
            if(cBox.isSelected() == true)
                Main.settings.setValue(settingName, new UsefulFileObjectSimple(1));
            else
                Main.settings.setValue(settingName, new UsefulFileObjectSimple(0));
    }
}

/**
 * A WindowListener which allows us to catch the window being closed and
 * shut things down. This simply calls Main.closeFramework() before the
 * window closes.
 */
class MainFrameCloseListener implements WindowListener
{
    @Override
    public void windowClosing(WindowEvent e)
    {
        Main.closeFramework();
    }

    @Override
    public void windowActivated(WindowEvent e) {}
    @Override
    public void windowDeactivated(WindowEvent e) {}
    @Override
    public void windowIconified(WindowEvent e) {}
    @Override
    public void windowDeiconified(WindowEvent e) {}
    @Override
    public void windowOpened(WindowEvent e) {}
    @Override
    public void windowClosed(WindowEvent e) {}
}