package junit.swingui;

import java.util.* ;
import java.awt.* ;
import java.awt.event.* ;
import javax.swing.* ;
import javax.swing.event.* ;

import junit.framework.* ;
import junit.runner.* ;

/**
 * A test class selector. A simple dialog to pick the name of a test suite.
 */
class TestSelector extends JDialog {
        private JButton fCancel;

        private JButton fOk;

        private JList fList;

        private JScrollPane fScrolledList;

        private JLabel fDescription;

        private String fSelectedItem;

        /**
         * Renders TestFailures in a JList
         */
        static class TestCellRenderer extends DefaultListCellRenderer {
                Icon fLeafIcon;

                Icon fSuiteIcon;

                public TestCellRenderer() {
                        fLeafIcon = UIManager.getIcon("Tree.leafIcon");
                        fSuiteIcon = UIManager.getIcon("Tree.closedIcon");
                }

                public Component getListCellRendererComponent(
                                JList list, Object value, int modelIndex,
                                boolean isSelected, boolean cellHasFocus) {
                        Component c = super.getListCellRendererComponent(list, value, modelIndex, isSelected, cellHasFocus);
                        String displayString = displayString((String) value);

                        if (displayString.startsWith("AllTests"))
                                setIcon(fSuiteIcon);
                        else
                                setIcon(fLeafIcon);

                        setText(displayString);
                        return c;
                }

                public static String displayString(String className) {
                        int typeIndex = className.lastIndexOf('.');
                        if (typeIndex < 0)
                                return className;
                        return className.substring(typeIndex + 1) + " - " + className.substring(0, typeIndex);
                }

                public static boolean matchesKey(String s, char ch) {
                        return ch == Character.toUpperCase(s.charAt(typeIndex(s)));
                }

                private static int typeIndex(String s) {
                        int typeIndex = s.lastIndexOf('.');
                        int i = 0;
                        if (typeIndex > 0)
                                i = typeIndex + 1;
                        return i;
                }
        }

        protected class DoubleClickListener extends MouseAdapter {
                public void mouseClicked(MouseEvent e) {
                        if (e.getClickCount() == 2) {
                                okSelected();
                        }
              }
        }

        protected class KeySelectListener extends KeyAdapter {
                public void keyTyped(KeyEvent e) {
                        keySelectTestClass(e.getKeyChar());
                }
        }

        public TestSelector(Frame parent, TestCollector testCollector) {
                super(parent, true);
                setSize(350, 300);
                setResizable(false);
                setLocationRelativeTo(parent);
                setTitle("Test Selector");

                Vector list = null;
                try {
                        parent.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
                        list = createTestList(testCollector);
                } finally {
                        parent.setCursor(Cursor.getDefaultCursor());
                }
                fList = new JList(list);
                fList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
                fList.setCellRenderer(new TestCellRenderer());
                fScrolledList = new JScrollPane(fList);

                fCancel = new JButton("Cancel");
                fDescription = new JLabel("Select the Test class:");
                fOk = new JButton("OK");
                fOk.setEnabled(false);
                getRootPane().setDefaultButton(fOk);

                defineLayout();
                addListeners();
        }

        private void addListeners() {
                fCancel.addActionListener(
                        new ActionListener() {
                                public void actionPerformed(ActionEvent e) {
                                        dispose();
                                }
                        }
                );

                fOk.addActionListener(
                        new ActionListener() {
                                public void actionPerformed(ActionEvent e) {
                                        okSelected();
                                }
                        }
                );

                fList.addMouseListener(new DoubleClickListener());
                fList.addKeyListener(new KeySelectListener());
                fList.addListSelectionListener(
                        new ListSelectionListener() {
                                public void valueChanged(ListSelectionEvent e) {
                                        checkEnableOK(e);
                                }
                        }
                );

                addWindowListener(
                        new WindowAdapter() {
                                public void windowClosing(WindowEvent e) {
                                        dispose();
                                }
                        }
                );
        }

        private void defineLayout() {
                getContentPane().setLayout(new GridBagLayout());
                GridBagConstraints labelConstraints = new GridBagConstraints();
                labelConstraints.gridx = 0; labelConstraints.gridy = 0;
                labelConstraints.gridwidth = 1; labelConstraints.gridheight = 1;
                labelConstraints.fill = GridBagConstraints.BOTH;
                labelConstraints.anchor = GridBagConstraints.WEST;
                labelConstraints.weightx = 1.0;
                labelConstraints.weighty = 0.0;
                labelConstraints.insets = new Insets(8, 8, 0, 8);
                getContentPane().add(fDescription, labelConstraints);

                GridBagConstraints listConstraints = new GridBagConstraints();
                listConstraints.gridx = 0; listConstraints.gridy = 1;
                listConstraints.gridwidth = 4; listConstraints.gridheight = 1;
                listConstraints.fill = GridBagConstraints.BOTH;
                listConstraints.anchor = GridBagConstraints.CENTER;
                listConstraints.weightx = 1.0;
                listConstraints.weighty = 1.0;
                listConstraints.insets = new Insets(8, 8, 8, 8);
                getContentPane().add(fScrolledList, listConstraints);

                GridBagConstraints okConstraints = new GridBagConstraints();
                okConstraints.gridx = 2; okConstraints.gridy = 2;
                okConstraints.gridwidth = 1; okConstraints.gridheight = 1;
                okConstraints.anchor = java.awt.GridBagConstraints.EAST;
                okConstraints.insets = new Insets(0, 8, 8, 8);
                getContentPane().add(fOk, okConstraints);


                GridBagConstraints cancelConstraints = new GridBagConstraints();
                cancelConstraints.gridx = 3; cancelConstraints.gridy = 2;
                cancelConstraints.gridwidth = 1; cancelConstraints.gridheight = 1;
                cancelConstraints.anchor = java.awt.GridBagConstraints.EAST;
                cancelConstraints.insets = new Insets(0, 8, 8, 8);
                getContentPane().add(fCancel, cancelConstraints);
        }

        public void checkEnableOK(ListSelectionEvent e) {
                fOk.setEnabled(fList.getSelectedIndex() != -1);
        }

        public void okSelected() {
                fSelectedItem = (String) fList.getSelectedValue();
                dispose();
        }

        public boolean isEmpty() {
                return fList.getModel().getSize() == 0;
        }

        public void keySelectTestClass(char ch) {
                ListModel model = fList.getModel();
                if ( !Character.isJavaIdentifierStart(ch))
                        return;
                for (int i = 0; i < model.getSize(); i++) {
                        String s = (String) model.getElementAt(i);
                        if (TestCellRenderer.matchesKey(s, Character.toUpperCase(ch))) {
                                fList.setSelectedIndex(i);
                                fList.ensureIndexIsVisible(i);
                                return;
                        }
                }
                Toolkit.getDefaultToolkit().beep();
        }

        public String getSelectedItem() {
                return fSelectedItem;
        }

        private Vector createTestList(TestCollector collector) {
                Enumeration each = collector.collectTests();
                Vector v = new Vector(200);
                Vector displayVector = new Vector(v.size());
                while (each.hasMoreElements()) {
                        String s = (String) each.nextElement();
                        v.addElement(s);
                        displayVector.addElement(TestCellRenderer.displayString(s));
                }
                if (v.size() > 0)
                        Sorter.sortStrings(displayVector, 0, displayVector.size() - 1, new ParallelSwapper(v));
                return v;
        }

        private class ParallelSwapper implements Sorter.Swapper {
                Vector fOther;

                ParallelSwapper(Vector other) {
                        fOther = other;
                }

                public void swap(Vector values, int left, int right) {
                        Object tmp = values.elementAt(left);
                        values.setElementAt(values.elementAt(right), left);
                        values.setElementAt(tmp, right);
                        Object tmp2 = fOther.elementAt(left);
                        fOther.setElementAt(fOther.elementAt(right), left);
                        fOther.setElementAt(tmp2, right);
                }
        }
}