/*
 * Scone - The Web Enhancement Framework
 * Copyright (C) 2009 Harald Weinreich, Volkert Buchmann, Frank Wollenweber, Torsten Haß
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package  scone.util;


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Enumeration;

import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;


/**
 * The Scone configuration GUI.
 *<UL>
 *<LI>Set Database parameters
 *<LI>Register Plugins
 *<LI>Configure Plugins
 */
public class ConfigGui extends JFrame {
    static final String fileName = "config/scone/plugins.xml";
    PluginRepository plugins = null;
    JList pluginList = null;
    DefaultListModel pluginListModel = null;
    PluginEditDialog dialog = null;
    RegisterDialog regDialog = null;

    /**
     * creates a new instance of the ConfigGui
     * @param plugins the plugin repository
     */
    public ConfigGui(PluginRepository plugins) {
        super("Configure Scone Properties");
        ImageIcon img = new ImageIcon("resources/scone/scone64.gif");
        setIconImage(img.getImage());  // Set icon of program

        this.plugins = plugins;
        createGui();
        dialog = new PluginEditDialog(this, "Configure Plugin", true);
        regDialog = new RegisterDialog(this, "Register New Plugin", true);
        addWindowListener(new SconeConfigWindowAdapter(this));
    }

    /**
     * sets up the GUI frame
     */
    public void createGui() {
        Container cp = getContentPane();

        cp.setLayout(new BorderLayout());
        cp.setBackground(Color.lightGray);
        pluginListModel = new DefaultListModel();   // Pluginlistmodels are used in Swing to represent the displayed Items...
        pluginList = new JList(pluginListModel);
        pluginList.setBackground(new Color(232, 232, 232));
        // Set Font
        Font displayFont = new Font("SansSerif", Font.BOLD, 12);

        pluginList.setFont(displayFont);
        // Set appearance of Cells...
        pluginList.setCellRenderer(new PluginListCellRenderer(plugins));

        Enumeration en = plugins.getEntries();

        while (en.hasMoreElements()) {
            PluginRepositoryEntry entry = (PluginRepositoryEntry) en.nextElement();
            String name = entry.getName();

            pluginListModel.addElement(name);
        }

        JScrollPane pluginListPane = new JScrollPane(pluginList);  // Enable Scrollbar

        cp.add(pluginListPane, "Center");
        pluginList.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                if (!e.getValueIsAdjusting() && pluginList.getSelectedIndex() >= 0) {
                    PluginRepositoryEntry entry = plugins.getEntryByNumber(pluginList.getSelectedIndex());

                    dialog.editPlugin(entry, pluginListModel, pluginList.getSelectedIndex());
                    pluginList.clearSelection();

                    // valueField.setText(sampleJList.getSelectedValue().toString());
                }
            }
            // try {
            // //get the corresponding node
            // PluginRepositoryEntry entry = plugins.getEntryByNumber(pluginList.getSelectedIndex());
            // dialog.editPlugin(entry, pluginList, pluginList.getSelectedIndex());
            // } catch (Exception ex) {
            // ex.printStackTrace();
            // }
            // }
        }
        );
        // Container buttonContainer=buttons.getContentPane();
        JPanel buttonContainer = new JPanel();

        buttonContainer.setLayout(new GridLayout(2, 3, 5, 5));

        // Configure Database
        JButton db = new JButton("Database");

        buttonContainer.add(db);
        db.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                new PersistentPropertiesGui(ConfigGui.this, new PersistentProperties("config/scone/db.xml"));
            }
        }
        );

        // Configure Access Tracking
        JButton userTracking = new JButton("Access Tracking");

        buttonContainer.add(userTracking);
        userTracking.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                new PersistentPropertiesGui(ConfigGui.this, new PersistentProperties("config/scone/accesstracking.xml"));
            }
        }
        );

        // Configure Robot
        JButton robot = new JButton("Robot");

        buttonContainer.add(robot);
        robot.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                new PersistentPropertiesGui(ConfigGui.this, new PersistentProperties("config/scone/robot.xml"));
            }
        }
        );

        // register new Plugin
        JButton register = new JButton("Register Plugin");

        buttonContainer.add(register);
        register.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try {
                    regDialog.show();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
        );

        // Cancel Tool...
        ImageIcon cancelIcon = new ImageIcon("resources/scone/cancel.gif");
        JButton cancel = new JButton("      Cancel   ", cancelIcon);

        buttonContainer.add(cancel);
        cancel.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        }
        );

        ImageIcon exitIcon = new ImageIcon("resources/scone/exit.gif");
        JButton exit = new JButton("  Exit & Save", exitIcon);

        buttonContainer.add(exit);
        exit.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try {
                    plugins.store();
                    System.exit(0);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
        );

        cp.add("South", buttonContainer);

        // Default is Exit and save...
        getRootPane().setDefaultButton(exit);
        // Show thing...
        this.setSize(480, 400);
        this.setLocation(Toolkit.getDefaultToolkit().getScreenSize().width / 2 - this.getWidth() / 2, Toolkit.getDefaultToolkit().getScreenSize().height / 2 - this.getHeight() / 2);
        this.setVisible(true);
        this.toFront();
    }

    /**
     * Register a new plugin
     * @param name the full classname of the plugin
     */
    public void register(String name) {
        PluginRepositoryEntry entry = plugins.register(name);

        if (entry != null) {
            pluginListModel.addElement(name);
        }
    }

    /**
     *  This WindowAdapter helps to close the config window...
     */
    class SconeConfigWindowAdapter extends WindowAdapter {
        protected ConfigGui configFrame;

        // Der Konstruktor
        public SconeConfigWindowAdapter(ConfigGui configFrame) {
            this.configFrame = configFrame;
        }

        // Das Fenster soll geschlossen werden
        public void windowClosing(WindowEvent e) {
            configFrame.dispose();
        }

        // Das Fenster wurde geschlossen
        public void windowClosed(WindowEvent e) {
            try {
                configFrame.plugins.store();
                System.exit(0);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

}


/**
 * Dialog box to configure, enable, disable and remove plugins
 */
class PluginEditDialog extends JDialog {
    protected PluginRepositoryEntry entry = null;
    protected int listPos = -1;
    protected DefaultListModel listModel = null;
    protected JLabel pluginName = new JLabel("pluginName", JLabel.CENTER);
    protected JButton disable = new JButton(" disable ");

    /**
     * creates a new instance of a PluginEditDialog
     * @param owner the owner Frame
     * @param title the dialog title
     * @param modal whethter the dialog is modal or not
     */
    public PluginEditDialog(Frame owner, String title, boolean modal) {
        super(owner, title, modal);

        Container cp = this.getContentPane();

        // Label shows the name of the plugin
        cp.setLayout(new BorderLayout());
        cp.add("North", pluginName);

        // another panel to display the buttons...
        JPanel buttonPanel = new JPanel();

        cp.add("Center", buttonPanel);

        JButton remove = new JButton(" Remove Plugin ");
        JButton config = new JButton(" Configure Plugin ");
        JButton done = new JButton(" Exit ");

        // buttonPanel.setLayout(new GridLayout(4, 1, 8, 3));
        buttonPanel.setLayout(new FlowLayout());
        buttonPanel.add(disable);
        buttonPanel.add(config);
        buttonPanel.add(remove);
        buttonPanel.add(done);

        getRootPane().setDefaultButton(done);
        this.setModal(true);
        this.pack();
        this.setLocation(Toolkit.getDefaultToolkit().getScreenSize().width / 2 - this.getWidth() / 2, Toolkit.getDefaultToolkit().getScreenSize().height / 2 - this.getHeight() / 2);

        disable.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try {
                    if (!entry.isEnabled()) {
                        entry.enable();
                    } else {
                        entry.disable();
                    }
                    hide();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
        );

        config.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try {
                    if (entry.getPlugin() == null) {
                        new PersistentPropertiesGui(PluginEditDialog.this, new PersistentProperties(
                                "config/properties/" + entry.getName() + ".xml"));
                    } else {
                        entry.getPlugin().displayConfigGUI(PluginEditDialog.this);
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
        );

        remove.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try {
                    entry.remove();
                    listModel.removeElementAt(listPos);
                    hide();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
        );

        done.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try {
                    hide();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
        );
    }

    // display this dialog for a special plugin
    public void editPlugin(PluginRepositoryEntry entry, DefaultListModel listModel, int listPos) {
        this.entry = entry;
        this.listModel = listModel;
        this.listPos = listPos;
        // set the pluginname
        pluginName.setText(entry.getName());
        pluginName.setForeground(new Color(0, 30, 60));
        pluginName.setFont(new Font(null, Font.BOLD, 16));
        // set enabled/disabled
        if (entry.isEnabled()) {
            disable.setLabel(" Disable Plugin ");
            disable.setBackground(new Color(202, 182, 182));
        } else {
            disable.setLabel(" Enable Plugin ");
            disable.setBackground(new Color(182, 202, 182));
        }
        this.pack();
        this.show();
    }
}


/**
 * The PluginListCellRenderer is used to control the appearance of the entries of the pluginList
 */
class PluginListCellRenderer extends DefaultListCellRenderer {
    // final static ImageIcon longIcon = new ImageIcon("long.gif");
    // final static ImageIcon shortIcon = new ImageIcon("short.gif");
    PluginRepository plugins = null;

    /**
     * New constructor to be able to access the plugins...
     */
    public PluginListCellRenderer(PluginRepository plugins) {
        this.plugins = plugins;
    }

    /* This is the only method defined by ListCellRenderer.  We just
     * reconfigure the Jlabel each time we're called.
     */
    public Component getListCellRendererComponent(
            JList list,
            Object value,   // value to display
            int index,      // cell index
            boolean iss,    // is the cell selected
            boolean chf)    // the list and the cell have the focus
    {

        /* The DefaultListCellRenderer class will take care of
         * the JLabels text property, it's foreground and background
         * colors, and so on.
         */
        super.getListCellRendererComponent(list, value, index, iss, chf);

        /* We additionally set the JLabels icon property here.
         */
        String s = value.toString();

        if (iss) {
            setBackground(new Color(222, 222, 242));
        }
        // else
        // setBackground((s.substring(2,3).equals("-")) ? new Color(242,222,222) : new Color(222,242,222));
        // setIcon((s.substring(2,3).equals("-")) ? new ImageIcon("resources/scone/off.gif") : new ImageIcon("resources/scone/bulb-on.gif"));
        // setIcon(plugins.getEntryByNumber(index).isEnabled() ? new ImageIcon("resources/scone/bulb-on.gif") : new ImageIcon("resources/scone/bulb-off.gif"));
        setIcon(plugins.getEntryByNumber(index).isEnabled() ? new ImageIcon("resources/scone/on.gif") : new ImageIcon("resources/scone/off.gif"));

        return this;
    }
}


/**
 * this dialog enables users to register new plugins
 */
class RegisterDialog extends JDialog {

    /**
     * Create a new dialog box to register new Scone plugins
     * @param owner the owner Frame
     * @param title the dialog title
     * @param modal whethter the dialog is modal or not
     */
    public RegisterDialog(final Frame owner, String title, boolean modal) {
        super(owner, title, modal);
        Container cp = getContentPane();

        cp.setLayout(new FlowLayout());
        final JTextField plugin = new JTextField(30);
        JButton ok = new JButton(" Register ");
        JButton cancel = new JButton(" Cancel ");

        ok.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try {
                    hide();
                    ((ConfigGui) owner).register(plugin.getText());
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
        );

        cancel.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try {
                    hide();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
        );

        cp.add(plugin);
        cp.add(ok);
        cp.add(cancel);

        this.setModal(true);
        this.pack();
        this.setLocation(Toolkit.getDefaultToolkit().getScreenSize().width / 2 - this.getWidth() / 2, Toolkit.getDefaultToolkit().getScreenSize().height / 2 - this.getHeight() / 2);
    }

}
