/*
 * PictureChooser.java
 *
 * Created on February 1, 2007, 1:07 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package usda.weru.erosion;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import de.schlichtherle.truezip.file.TFile;

import java.io.FilenameFilter;
import java.io.IOException;
import java.io.UTFDataFormatException;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import javax.accessibility.AccessibleContext;
import javax.swing.Box;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import usda.weru.erosion.gui.PictureChooser_n;
import usda.weru.util.wepsFileChooser2.WepsFileChooser2;

/**
 *
 * @author Joseph Levin
 */
public final class PictureChooser extends PictureChooser_n {

    private static final long serialVersionUID = 1L;

    /**
     *
     */
    public static final int APPROVE_OPTION = 0;

    /**
     *
     */
    public static final int CANCEL_OPTION = 1;

    /**
     *
     */
    public static final int ERROR_OPTION = -1;

    /**
     *
     */
    public static final String DIALOG_TITLE_CHANGED_PROPERTY = "DialogTitleChangedProperty";

    /**
     *
     */
    protected static final String PICTURES_FILE = "pictures.xml";

    /**
     *
     */
    protected static final String Xml_picture = "picture";

    /**
     *
     */
    protected static final String Xml_title = "title";

    /**
     *
     */
    protected static final String Xml_description = "description";

    /**
     *
     */
    protected static final String Xml_value = "value";

    /**
     *
     */
    protected static final String Xml_id = "id";

    /**
     *
     */
    protected static final String Xml_file = "file";

    /**
     *
     */
    protected TFile c_pictureFile;

    /**
     *
     */
    protected ImageThread c_scalingThread;

    /**
     *
     */
    protected JDialog c_dialog = null;

    /**
     *
     */
    protected int c_returnValue = CANCEL_OPTION;

    /**
     *
     */
    protected String c_dialogTitle = "Picture Chooser";

    /**
     *
     */
    protected PictureButton c_selectedButton = null;

    /**
     *
     * @param file
     */
    public PictureChooser(TFile file) {
        c_scalingThread = new ImageThread();
        c_scalingThread.start();
        load(file);
    }

    /**
     *
     * @param parameter
     * @return
     */
    public String getValue(String parameter) {
        if (c_selectedButton != null) {
            return c_selectedButton.getValue(parameter);
        } else {
            return null;
        }
    }

    /**
     *
     * @param parent
     * @return
     * @throws HeadlessException
     */
    public int showDialog(Component parent) throws HeadlessException {
        c_selectedButton = null;
        c_dialog = createDialog(parent);
        c_dialog.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                c_returnValue = CANCEL_OPTION;
            }
        });
        c_returnValue = ERROR_OPTION;

        c_dialog.setVisible(true);
        firePropertyChange("PictureChooserDialogIsClosingProperty", c_dialog, null);
        c_dialog.dispose();
        c_dialog = null;
        return c_returnValue;
    }

    /**
     *
     * @param dialogTitle
     */
    public void setDialogTitle(String dialogTitle) {
        String oldValue = c_dialogTitle;
        c_dialogTitle = dialogTitle;
        if (c_dialog != null) {
            c_dialog.setTitle(dialogTitle);
        }
        firePropertyChange(DIALOG_TITLE_CHANGED_PROPERTY, oldValue, c_dialogTitle);
    }

    /**
     *
     * @return
     */
    public String getDialogTitle() {
        return c_dialogTitle;
    }

    /**
     *
     * @param parent
     * @return
     * @throws HeadlessException
     */
    protected JDialog createDialog(Component parent) throws HeadlessException {
        String title = getDialogTitle();
        putClientProperty(AccessibleContext.ACCESSIBLE_DESCRIPTION_PROPERTY, title);

        JDialog dialog;
        Window window = JOptionPane.getFrameForComponent(parent);
//        if (window instanceof Frame) {
        dialog = new JDialog((Frame) window, title, true);
//        } else {
//            dialog = new JDialog((Dialog)window, title, true);
//        }
        dialog.setComponentOrientation(this.getComponentOrientation());

        Container contentPane = dialog.getContentPane();
        contentPane.setLayout(new BorderLayout());
        contentPane.add(this, BorderLayout.CENTER);

        dialog.pack();
        dialog.setLocationRelativeTo(parent);

        return dialog;
    }

    /**
     *
     */
    public void approveSelection() {
        c_returnValue = APPROVE_OPTION;
        if (c_dialog != null) {
            c_dialog.setVisible(false);
        }
    }

    /**
     *
     * @param evt
     */
    @Override
    protected void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {
        cancelSelection();
    }

    /**
     *
     */
    public void cancelSelection() {
        c_returnValue = CANCEL_OPTION;
        if (c_dialog != null) {
            c_dialog.setVisible(false);
        }
    }

    /**
     *
     * @param file
     * @return
     */
    public boolean load(TFile file) {
        if (file == null) {
            return false;
        }
        if (file.isDirectory()) {
            return loadDicrectory(file);
        } else {
            return loadFile(file);
        }
    }

    /**
     *
     * @param dir
     * @return
     */
    public boolean loadDicrectory(TFile dir) {
        if (dir == null || !dir.isDirectory()) {
            return false;
        }
        TFile picturesFile = new TFile(dir, PICTURES_FILE);
        if (!picturesFile.exists()) {
            JOptionPane.showMessageDialog(this, "Unable to locate the pictures file.\n" + picturesFile.getAbsolutePath(), "Error", JOptionPane.ERROR_MESSAGE);
            return false;
        } else {
            return loadFile(picturesFile);
        }
    }

    /**
     *
     */
    public void dispose() {
        for (Component c : g_buttonPanel.getComponents()) {
            if (c instanceof PictureButton) {
                PictureButton pb = (PictureButton) c;
                pb.setImage(null);
            }
        }
        g_buttonPanel.removeAll();
        if (c_dialog != null) {
            c_dialog.dispose();
            c_dialog = null;
        }
        c_scalingThread.interrupt();
        c_scalingThread = null;
    }

    /**
     *
     * @param file
     * @return
     */
    public boolean loadFile(TFile file) {
        g_buttonPanel.removeAll();
        if (file == null || !file.isFile()) {
            return false;
        }
        TFile dir = new TFile(file.getParentFile());
        try {
            SAXBuilder builder = new SAXBuilder();
            Document document = builder.build(file);
            Element root = document.getRootElement();

            //Have the root element
            List<Element> pictureElements = root.getChildren(Xml_picture);
            for (Element pictureElement : pictureElements) {
                String filePath = pictureElement.getAttributeValue(Xml_file);
                String title = pictureElement.getChildTextTrim(Xml_title);
                String description = pictureElement.getChildTextTrim(Xml_description);

                if (g_buttonPanel.getComponentCount() == 0) {
                    g_buttonPanel.add(Box.createRigidArea(new Dimension(10, 0)));
                }

                PictureButton pb = new PictureButton(c_scalingThread);
                pb.setTitle(title);
                pb.setDescription(description);

                List<Element> valueElements = pictureElement.getChildren(Xml_value);
                for (Element valueElement : valueElements) {
                    String id = valueElement.getAttributeValue(Xml_id);
                    String value = valueElement.getTextTrim();
                    pb.setValue(id, value);
                }

                pb.setSize(150, 150);
                pb.setImageFile(new TFile(dir, filePath));
                g_buttonPanel.add(pb);
                g_buttonPanel.add(Box.createRigidArea(new Dimension(10, 0)));

            }

            return true;

        } catch (UTFDataFormatException udfe) {
            JOptionPane.showMessageDialog(this, "Unable to load the pictures file.\n" + file.getAbsolutePath() + "\n\n" + udfe.toString(), "Error", JOptionPane.ERROR_MESSAGE);
            return false;
        } catch (JDOMException jde) {
            JOptionPane.showMessageDialog(this, "Unable to load the pictures file.\n" + file.getAbsolutePath() + "\n\n" + jde.toString(), "Error", JOptionPane.ERROR_MESSAGE);
            return false;
        } catch (IOException ioe) {
            JOptionPane.showMessageDialog(this, "Unable to load the pictures file.\n" + file.getAbsolutePath() + "\n\n" + ioe.toString(), "Error", JOptionPane.ERROR_MESSAGE);
            return false;
        }
    }

    /**
     *
     * @param evt
     */
    @Override
    protected void scrollPaneComponentResized(java.awt.event.ComponentEvent evt) {

    }

    /**
     *
     * @param args
     */
    public static void main(String[] args) {

        WepsFileChooser2 jfc = new WepsFileChooser2(new TFile("."));
        jfc.setAcceptAllFileFilterUsed(true);
        jfc.setFileSelectionMode(WepsFileChooser2.SelectionType.FILES_AND_DIRECTORIES);
        int result = jfc.showDialog(null);
        if (result == WepsFileChooser2.APPROVE_OPTION) {
            PictureChooser pc = new PictureChooser(new TFile(jfc.getSelectedFile()));
            pc.showDialog(null);

        }
    }

    static class PictureFilenameFilter implements FilenameFilter {

        @Override
        public boolean accept(java.io.File dir, String name) {
            name = name.toLowerCase().trim();

            if (name.endsWith(".jpg")) {
                return true;
            } else {
                return false;
            }
        }
    }

    static class ImageThread extends Thread {

        protected Vector<PictureButton> c_queue;

        public ImageThread() {
            super("Image Scaler");
            c_queue = new Vector<PictureButton>();
        }

        @Override
        public void run() {
            while (true) {
                PictureButton[] queue = getQueued();
                for (final PictureButton button : queue) {
                    if (button.getLoading() && button.getImageFile() != null) {
                        ImageIcon icon = new ImageIcon(button.getImageFile().getAbsolutePath());
                        button.setImage(icon.getImage());
                        button.setLoading(false);
                    }
                    if (button.getScaling()) {
                        //Icon scaling
                        Icon tempIcon = null;
                        Image image = button.getImage();
                        if (image != null && button.getHeight() != 0) {
                            image = image.getScaledInstance(-1, button.getHeight(), Image.SCALE_FAST);
                            tempIcon = new ImageIcon(image);
                            image = null;
                        } else {
                            tempIcon = null;
                        }
                        final Icon icon = tempIcon;
                        java.awt.EventQueue.invokeLater(new Runnable() {
                            @Override
                            public void run() {
                                button.setIcon(icon);
                                button.setScaling(false);
                            }
                        });
                    }
                }
                try {
                    sleep(100);
                } catch (InterruptedException ex) {
                    return;
                }
            }
        }

        public synchronized PictureButton[] getQueued() {
            PictureButton[] temp = new PictureButton[c_queue.size()];
            temp = c_queue.toArray(temp);
            c_queue.clear();
            return temp;
        }

        public synchronized void add(PictureButton button) {
            if (!c_queue.contains(button)) {
                c_queue.add(button);
            }
        }
    }

    class PictureButton extends JButton implements ComponentListener, MouseListener, ActionListener {

        private static final long serialVersionUID = 1L;

        protected TFile c_imageFile;
        protected Image c_image;
        protected ImageThread c_thread;
        protected boolean c_scaling = false;
        protected boolean c_loading = true;
        protected String c_title;
        protected String c_description;
        protected Map<String, String> c_values;

        public PictureButton(ImageThread thread) {
            super();
            c_thread = thread;
            addActionListener(this);
            addComponentListener(this);
            addMouseListener(this);
            setMargin(new Insets(0, 0, 0, 0));

        }

        @Override
        public Dimension getPreferredSize() {
            Dimension size = super.getPreferredSize();
            size.height = g_buttonPanel.getHeight() - 20;
            return size;
        }

        @Override
        public Dimension getMinimumSize() {
            return getPreferredSize();
        }

        @Override
        public Dimension getMaximumSize() {
            return getPreferredSize();
        }

        public synchronized void setImageFile(TFile file) {
            setLoading(true);
            c_imageFile = file;
            c_thread.add(this);

        }

        public TFile getImageFile() {
            return c_imageFile;
        }

        public void setImage(Image image) {
            if (image == null) {
                c_image = null;
                setIcon(null);
                return;
            }
            c_image = image;
            updateScaling();
        }

        public Image getImage() {
            return c_image;
        }

        protected void updateScaling() {
            setScaling(true);
            c_thread.add(this);
            repaint();
        }

        public synchronized void setScaling(boolean scaling) {
            c_scaling = scaling;
        }

        public synchronized boolean getScaling() {
            return c_scaling;
        }

        public synchronized void setLoading(boolean loading) {
            c_loading = loading;
        }

        public synchronized boolean getLoading() {
            return c_loading;
        }

        @Override
        public void componentResized(ComponentEvent e) {
            updateScaling();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (getLoading() || getScaling()) {
                g.setColor(Color.WHITE);
                float w = getWidth();
                float h = 25;
                float x = 0;
                float y = 0;

                g.fillRect((int) x, (int) y, (int) w, (int) h);
                g.setColor(Color.BLACK);
                g.drawRect((int) x, (int) y, (int) w, (int) h);

                String text = "";
                if (getLoading()) {
                    text = "Loading Image";
                } else if (getScaling()) {
                    text = "Scaling Image";
                }

                float wt = g.getFontMetrics().stringWidth(text);
                float ht = g.getFontMetrics().getHeight();
                float xt = x + (w / 2) - (wt / 2);
                float yt = y + +h - (ht / 2);
                g.drawString(text, (int) xt, (int) yt);
            }
        }

        @Override
        public void componentMoved(ComponentEvent e) {
        }

        @Override
        public void componentShown(ComponentEvent e) {
        }

        @Override
        public void componentHidden(ComponentEvent e) {
        }

        @Override
        public void mouseClicked(MouseEvent e) {
        }

        @Override
        public void mousePressed(MouseEvent e) {
        }

        @Override
        public void mouseReleased(MouseEvent e) {
        }

        public String getTitle() {
            if (c_title != null) {
                return c_title;
            } else {
                return "";
            }
        }

        public void setTitle(String title) {
            c_title = title;
        }

        public String getDescription() {
            if (c_description != null) {
                return c_description;
            } else {
                return "";
            }
        }

        public void setDescription(String description) {
            c_description = description;
        }

        @Override
        public void mouseEntered(MouseEvent e) {
            g_titleLabel.setText(getTitle() + " ");
            g_descriptionLabel.setText(getDescription() + " ");
        }

        @Override
        public void mouseExited(MouseEvent e) {
            g_titleLabel.setText(" ");
            g_descriptionLabel.setText(" ");
        }

        public String getValue(String parameter) {
            if (c_values != null) {
                return c_values.get(parameter);
            } else {
                return null;
            }
        }

        public void setValue(String parameter, String value) {
            if (c_values == null) {
                c_values = new Hashtable<String, String>();
            }
            c_values.put(parameter, value);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            c_selectedButton = this;
            approveSelection();
        }

    }

}
