/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * DatabaseChooser.java
 *
 * Created on Apr 9, 2010, 1:00:22 PM
 */
package ex1.database;

import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.file.swing.TFileChooser;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.LinkedList;
import java.util.List;
import javax.swing.DefaultComboBoxModel;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.ListCellRenderer;

/**
 *
 * @author Joseph Levin <joelevin@weru.ksu.edu>
 */
public class DatabaseChooser extends javax.swing.JPanel {

    private static final long serialVersionUID = 1L;

    /**
     *
     */
    public static final String PROP_DATABASE_PROVIDERS = "databaseProviders";

    /**
     *
     */
    public static final String PROP_BROWSE_DATABASE_PROVIDER_USED = "browseDatabaseProviderUsed";

    private final Icon ICON_DATABASE;

    private List<WepsDatabasesProvider> c_providers;
    private final Object LOCK_PROVIDERS = new Object();

    private boolean c_browseDatabaseProviderUsed;

    private boolean c_loading;

    /**
     * Creates new form DatabaseChooser
     */
    public DatabaseChooser() {
        initComponents();

        ICON_DATABASE = new javax.swing.ImageIcon(DatabaseChooser.class.getResource("/ex1/database/database.png")); // NOI18N        
        //ICON_FOLDER_OPEN = new javax.swing.ImageIcon(DatabaseChooser.class.getResource("/ex1/database/folder_open.png")); // NOI18N

        comboBox.setModel(new InternalComboBoxModel<DatabaseInformation>());
        comboBox.setRenderer(new InternalListCellRenderer<DatabaseInformation>());
        comboBox.addItemListener(new InternalItemListener());

        comboBox.getModel().setSelectedItem(null);

    }

    /**
     *
     * @param provider
     */
    public void addDatabaseProvider(WepsDatabasesProvider provider) {
        WepsDatabasesProvider[] old = getDatabaseProviders();
        synchronized (LOCK_PROVIDERS) {
            if (c_providers == null) {
                c_providers = new LinkedList<>();
            }
            c_providers.add(provider);
        }
        firePropertyChange(PROP_DATABASE_PROVIDERS, old, getDatabaseProviders());
    }

    /**
     *
     * @param provider
     * @return
     */
    public boolean removeDatabaseProvider(WepsDatabasesProvider provider) {
        WepsDatabasesProvider[] old = getDatabaseProviders();
        boolean removed = false;
        synchronized (LOCK_PROVIDERS) {
            if (c_providers != null) {
                removed = c_providers.remove(provider);
            }
        }
        if (removed) {
            firePropertyChange(PROP_DATABASE_PROVIDERS, old, getDatabaseProviders());
        }
        return removed;
    }

    /**
     *
     * @return
     */
    public WepsDatabasesProvider[] getDatabaseProviders() {
        synchronized (LOCK_PROVIDERS) {
            if (c_providers != null) {
                return c_providers.toArray(new WepsDatabasesProvider[c_providers.size()]);
            } else {
                return new WepsDatabasesProvider[0];
            }
        }
    }

    /**
     *
     * @param used
     */
    public void setBrowseDatabaseProviderUsed(boolean used) {
        boolean old = c_browseDatabaseProviderUsed;
        c_browseDatabaseProviderUsed = used;
        firePropertyChange(PROP_BROWSE_DATABASE_PROVIDER_USED, old, c_browseDatabaseProviderUsed);
    }

    /**
     *
     * @return
     */
    public boolean isBrowseDatabaseProviderUsed() {
        return c_browseDatabaseProviderUsed;
    }

    /**
     *
     * @return
     */
    public DatabaseInformation getSelectedDatabaseInformation() {
        Object o = comboBox.getSelectedItem();
        if (o instanceof DatabaseInformation) {
            return (DatabaseInformation) o;
        } else {
            return null;
        }
    }

    /**
     * This method is called from within the constructor to initialize the form. WARNING: Do NOT
     * modify this code. The content of this method is always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        listRenderer = new javax.swing.JPanel();
        iconLabel = new javax.swing.JLabel();
        subLabel = new javax.swing.JLabel();
        nameLabel = new javax.swing.JLabel();
        comboBox = new InternalComboBox<DatabaseInformation>();

        iconLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        iconLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/ex1/database/database.png"))); // NOI18N

        subLabel.setFont(subLabel.getFont().deriveFont(subLabel.getFont().getStyle() & ~java.awt.Font.BOLD, subLabel.getFont().getSize()-2));
        subLabel.setText("c:\\Documents\\sdfsd\\sdfsd\\db");

        nameLabel.setFont(nameLabel.getFont().deriveFont(nameLabel.getFont().getStyle() | java.awt.Font.BOLD));
        nameLabel.setText("Standard (db)");

        javax.swing.GroupLayout listRendererLayout = new javax.swing.GroupLayout(listRenderer);
        listRenderer.setLayout(listRendererLayout);
        listRendererLayout.setHorizontalGroup(
            listRendererLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, listRendererLayout.createSequentialGroup()
                .addComponent(iconLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(listRendererLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(subLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 122, Short.MAX_VALUE)
                    .addComponent(nameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 122, Short.MAX_VALUE)))
        );
        listRendererLayout.setVerticalGroup(
            listRendererLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(listRendererLayout.createSequentialGroup()
                .addComponent(nameLabel)
                .addGap(0, 0, 0)
                .addComponent(subLabel))
            .addComponent(iconLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 27, Short.MAX_VALUE)
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(comboBox, 0, 243, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(comboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
        );
    }// </editor-fold>//GEN-END:initComponents


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JComboBox<DatabaseInformation> comboBox;
    private javax.swing.JLabel iconLabel;
    private javax.swing.JPanel listRenderer;
    private javax.swing.JLabel nameLabel;
    private javax.swing.JLabel subLabel;
    // End of variables declaration//GEN-END:variables

    private class InternalComboBox<E> extends JComboBox<DatabaseInformation> {

        private static final long serialVersionUID = 1L;

    }

    private class InternalComboBoxModel<E> extends DefaultComboBoxModel<DatabaseInformation> {

        private static final long serialVersionUID = 1L;

        public InternalComboBoxModel() {
            //listen for updates to the providers list
            addPropertyChangeListener(PROP_DATABASE_PROVIDERS, new PropertyChangeListener() {

                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    update();
                }
            });

            addPropertyChangeListener(PROP_BROWSE_DATABASE_PROVIDER_USED, new PropertyChangeListener() {

                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    update();
                }
            });

            update();
        }

        private void update() {
            c_loading = true;
            try {
                DatabaseInformation selected = (DatabaseInformation) getSelectedItem();
                boolean selectedStillValid = false;
                removeAllElements();
                WepsDatabasesProvider[] providers = getDatabaseProviders();
                if (providers != null) {
                    for (WepsDatabasesProvider provider : providers) {
                        DatabaseInformation[] infos = provider.getDatabases();
                        if (infos != null) {
                            for (DatabaseInformation info : infos) {
                                addElement(info);
                                if (info.equals(selected)) {
                                    selectedStillValid = true;
                                }
                            }
                        }
                    }
                }
                if (isBrowseDatabaseProviderUsed()) {
                    addElement(new InternalBrowseDatabaseInformation());
                }

                if (selectedStillValid) {
                    setSelectedItem(selected);
                } else {
                    setSelectedItem(null);
                }
            } finally {
                c_loading = false;
            }

        }
    }

    private class InternalListCellRenderer<E> implements ListCellRenderer<DatabaseInformation> {

        @Override
        public Component getListCellRendererComponent(JList<? extends DatabaseInformation> list, DatabaseInformation value, int index, boolean isSelected, boolean cellHasFocus) {
            if (value != null && value instanceof DatabaseInformation) {
                listRenderer.setVisible(true);
                DatabaseInformation info = value;
                nameLabel.setText(info.getDisplayName());
                subLabel.setText(info.getShortDescription());

                Icon icon = info.getIcon();
                if (icon != null) {
                    iconLabel.setIcon(icon);
                } else {
                    iconLabel.setIcon(ICON_DATABASE);
                }
            } else {
                JLabel dummy = new JLabel(" Select a database...");
                dummy.setOpaque(true);
                dummy.setBorder(null);
                dummy.setBackground(getBackground());
                return dummy;
            }

            //TODO: setup the display of the renderer based on selection etc...
            listRenderer.setBackground(isSelected ? Color.LIGHT_GRAY : getBackground());

            return listRenderer;
        }

    }

    private class InternalItemListener implements ItemListener {

        @Override
        public void itemStateChanged(ItemEvent e) {
            if (c_loading || e.getStateChange() != ItemEvent.SELECTED) {
                return;
            }

            if (getSelectedDatabaseInformation() instanceof InternalBrowseDatabaseInformation) {
                //open the file chooser
                TFileChooser jfc = new TFileChooser();
                jfc.setFileSelectionMode(TFileChooser.DIRECTORIES_ONLY);
                jfc.setCurrentDirectory(new TFile("."));
                int result = jfc.showOpenDialog(comboBox);

                if (TFileChooser.APPROVE_OPTION == result) {
                    //create a file info and select it
                    TFile selected = new TFile(jfc.getSelectedFile());
                    FileDatabaseInformation info = new FileDatabaseInformation(selected);
                    comboBox.getModel().setSelectedItem(info);

                } else {
                    comboBox.getModel().setSelectedItem(null);
                }

            }
        }

    }

    private static class InternalBrowseDatabaseInformation implements DatabaseInformation {

        @Override
        public String getName() {
            return "file:browse";
        }

        @Override
        public String getDisplayName() {
            return "Browse ...";
        }

        @Override
        public Icon getIcon() {
            try {
                return new ImageIcon(DatabaseChooser.class.getResource("/ex1/database/folder_open.png")); // NOI18N
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

        @Override
        public String getDescription() {
            return null;
        }

        @Override
        public String getShortDescription() {
            return "Select a database directory.";
        }

    }

}
