//copyright (C) 2007 Mocanu Cristian Romeo

 

package balls;

 

import javax.swing.JApplet;

import javax.swing.JTree;

import javax.swing.JPanel;

import javax.swing.JFrame;

import javax.swing.tree.DefaultMutableTreeNode;

import java.awt.Container;

import javax.swing.JSplitPane;

import javax.swing.tree.TreeSelectionModel;

import javax.swing.JLabel;

import javax.swing.JRadioButton;

import java.awt.event.ActionListener;

import java.awt.event.ActionEvent;

import javax.swing.tree.TreePath;

import javax.swing.JScrollPane;

import java.awt.event.ActionListener;

import java.util.Random;

import javax.swing.SwingUtilities;

import javax.swing.Box;

import javax.swing.BoxLayout;

import javax.swing.JMenuBar;

import javax.swing.JMenuItem;

import javax.swing.JMenu;

import javax.swing.JOptionPane;

import java.util.ResourceBundle;

import java.text.MessageFormat;

import javax.swing.ImageIcon;

import java.awt.Cursor;

import javax.swing.JProgressBar;

import java.awt.BorderLayout;

import java.lang.reflect.InvocationTargetException;

import java.util.Observer;

import java.util.Observable;

 

/**

 * Describe class <code>TreeNav</code> here.

 *

 * @author <a href="mailto:chrimeea@yahoo.com">Cristian Mocanu</a>

 * @version 1.0

 */

public class BallsApplet extends JApplet implements Observer {

    private JTree tree;

    private Box rPanel;

    private JLabel question;

    private Random random;

    private JRadioButton[] options;

    private final DefaultMutableTreeNode root = new DefaultMutableTreeNode("Solution");

    private ResourceBundle rb = ResourceBundle.getBundle("Messages");

    private JProgressBar progressBar;

    private BallsSolver solver;

 

    public void update(Observable o, Object arg) {

            progressBar.setValue((Integer) arg);

    }

 

    @Override

    public void start() {

            final BallsSolution solution = solver.solve();

            SwingUtilities.invokeLater(new Runnable() {

                        public void run() {

                            progressBar.setVisible(false);

                            getContentPane().remove(progressBar);

                            setCursor(null);

                            renderMenu();

                            renderUI(solution);

                        }

                });

    }

 

    @Override

    public void init() {

            super.init();

            random = new Random();

            solver = new BallsSolver();

            solver.addObserver(this);

            try {

                SwingUtilities.invokeAndWait(new Runnable() {

                            public void run() {

                                    setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

                                    progressBar = new JProgressBar(0, solver.getTotalStages());

                                    progressBar.setValue(0);

                                    progressBar.setStringPainted(true);

                                    progressBar.setBorderPainted(true);

                                    progressBar.setString("Solving...");

                                    getContentPane().add(progressBar, BorderLayout.NORTH);

                                    setVisible(true);

                            }

                        });

            } catch (InterruptedException e) {

            } catch (InvocationTargetException e) {

            }

    }

 

    private void renderMenu() {

            final ImageIcon icon = new ImageIcon(BallsApplet.class.getResource("Scale-icon.gif"));

            JMenuBar menu = new JMenuBar();

            JMenu mOption = new JMenu(rb.getString("options_menu"));

            menu.add(mOption);

            JMenuItem mitem = new JMenuItem(rb.getString("restart_menu"));

            mitem.addActionListener(new ActionListener() {

                        public void actionPerformed(ActionEvent e) {

                            SwingUtilities.invokeLater(new Runnable() {

                                        public void run() {

                                                for (JRadioButton b: options) {

                                                    b.setVisible(true);

                                                }

                                                renderOptions(chooseSolution(root));

                                        }

                                    });

                        }

                });

            mOption.add(mitem);

            mitem = new JMenuItem(rb.getString("about_menu"));

            final JApplet j = this;

            mitem.addActionListener(new ActionListener() {

                        public void actionPerformed(ActionEvent e) {

                            SwingUtilities.invokeLater(new Runnable() {

                                        public void run() {

                                                JOptionPane.showMessageDialog(j,

                                                                                          rb.getString("about_message"),

                                                                                          rb.getString("about_title"),

                                                                                          JOptionPane.INFORMATION_MESSAGE,

                                                                                          icon);

                                        }

                                    });

                        }

                });

            mOption.add(mitem);

            setJMenuBar(menu);

    }

 

    private void renderUI(BallsSolution solution) {

            createNodes(root, solution);

            tree = new JTree(root);

            tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

            rPanel = new Box(BoxLayout.Y_AXIS);

            JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, new JScrollPane(tree), new JScrollPane(rPanel));

            split.setResizeWeight(0.5);

            getContentPane().add(split);

            question = new JLabel();

            rPanel.add(question);

            //Box b = new Box(BoxLayout.X_AXIS);

            options = new JRadioButton[3];

            for (int i = 0; i < 3; i++) {

                options[i] = new JRadioButton();

                rPanel.add(options[i]);

            }

            renderOptions(chooseSolution(root));

    }

 

    private DefaultMutableTreeNode chooseSolution(DefaultMutableTreeNode root) {

            return (DefaultMutableTreeNode) root.getChildAt(random.nextInt(root.getChildCount()));

    }

 

    private String getOutcome(Knowledge knowledge) {

            int s = knowledge.getSolution();

            if (s == -1) {

                return rb.getString("impossible_outcome");

            } else if (knowledge.getState(s) == BallState.UNKNOWN_LIGHT) {

                return MessageFormat.format(rb.getString("solution_light"), s + 1);

            } else if (knowledge.getState(s) == BallState.UNKNOWN_HEAVY) {

                return MessageFormat.format(rb.getString("solution_heavy"), s + 1);

            } else {

                return MessageFormat.format(rb.getString("solution_unknown"), s + 1);

            }

    }

 

    private void renderOptions(DefaultMutableTreeNode root) {

            int cc = root.getChildCount();

            if (cc == 0) {

                question.setText(root.toString());

                for (JRadioButton b: options) {

                        b.setVisible(false);

                }

                return;

            }

            question.setText(MessageFormat.format(rb.getString("compare"), root.toString()));

            for (int i = 0; i < cc; i++) {

                final DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) root.getChildAt(i);

                options[i].setText(childNode.toString());

                ActionListener[] l = options[i].getActionListeners();

                assert l.length < 2;

                if (l.length == 1) {

                        options[i].removeActionListener(l[0]);

                }

                options[i].addActionListener(new ActionListener() {

                            public void actionPerformed(ActionEvent e) {

                                    SwingUtilities.invokeLater(new Runnable() {

                                                public void run() {

                                                    DefaultMutableTreeNode node = chooseSolution(childNode);

                                                    TreePath treePath = new TreePath(node.getPath());

                                                    tree.expandPath(treePath);

                                                    tree.setSelectionPath(treePath);

                                                    renderOptions((DefaultMutableTreeNode) tree.getLastSelectedPathComponent());

                                                }

                                        });

                            }

                        });

                options[i].setSelected(false);

                options[i].setVisible(true);

            }

            for (int i = cc; i < 3; i++) {

                options[i].setVisible(false);

            }

    }

 

    private void createNodes(DefaultMutableTreeNode root, BallsSolution solution) {

            DefaultMutableTreeNode subRoot;

            if (solution.isEmptySolutions()) {

                Knowledge k = solution.getKnowledge();

                subRoot = new DefaultMutableTreeNode(getOutcome(k));

                root.add(subRoot);

            } else {

                for (SolutionBean b: solution.getSolutions()) {

                        StringBuilder label1 = new StringBuilder();

                        for (int i: b.getTransition().getLeftPan()) {

                            label1.append((i + 1) + " ");

                        }

                        StringBuilder label2 = new StringBuilder();

                        for (int i: b.getTransition().getRightPan()) {

                            label2.append((i + 1) + " ");

                        }

                        subRoot = new DefaultMutableTreeNode(MessageFormat.format(rb.getString("and"), label1, label2));

                    DefaultMutableTreeNode temp;

                        if (b.getSolutionsLight().getKnowledge().getSolution() > -1) {

                            temp = new DefaultMutableTreeNode(rb.getString("case_light"));

                            createNodes(temp, b.getSolutionsLight());

                            subRoot.add(temp);

                        }

                        if (b.getSolutionsHeavy().getKnowledge().getSolution() > -1) {

                            temp = new DefaultMutableTreeNode(rb.getString("case_heavy"));

                            createNodes(temp, b.getSolutionsHeavy());

                            subRoot.add(temp);

                        }

                        if (b.getSolutionsEqual().getKnowledge().getSolution() > -1) {

                            temp = new DefaultMutableTreeNode(rb.getString("case_equal"));

                            createNodes(temp, b.getSolutionsEqual());

                            subRoot.add(temp);

                        }

                        root.add(subRoot);

                }

            }

    }

}