package junit.swingui;

import java.util.Vector;
import java.awt.* ;
import javax.swing.* ;
import javax.swing.tree.* ;

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

/**
 * A Panel showing a test suite as a tree. 
 */
class TestSuitePanel extends JPanel implements TestListener {
        private JTree fTree;

        private JScrollPane fScrollTree;

        private TestTreeModel fModel;

        static class TestTreeCellRenderer extends DefaultTreeCellRenderer {
                private Icon fErrorIcon;

                private Icon fOkIcon;

                private Icon fFailureIcon;

                TestTreeCellRenderer() {
                        super();
                        loadIcons();
                }

                void loadIcons() {
                        fErrorIcon = TestRunner.getIconResource(getClass(), "icons/error.gif");
                        fOkIcon = TestRunner.getIconResource(getClass(), "icons/ok.gif");
                        fFailureIcon = TestRunner.getIconResource(getClass(), "icons/failure.gif");
                }

                String stripParenthesis(Object o) {
                        String text = o.toString ();
                        int pos = text.indexOf('(');
                        if (pos < 1)
                                return text;
                        return text.substring (0, pos);
                }

                public Component getTreeCellRendererComponent(JTree tree, Object value,
                                boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {

                        Component c = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
                        TreeModel model = tree.getModel();
                        if (model instanceof TestTreeModel) {
                                TestTreeModel testModel = (TestTreeModel) model;
                                Test t = (Test) value;
                                String s = "";
                        if (testModel.isFailure(t)) {
                                if (fFailureIcon != null)
                                        setIcon(fFailureIcon);
                                s = " - Failed";
                        }
                        else if (testModel.isError(t)) {
                                if (fErrorIcon != null)
                                        setIcon(fErrorIcon);
                                s = " - Error";
                        }
                        else if (testModel.wasRun(t)) {
                                if (fOkIcon != null)
                                        setIcon(fOkIcon);
                                s = " - Passed";
                        }
                        if (c instanceof JComponent)
                                ((JComponent) c).setToolTipText(getText() + s);
                        }
                        setText(stripParenthesis(value));
                        return c;
                }
        }

        public TestSuitePanel() {
                super(new BorderLayout());
                setPreferredSize(new Dimension(300, 100));
                fTree = new JTree();
                fTree.setModel(null);
                fTree.setRowHeight(20);
                ToolTipManager.sharedInstance().registerComponent(fTree);
                fTree.putClientProperty("JTree.lineStyle", "Angled");
                fScrollTree = new JScrollPane(fTree);
                add(fScrollTree, BorderLayout.CENTER);
        }

        public void addError( final Test test, final Throwable t) {
                fModel.addError(test);
                fireTestChanged(test, true);
        }

        public void addFailure( final Test test, final AssertionFailedError t) {
                fModel.addFailure(test);
                fireTestChanged(test, true);
        }

        /**
         * A test ended.
         */
        public void endTest(Test test) {
                fModel.addRunTest(test);
                fireTestChanged(test, false);
        }

        /**
         * A test started.
         */
        public void startTest(Test test) {
        }

        /**
         * Returns the selected test or null if multiple or none is selected
         */
        public Test getSelectedTest() {
                TreePath[] paths = fTree.getSelectionPaths();
                if (paths != null && paths.length == 1)
                        return (Test) paths[0].getLastPathComponent();
                return null;
        }

        /**
         * Returns the Tree
         */
        public JTree getTree() {
                return fTree;
        }

        /**
         * Shows the test hierarchy starting at the given test
         */
        public void showTestTree(Test root) {
                fModel = new TestTreeModel(root);
                fTree.setModel(fModel);
                fTree.setCellRenderer(new TestTreeCellRenderer());
        }

        private void fireTestChanged( final Test test, final boolean expand) {
                SwingUtilities.invokeLater(
                        new Runnable() {
                                public void run() {
                                        Vector vpath = new Vector();
                                        int index = fModel.findTest(test, (Test) fModel.getRoot(), vpath);
                                        if (index >= 0) {
                                                Object[] path = new Object[vpath.size()];
                                                vpath.copyInto(path);
                                                TreePath treePath = new TreePath(path);
                                                fModel.fireNodeChanged(treePath, index);
                                                if (expand) {
                                                        Object[] fullPath = new Object[vpath.size() + 1];
                                                        vpath.copyInto(fullPath);
                                                        fullPath[vpath.size()] = fModel.getChild(treePath.getLastPathComponent(), index);
                                                                                                                                        ;
                                                        TreePath fullTreePath = new TreePath(fullPath);
                                                        fTree.scrollPathToVisible(fullTreePath);
                                                }
                                        }
                                }
                        } );
        }
}