/*
 * $Id$
 *
 * Copyright 1996-2008 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */
package com.sun.javatest.exec;

import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.FileInputStream;
import java.net.URL;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
import java.util.Vector;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import com.sun.javatest.Harness;
import com.sun.javatest.InterviewParameters;
import com.sun.javatest.TemplateUtilities;
//import com.sun.javatest.TemplateUtilities;
import com.sun.javatest.TestSuite;
import com.sun.javatest.WorkDirectory;
import com.sun.javatest.tool.Desktop;
import com.sun.javatest.tool.FileChooser;
import com.sun.javatest.tool.FileHistory;
import com.sun.javatest.tool.TestSuiteChooser;
import com.sun.javatest.tool.ToolDialog;
import com.sun.javatest.tool.UIFactory;
import com.sun.javatest.tool.WorkDirChooser;
import com.sun.interview.Interview;

import java.awt.Container;
import java.awt.Window;
import javax.swing.JInternalFrame;

class QuickStartWizard extends ToolDialog
{
    QuickStartWizard(ExecTool tool, UIFactory uif) {
        super(tool, uif, "qsw");
        this.tool = tool;
    }



    protected void initGUI() {
        disableDefaultDisposeHandler();
        initDirs();
        initPanes();

        setI18NTitle("qsw.title");

        body = uif.createPanel("qsw.body", new BorderLayout(), false);
        body.setBorder(BorderFactory.createLoweredBevelBorder());

        /*
         *      *-----------------------+
         *      |       | head          |
         *      |       +---------------|
         *      |       |               |
         *      | logo  | question pane |
         *      |       |               |
         *      |       +---------------|
         *      |       | error         |
         *      |-------+---------------+
         *      |         buttons       |
         *      |-----------------------+
         */

        TestSuite ts;
        try {
            //System.err.println("QSG: installDirIsTestSuite=" + installDirIsTestSuite);
            //System.err.println("QSG: installParentDirIsTestSuite=" + installParentDirIsTestSuite);
            //System.err.println("QSG: userDirIsTestSuite=" + userDirIsTestSuite);
            if (installDirIsTestSuite)
                ts = TestSuite.open(installDir);
            else if (installParentDirIsTestSuite)
                ts = TestSuite.open(installParentDir);
            else if (userDirIsTestSuite)
                ts = TestSuite.open(userDir);
            else
                ts = null;
        }
        catch (Throwable e) {
            ts = null;
        }

        // logo...
        JLabel logo;

        URL tsLogoURL = (ts == null ? null : ts.getLogo());
        //System.err.println("QSG: tsLogoURL=" + tsLogoURL);
        if (tsLogoURL == null) {
            logo = new JLabel(tool.getManager().getDesktop().getLogo());
            logo.setName("qsw.jtlogo");
            logo.setBackground(uif.getI18NColor("qsw.jtlogo.bg"));
            uif.setAccessibleInfo(logo, "qsw.jtlogo");
        }
        else {
            logo = new JLabel(new ImageIcon(tsLogoURL));
            logo.setName("qsw.tslogo");
            logo.setBackground(Color.white);
            // the following comments are to keep the i18n checker happy
            // getI18NString("qsw.tslogo.desc")
            // getI18NString("qsw.tslogo.name")
            uif.setAccessibleInfo(logo, "qsw.tslogo");
        }
        logo.setOpaque(true);
        logo.setFocusable(false); // mildly questionable, but it can't take/show focus
        body.add(logo, BorderLayout.WEST);

        main = uif.createPanel("qsw.main", new BorderLayout(), false);
        main.setBorder(BorderFactory.createEmptyBorder(20, 20, 0, 11));
        head = uif.createOutputField("qsw.head");
        head.setBorder(null);
        head.setFont(head.getFont().deriveFont(Font.BOLD));
        main.add(head, BorderLayout.NORTH);

        foot = uif.createOutputField("qsw.foot");
        foot.setBorder(null);
        foot.setFont(foot.getFont().deriveFont(Font.BOLD));
        foot.setForeground(uif.getI18NColor("qsw.foot"));
        main.add(foot, BorderLayout.SOUTH);

        body.add(main, BorderLayout.CENTER);

        setBody(body);

        backBtn = uif.createButton("qsw.back", listener);
        nextBtn = uif.createButton("qsw.next", listener);
        doneBtn = uif.createButton("qsw.done", listener);
        JButton cancelBtn = uif.createCancelButton("qsw.cancel");
        cancelBtn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                closeExecTool(e);
            }

        });
        setPane(taskPane);
        setButtons(new JButton[] { backBtn, nextBtn, doneBtn, cancelBtn }, null);
        setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);

    }

    private void closeExecTool(AWTEvent ev) {

        Component src = (Component) ev.getSource();
        for (Container p = src.getParent(); p != null; p = p.getParent()) {
            if (p instanceof JInternalFrame || p instanceof Window &&  p.getParent() != null) {
                p.setVisible(false);
                break;
            }
        }

        tool.getDesktop().removeTool(tool);
        tool.dispose();
    }

    private void initDirs() {
        File classDir = Harness.getClassDir();
        installDir = (classDir == null ? null : classDir.getParentFile());
        installDirIsTestSuite = (installDir == null ? false : TestSuite.isTestSuite(installDir));
        installParentDir = (installDir == null ? null : installDir.getParentFile());
        installParentDirIsTestSuite = (installParentDir == null ? false : TestSuite.isTestSuite(installParentDir));

        userDir = new File(System.getProperty("user.dir"));
        userDirIsTestSuite = (userDir == null ? false : TestSuite.isTestSuite(userDir));
        userDirIsWorkDirectory = (userDir == null ? false : WorkDirectory.isWorkDirectory(userDir));
    }

    private void initPanes() {
        taskPane = new TaskPane();
        configPane = new ConfigPane();
        testSuitePane = new TestSuitePane();
        newWorkDirPane = new CreateWorkDirPane();
        openWorkDirPane = new OpenWorkDirPane();
        endPane = new EndPane();
    }

    private void setPane(Pane p) {
        if (currPane != null)
            main.remove(currPane);

        p.update();
        head.setText(p.getHead());
        main.add(p, BorderLayout.CENTER);
        showError(null);
        backBtn.setEnabled(history.size() > 0);
        p.updateNextButton();
        doneBtn.setEnabled(p == endPane);
        currPane = p;

        main.validate();
        main.repaint();
    }

    private void showError(String key) {
        if (key == null) {
            foot.setText("");
            foot.setEnabled(false);
        }
        else {
            foot.setText(uif.getI18NString(key));
            foot.setEnabled(true);
            nextBtn.setEnabled(false);
        }
    }

    private void doBack() {
        int n = history.size();
        if (n > 0) {
            Pane p = (Pane) (history.remove(n - 1));
            setPane(p);
        }
    }

    private void doNext() {
        Pane p = currPane.getNext();
        if (p != null) {
            history.add(currPane);
            setPane(p);
        }
    }

    boolean checkSingleTestManager() {
        if (contextManager != null) {
            ExecToolManager em = tool.getExecToolManager();
            Desktop d = em.getDesktop();
            if(!em.checkOpenNewTool(d, contextManager)) {
                return false;
            }
        }
        return true;

    }

    private void doDone() {
        if (config == null)
            throw new IllegalStateException();

        if (workDir != null)
            config.setWorkDirectory(workDir);

        tool.setInterviewParameters(config);

        if (showConfigEditorFlag)
            tool.showConfigEditor(runTestsFlag);
        else if (runTestsFlag)
            tool.runTests();

        setVisible(false);
    }

    private ExecTool tool;

    private Pane currPane;
    private Pane taskPane;
    private ConfigPane configPane;
    private Pane testSuitePane;
    private Pane newWorkDirPane;
    private Pane openWorkDirPane;
    private Pane endPane;

    private int task;
    private static final int UNSET = 0, NEW = 1, RESUME = 2, BROWSE = 3;
    // indicates using jtm or jti templates
    private boolean jtmTemplate = true;

    private Properties configData;
    private File configFile;
    private Properties jtmData;
    private File jtmFile;

    private InterviewParameters config;
    private ContextManager contextManager;
    private TestSuite testSuite;
    private WorkDirectory workDir;
    private boolean showConfigEditorFlag;
    private boolean runTestsFlag;

    private File installDir;
    private File installParentDir;
    private boolean installDirIsTestSuite;
    private boolean installParentDirIsTestSuite;
    private File userDir;
    private boolean userDirIsTestSuite;
    private boolean userDirIsWorkDirectory;

    private JPanel body;
    private JPanel main;
    private JTextField head;
    private JTextField foot;
    private JButton backBtn;
    private JButton nextBtn;
    private JButton doneBtn;
    private Listener listener = new Listener();
    private KeyStroke enterKey = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
    private Vector history = new Vector();
    private boolean allowConfigLoadOutsideDefault;
    private File defaultConfigSavePath;
    private boolean allowConfigSaveOutsideDefault;
    private File defaultConfigLoadPath;

    private class Listener implements ActionListener
    {
        public void actionPerformed(ActionEvent e) {
            Object src = e.getSource();
            if (src == nextBtn)
                doNext();
            else if (src == backBtn)
                doBack();
            else if (src == doneBtn)
                doDone();
            else
                System.err.println("QSG.Listener " + e);
        }
    }

    private class FilePanel extends JPanel {

        FilePanel(String key, final JFileChooser chooser) {
            uif.initPanel(this, key, new BorderLayout(), false);

            label = uif.createLabel(key, true);

            field = uif.createInputField(key, label);
            currPathComp = field;

            button = uif.createButton(key + ".browse");
            button.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        // seed the path if the user has started to enter
                        // something
                        String path = getPath();
                        if (chooser instanceof FileChooser  &&
                                ((FileChooser)chooser).getChosenExtension() != null &&
                                ((FileChooser)chooser).getChosenExtension().equals(".jti")) {

                            File f = ConfigEditor.loadConfigFile(
                                contextManager, parent, uif,
                                (FileChooser)chooser);
                            path = (f == null ? null : f.getPath());
                        }
                        else {
                            // set chooser to value in field?
                            if (path != null && path.length() > 0)
                                chooser.setSelectedFile(new File(path));

                            int rc = chooser.showDialog(body, chooser.getApproveButtonText());
                            if (rc != JFileChooser.APPROVE_OPTION)
                                return;

                            path = chooser.getSelectedFile().getPath();
                        }

                        field.setText(path);
                        if (combo != null)
                                combo.setSelectedItem(path);
                    }
                });

            add(label, BorderLayout.WEST);
            add(field, BorderLayout.CENTER); // default, may be changed to combo
            add(button, BorderLayout.EAST);
        }

        public void setEnabled(boolean b) {
            super.setEnabled(b);
            label.setEnabled(b);
            currPathComp.setEnabled(b);
            button.setEnabled(b);
        }

        void setSuggestions(String[] suggestions) {
            if (suggestions == null || suggestions.length == 0)
                setPathComponent(field);
            else {
                if (combo == null) {
                    combo = uif.createChoice(getName()/*key*/, true, label);
                    //combo.setEditable(true);
                    combo.setFont(combo.getFont().deriveFont(Font.PLAIN));
                    if (listener != null) {
                        // would be better to use editor addActionListener
                        Component c = combo.getEditor().getEditorComponent();
                        if (c instanceof JTextField)
                            ((JTextField) c).getDocument().addDocumentListener(listener);
                    }
                }
                setPathComponent(combo);
                combo.removeAllItems();
                for (int i = 0; i < suggestions.length; i++)
                    combo.addItem(suggestions[i]);
            }
        }

        File getFile() {
            String path = getPath();
            return (path == null || path.length() == 0 ? null : new File(path));
        }

        String getPath() {
            //System.err.println("QSG.FP.getPath currComp=" + currPathComp);
            //System.err.println("QSG.FP.getPath combo.selectedItem=" + (combo == null ? "null" : String.valueOf(combo.getSelectedItem())));
            if (currPathComp == field)
                return field.getText();
            else if (currPathComp == combo) {
                Component c = combo.getEditor().getEditorComponent();
                if (c.isShowing() && c instanceof JTextField)
                    return ((JTextField) c).getText();
                else
                    return ((String) (combo.getSelectedItem()));
            }
            else
                throw new IllegalStateException();
        }

        void setDocumentListener(DocumentListener l) {
            field.getDocument().addDocumentListener(l);
            listener = l;
        }

        private void setPathComponent(JComponent newPathComp) {
            //System.err.println("QSG.FP.setPathComponent " + newPathComp);
            if (newPathComp != currPathComp) {
                if (currPathComp != null)
                    remove(currPathComp);
                add(newPathComp, BorderLayout.CENTER);
                newPathComp.setEnabled(isEnabled());
                label.setLabelFor(newPathComp);
                currPathComp = newPathComp;
            }
        }

        private JLabel label;
        private JTextField field;
        private JComboBox combo;
        private JComponent currPathComp;
        private JButton button;
        private DocumentListener listener;
    }

    private abstract class Pane extends JPanel {
        Pane(String key) {
            paneKey = key;
            setLayout(new GridBagLayout());
            int dpi = uif.getDotsPerInch();
            setPreferredSize(new Dimension(5 * dpi, (int) (2.5 * dpi)));
            head = uif.getI18NString(paneKey + ".hd");
        }

        void stateChanged() { }

        String getHead() {
            return head;
        }

        void update() {
            updateNextButton();
        }

        abstract void updateNextButton();

        Pane getNext() {
            return null;
        }

        JCheckBox addCheck(String key) {
            JCheckBox cb = uif.createCheckBox(paneKey + "." + key);
            cb.addChangeListener(changeListener);

            GridBagConstraints c = new GridBagConstraints();
            c.fill = GridBagConstraints.HORIZONTAL;
            c.gridwidth = GridBagConstraints.REMAINDER;
            c.insets.left = 10;
            c.insets.bottom = 5;
            c.weightx = 1;
            add(cb, c);

            return cb;
        }

        JRadioButton addChoice(String key, ButtonGroup bg) {
            JRadioButton rb = uif.createRadioButton(paneKey + "." + key, bg);
            rb.addChangeListener(changeListener);

            GridBagConstraints c = new GridBagConstraints();
            c.fill = GridBagConstraints.HORIZONTAL;
            c.gridwidth = GridBagConstraints.REMAINDER;
            c.insets.left = 10;
            c.insets.bottom = 5;
            c.weightx = 1;
            add(rb, c);

            return rb;
        }

        FilePanel addFile(String key, JFileChooser chooser) {
            return addFile(key, chooser, null);
        }

        FilePanel addFile(String key, final JFileChooser chooser, final JRadioButton rb) {
            final FilePanel fp = new FilePanel(paneKey + "." + key, chooser);

            GridBagConstraints c = new GridBagConstraints();
            c.fill = GridBagConstraints.HORIZONTAL;
            c.gridwidth = GridBagConstraints.REMAINDER;
            c.insets.bottom = 10;
            c.insets.left = (rb == null ? 0 : 30);
            c.weightx = 1;
            add(fp, c);

            if (rb != null) {
                fp.addAncestorListener(new AncestorListener() {
                        public void ancestorAdded(AncestorEvent e) {
                            fp.setEnabled(rb.isSelected());
                        }
                        public void ancestorMoved(AncestorEvent e) { }
                        public void ancestorRemoved(AncestorEvent e) { }
                    });
                rb.addChangeListener(new ChangeListener() {
                        public void stateChanged(ChangeEvent e) {
                            fp.setEnabled(rb.isSelected());
                        }
                    });
            }

            fp.setDocumentListener(new DocumentListener() {
                    public void changedUpdate(DocumentEvent e) {
                        changeListener.stateChanged(new ChangeEvent(fp));
                    }
                    public void insertUpdate(DocumentEvent e) {
                        changedUpdate(e);
                    }
                    public void removeUpdate(DocumentEvent e) {
                        changedUpdate(e);
                    }
                });

            return fp;
        }

        JTextArea addText() {
            return addText(true);
        }

        JTextArea addText(boolean initContent) {
            // text area...
            JTextArea textArea = uif.createTextArea("qsw.text");
            textArea.setEditable(false);
            textArea.setLineWrap(true);
            textArea.setOpaque(false);
            textArea.setWrapStyleWord(true);
            // override JTextArea focus traversal keys, resetting them to
            // the Component default (i.e. the same as for the parent.)
            textArea.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null);
            textArea.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null);
            if (initContent)
                textArea.setText(uif.getI18NString(paneKey + ".txt"));
            /*
              // set enter to be same as Next
              {
              InputMap im = textArea.getInputMap();
              im.put(enterKey, "next");
              ActionMap am = textArea.getActionMap();
              am.put("next", valueAction);
              }
            */
            GridBagConstraints c = new GridBagConstraints();
            c.gridwidth = GridBagConstraints.REMAINDER;
            c.insets.top = 20;
            c.insets.right = 10;
            c.insets.bottom = 10;
            c.fill = GridBagConstraints.BOTH;
            add(textArea, c);
            return textArea;
        }

        private ChangeListener changeListener = new ChangeListener() {
                public void stateChanged(ChangeEvent e) {
                    Pane.this.stateChanged();
                }
            };

        private String paneKey;
        private String head;
    };

    //------------------------------------------------------------------------------

    private class TaskPane extends Pane {
        TaskPane() {
            super("qsw.tsk");
            addText();
            newRun = addChoice("new", bg);
            resumeRun = addChoice("resume", bg);
            browse = addChoice("browse", bg);
        }

        void stateChanged() {
            task = (newRun.isSelected() ? NEW
                    : resumeRun.isSelected() ? RESUME
                    : browse.isSelected() ? BROWSE
                    : UNSET);
            updateNextButton();
        }

        void updateNextButton() {
            nextBtn.setEnabled(task != UNSET);
        }


        Pane getNext() {

            return (task == NEW || task == BROWSE ? (Pane) testSuitePane
                    : task == RESUME ? (Pane) openWorkDirPane
                    : null);
        }


        private ButtonGroup bg = new ButtonGroup();
        private JRadioButton newRun;
        private JRadioButton resumeRun;
        private JRadioButton browse;
    };

    //------------------------------------------------------------------------------

    private class ConfigPane extends Pane  {
        ConfigPane() {
            super("qsw.cfg");
            addText();
            jtiChooser = new FileChooser(true);
            jtiChooser.addChoosableExtension(".jti",
                                          uif.getI18NString("qsw.cfg.jtiFiles"));

            jtmChooser = new FileChooser(true);
            jtmChooser.setDialogTitle(uif.getI18NString("qsw.cfg.jtmChooser.title"));
            jtmChooser.addChoosableExtension(".jtm",
                                          uif.getI18NString("qsw.cfg.jtmFiles"));

            newConfig = addChoice("new", bg);
            jtmConfig = addChoice("template", bg);
            jtmPanel = addFile("jtm.field", jtmChooser, jtmConfig);

        }


        void tuneTemplateFilter() {
            if (contextManager != null &&
                    contextManager.getFeatureManager() != null &&
                    contextManager.getFeatureManager().isEnabled(FeatureManager.WD_WITHOUT_TEMPLATE) ) {
                jtmChooser.addChoosableExtension(".jti",
                                              uif.getI18NString("qsw.cfg.jtiFiles"));
            }
        }


        private void tunePane() {

            if (contextManager != null) {

                jtmChooser.setCurrentDirectory(contextManager.getDefaultTemplateLoadPath());

                if (contextManager.getFeatureManager() != null) {
                    FeatureManager fm = contextManager.getFeatureManager();
                    jtmConfig.setEnabled(fm.isEnabled(FeatureManager.TEMPLATE_USAGE));
                    newConfig.setEnabled(fm.isEnabled(FeatureManager.WD_WITHOUT_TEMPLATE));
                }
            }
        }


        void stateChanged() {
            showError(null);
            updateNextButton();
        }


        void updateNextButton() {

            tunePane();

            if (newConfig.isSelected()) {
                nextBtn.setEnabled(true);
            } else if (jtmConfig.isSelected()) {
                File f = jtmPanel.getFile();
                nextBtn.setEnabled(f != null && f.exists() && f.isFile());
            }
            else
                nextBtn.setEnabled(false);
        }

        Pane getNext() {
            if (bg.getSelection() == null)
                return null;

            if (newConfig.isSelected()) {
                configData = null;
                configFile = null;
                jtmData = null;
                jtmFile = null;
            } else if (jtmConfig.isSelected()) {
                jtmData = new Properties();
                jtmFile = chkConfigFile(jtmPanel, jtmData);
                if (jtmFile == null) {
                    return null;
                }

                if (jtmData != null) {
                    String jtmDataInterview = (String) (jtmData.get("INTERVIEW"));

                    if (jtmDataInterview != null
                        && !config.getClass().getName().equals(jtmDataInterview)) {
                        uif.showError("qsw.ts.templateMismatch");
                        return null;
                    }

                    jtmTemplate = Boolean.parseBoolean((String)jtmData.get("IS_TEMPLATE"));

                    if (config != null) {
                        try {
                            if (jtmTemplate) {
                                testSuite.loadInterviewFromTemplate(jtmFile, config);
                                config.setTemplatePath(jtmFile.getAbsolutePath());
                            } else {
                                config.load(jtmFile);
                            }
                        } catch (TestSuite.Fault ex) {
                            // todo
                            ex.printStackTrace();
                        } catch (IOException ex) {
                            // todo
                            ex.printStackTrace();
                        } catch (Interview.Fault ex) {
                            uif.showError("qsw.ts.cantLoadConfig", ex.getMessage());
                            return null;
                        }
                    }
                }

                return (task == NEW ? (Pane) newWorkDirPane : (Pane) endPane);
            }



            if (configData != null) {
                String configDataInterview = (String) (configData.get("INTERVIEW"));

                if (configDataInterview != null
                    && !config.getClass().getName().equals(configDataInterview)) {
                    uif.showError("qsw.ts.configMismatch");
                    return null;
                }

                try {
                    config.load(configData, configFile);
                }
                catch (InterviewParameters.Fault e) {
                    uif.showError("qsw.ts.cantLoadConfig", e.getMessage());
                    return null;
                }
            }

            return (config == null ? null : task == NEW ? (Pane) newWorkDirPane : (Pane) endPane);

        }


        private File chkConfigFile(FilePanel panel, Properties data ) {
            String path = panel.getPath();
            File file = null;
            if (path.length() == 0) {
                showError("qsw.cfg.noFile");
                return null;
            }

            File f = new File(path);
            if (!f.exists()) {
                showError("qsw.cfg.cantFindFile");
                return null;
            }

            if (!f.isFile()) {
                showError("qsw.cfg.badFile");
                return null;
            }

            try {
                InputStream in = new BufferedInputStream(new FileInputStream(f));

                try {
                    data.clear();
                    data.load(in);
                    file = f;
                }
                catch (RuntimeException e) {
                        // can get IllegalArgumentException if the file is corrupt
                    uif.showError("qsw.cfg.cantReadFile", e);
                return null;
                }
                finally {
                    in.close();
                }
            }
            catch (IOException e) {
                uif.showError("qsw.cfg.cantReadFile", e);
                return null;
            }

            if (!InterviewParameters.isChecksumValid(data, true)) {
                uif.showError("qsw.cfg.badChecksum");
                return null;
            }

            return file;
        }

        private ButtonGroup bg = new ButtonGroup();
        private JRadioButton newConfig;
        private JRadioButton fileConfig;
        private JRadioButton jtmConfig;
        private FilePanel filePanel;
        private FilePanel jtmPanel;
        private FileChooser jtiChooser;
        private FileChooser jtmChooser;

        private long configLastModified;

    };

    //------------------------------------------------------------------------------

    private class TestSuitePane extends Pane {
        TestSuitePane() {
            super("qsw.ts");
            addText();
            chooser = new TestSuiteChooser();
            testSuitePanel = addFile("file", chooser);
        }

        void stateChanged() {
            showError(null);
            updateNextButton();
        }

        void update() {
            super.update();

            // update file with suggestions based on -
            // - config template
            // - installation directory and its parent
            // - current directory

            Set s = new TreeSet();
            if (configData != null) {
                String configTestSuite = (String) (configData.get("TESTSUITE"));
                if (configTestSuite != null)
                    s.add(configTestSuite);
            }

            if (userDirIsTestSuite)
                s.add(userDir.getPath());

            if (installDirIsTestSuite)
                s.add(installDir.getPath());

            if (installParentDirIsTestSuite)
                s.add(installParentDir.getPath());

            if (s.size() > 0)
                testSuitePanel.setSuggestions((String[]) (s.toArray(new String[s.size()])));
        }

        void updateNextButton() {
            File file = testSuitePanel.getFile();
            TestSuite chooserTestSuite = chooser.getSelectedTestSuite();

            if (file == null)
                nextBtn.setEnabled(false);
            else if (chooserTestSuite != null && chooserTestSuite.getRoot().equals(file))
                nextBtn.setEnabled(true);
            else
                nextBtn.setEnabled(TestSuite.isTestSuite(file));
        }

        Pane getNext() {
            // update test suite and check validity?
            // if ts == chooser.getSelectedFile, use chooser.getSelectedTestSuite
            File file = testSuitePanel.getFile();
            if (file == null) {
                showError("qsw.ts.noFile");
                return null;
            }
            else if (testSuite == null || !testSuite.getRoot().equals(file) || config == null) {
                try {
                    TestSuite chooserTestSuite = chooser.getSelectedTestSuite();
                    if (chooserTestSuite != null
                        && chooserTestSuite.getRoot().equals(file))
                        testSuite = chooserTestSuite;
                    else
                        testSuite = TestSuite.open(file);
                }
                catch (FileNotFoundException e) {
                    showError("qsw.ts.cantFindFile");
                    return null;
                }
                catch (TestSuite.Fault e) {
                    uif.showError("qsw.ts.cantOpen",
                                  new Object[] { file, e.getMessage() });
                    return null;
                }

                // now that test suite is set, try to update config too
                try {
                    config = testSuite.createInterview();
                }
                catch (TestSuite.Fault e) {
                    uif.showError("qsw.ts.cantCreateInterview", e.getMessage());
                    return null;
                }
                catch (Throwable t) {
                    uif.showError("qsw.ts.cantCreateInterview", t.toString());
                    return null;
                }

            }

            if (testSuite != null) {
                contextManager = ExecTool.createContextManager(testSuite);
            }
            configPane.tuneTemplateFilter();

            if (!checkSingleTestManager()) {
                return null;
            }


            return (task == NEW || task == BROWSE ? (Pane) configPane
                    : task == RESUME ? (Pane) openWorkDirPane
                    : null);

           // return (config == null ? null : task == NEW ? (Pane) newWorkDirPane : (Pane) endPane);
        }

        private FilePanel testSuitePanel;
        private TestSuiteChooser chooser;
    };

    //------------------------------------------------------------------------------

    private abstract class WorkDirPane extends Pane {
        WorkDirPane(String key) {
            super(key);
            textArea = addText();
            chooser = new WorkDirChooser(true);
            workDirPanel = addFile("file", chooser);
        }

        protected final JTextArea textArea;
        protected final FilePanel workDirPanel;
        protected WorkDirChooser chooser;
    };

    private class CreateWorkDirPane extends WorkDirPane {
        CreateWorkDirPane() {
            super("qsw.nwd");
            chooser.setMode(WorkDirChooser.NEW);
        }

        void stateChanged() {
            updateNextButton();
        }

        public void update() {
            chooser.setTestSuite(testSuite);
        }

        void updateNextButton() {
            String path = workDirPanel.getPath();
            nextBtn.setEnabled(path != null && path.length() > 0);
        }

        Pane getNext() {
            File file = workDirPanel.getFile();

            if (file == null) {
                showError("qsw.nwd.noFile");
                return null;
            }
            else if (workDir == null || !workDir.getRoot().equals(file)) {
                try {
                    WorkDirectory chooserWorkDir = chooser.getSelectedWorkDirectory();
                    if (chooserWorkDir != null && canonicalEquals(chooserWorkDir.getRoot(), file)) {
                        // workdir was created inside the chooser
                        workDir = chooserWorkDir;
                    }
                    else
                        workDir = WorkDirectory.create(file, testSuite);

                    if (jtmFile != null && workDir != null && jtmTemplate) {
                        TemplateUtilities.setTemplateFile(workDir, jtmFile, true);
                        //tool.setWorkDir(workDir, true);
                        //tool.getConfigHandler().loadConfigNoUI(jtmFile);
                    }

                }
                catch (WorkDirectory.Fault e) {
                    uif.showError("qsw.nwd.cantCreate",
                                  new Object[] { file, e.getMessage() });
                    return null;
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }

            return endPane;
        }
    };

    private static boolean canonicalEquals(File f1, File f2) {
        try {
            File c1 = f1.getCanonicalFile();
            File c2 = f2.getCanonicalFile();
            return (c1.equals(c2));
        }
        catch (IOException e) {
            return false;
        }
    }

    private class OpenWorkDirPane extends WorkDirPane {
        OpenWorkDirPane() {
            super("qsw.owd");
            chooser.setMode(WorkDirChooser.OPEN_FOR_ANY_TESTSUITE);

            if (userDirIsWorkDirectory)
                workDirPanel.setSuggestions(new String[] { userDir.getPath() });
        }

        void stateChanged() {
            updateNextButton();
        }

        void updateNextButton() {
            File file = workDirPanel.getFile();
            WorkDirectory chooserWorkDir = chooser.getSelectedWorkDirectory();

            if (file == null)
                nextBtn.setEnabled(false);
            else if (chooserWorkDir != null && chooserWorkDir.getRoot().equals(file))
                nextBtn.setEnabled(true);
            else
                nextBtn.setEnabled(WorkDirectory.isWorkDirectory(file));
        }

        Pane getNext() {
            File file = workDirPanel.getFile();

            if (file == null) {
                showError("qsw.owd.noFile");
                return null;
            }
            else if (workDir == null || !workDir.getRoot().equals(file)) {
                try {
                    WorkDirectory chooserWorkDir = chooser.getSelectedWorkDirectory();
                    if (chooserWorkDir != null
                        && chooserWorkDir.getRoot().equals(file))
                        workDir = chooserWorkDir;
                    else
                        workDir = WorkDirectory.open(file);
                    testSuite = workDir.getTestSuite();
                }
                catch (FileNotFoundException e) {
                    showError("qsw.owd.cantFindFile");
                    return null;
                }
                catch (WorkDirectory.Fault e) {
                    uif.showError("qsw.owd.cantOpen",
                                  new Object[] { file, e.getMessage() });
                    return null;
                }

                try {
                    config = testSuite.createInterview();
                    // should get latest config for workDir
                }
                catch (TestSuite.Fault e) {
                    uif.showError("qsw.owd.createCreateInterview", e.getMessage());
                    return null;
                }

                FileHistory h = FileHistory.getFileHistory(workDir, "configHistory.jtl");
                File latestConfigFile = h.getLatestEntry();
                if (latestConfigFile != null) {
                    try {
                        config.load(latestConfigFile);
                    }
                    catch (IOException e) {
                        uif.showError("qsw.owd.cantLoadDefaultConfig",
                                      new Object[] { latestConfigFile, e });
                        return null;
                    }
                    catch (InterviewParameters.Fault e) {
                        uif.showError("qsw.owd.cantLoadDefaultConfig",
                                      new Object[] { latestConfigFile, e.getMessage() });
                        return null;
                    }
                }
                if (testSuite != null) {
                    contextManager = ExecTool.createContextManager(testSuite);

                    if (!checkSingleTestManager()) {
                        return null;
                    }
                }

            }

            return endPane;
        }
    };

    //------------------------------------------------------------------------------

    private class EndPane extends Pane {
        EndPane() {
            super("qsw.end");
            configTextArea = addText(false);
            configCheck = addCheck("cfg");
            runTestsTextArea = addText(false);
            runTestsCheck = addCheck("run");
        }

        void update() {
            super.update();

            // update text according to whether config is complete or not
            // (and so whether config editor required)
            // set configCheck if config incomplete
            Integer haveConfig = new Integer(configData == null ? 0 : 1);

            StringBuffer sb = new StringBuffer();
            if (config.isFinishable()) {
                // "Your configuration is complete, but you can change it by using
                // the Configuration Editor."
                sb.append(uif.getI18NString("qsw.end.cfgComplete"));
                configCheck.setSelected(task == BROWSE ? false : true);
            }
            else {
                if (configData != null) {
                    // "Your configuration is incomplete."
                    sb.append(uif.getI18NString("qsw.end.cfgIncomplete"));
                    sb.append(" ");
                }
                // "Before you can run tests, you must complete (a|your) configuration
                // by using the Configuration Editor."
                sb.append(uif.getI18NString("qsw.end.needEditor", haveConfig));
                configCheck.setSelected(task == BROWSE ? false : true);
            }
            sb.append(" ");
            // "You can open the Configuration Editor automatically by
            // checking the box below. You can also open the Configuration Editor
            // at any time from the Configure menu."
            sb.append(uif.getI18NString("qsw.end.editor"));
            configTextArea.setText(sb.toString());

            if (task == BROWSE) {
                runTestsTextArea.setVisible(false);
                runTestsCheck.setVisible(false);
            }
            else {
                runTestsTextArea.setVisible(true);
                runTestsCheck.setVisible(true);
                // "Once (the|your) configuration is complete, you can run tests automatically
                // by checking the box below. You can also run tests at any time from the
                // Run Tests menu."
                runTestsTextArea.setText(uif.getI18NString("qsw.end.runTests", haveConfig));
            }

            stateChanged();
        }

        void updateNextButton() {
            nextBtn.setEnabled(false);
        }

        void stateChanged() {
            if (runTestsCheck.isSelected()
                && (config == null || !config.isFinishable()))
                configCheck.setSelected(true);
            showConfigEditorFlag = configCheck.isSelected();
            runTestsFlag = runTestsCheck.isSelected();
        }

        private JTextArea configTextArea;
        private JCheckBox configCheck;
        private JTextArea runTestsTextArea;
        private JCheckBox runTestsCheck;
    };

    protected void windowClosingAction(AWTEvent e) {
        setVisible(false);
        closeExecTool(e);
    }

}
