/*
 * $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.BorderLayout;
import java.awt.Component;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.Hashtable;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListModel;
import javax.swing.SwingConstants;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import com.sun.javatest.ObservableTestFilter;
import com.sun.javatest.TestFilter;
import com.sun.javatest.TestSuite;
import com.sun.javatest.tool.ToolDialog;
import com.sun.javatest.tool.UIFactory;
import com.sun.javatest.util.Debug;
import com.sun.javatest.util.DynamicArray;

/**
 * The primary purpose is to hold the a variety of named filter sets from
 * which the user will select one (the "active" one).
 */
class FilterConfig {
     /**
      * Observe changes to the state of the view.  The changes to the view state
      * will generally be the result of user actions.
      */
    public interface Observer {
       /**
        * The state of the given filter has changed.
        */
        public void filterUpdated(TestFilter f);

        public void filterAdded(TestFilter f);

       /**
        * Removing the active filter will result in an exception.
        */
        public void filterRemoved(TestFilter f);
    }

    public FilterConfig(ExecModel e, JComponent parent, UIFactory uif) {
        // load default filters here instead of ExecTool to avoid instantiating
        // them
        execModel = e;
        this.parentComponent = parent;
        this.uif = uif;
    }

    /**
     * Add a test filter to the list of possible filters.
     * Care should be taken not to add a filter more than once.
     */
    synchronized void add(TestFilter f) {
        if (f == null)
            return;

        // record this filter officially
        filters = (TestFilter[])DynamicArray.append(filters, f);

        // register as change observer if possbile
        if (f instanceof ObservableTestFilter) {
            ((ObservableTestFilter)f).addObserver(listener);
        }

        if (f instanceof ConfigurableTestFilter && fep != null) {
            fep.addConfigurableFilter((ConfigurableTestFilter)f);
        }

        // tell people about the addition
        // obs should never be null
        for (int i = 0; i < obs.length; i++)
            obs[i].filterAdded(f);

        if (fep != null)
            fep.listModel.addElement(f);
    }

    /**
     * Remove a test filter from the list of possible filters.
     * You cannot remove the active filter.
     *
     * @param f Should not be null.  Should also be a filter which was previously
     *        added to this object.
     * @throws FilterInUseFault Thrown if you try to remove the active filter.
     */
    synchronized void remove(TestFilter f) {
        if (f == null)
            return;

        // remove this filter officially
        filters = (TestFilter[])DynamicArray.remove(filters, f);

        if (f instanceof ObservableTestFilter)
            ((ObservableTestFilter)f).removeObserver(listener);

        if (f instanceof ConfigurableTestFilter && fep != null) {
            fep.removeConfigurableFilter((ConfigurableTestFilter)f);
        }

        // tell people about the removal
        // obs should never be null
        for (int i = 0; i < obs.length; i++)
            obs[i].filterRemoved(f);

        if (fep != null)
            fep.listModel.removeElement(f);
    }

    synchronized String[] getFilterNames() {
        int count = filters.length;
        String[] names = new String[count];

        for (int i = 0; i < count; i++)
            names[i] = filters[i].getName();

        return names;
    }

    synchronized TestFilter[] getFilters() {
        int count = filters.length;
        TestFilter[] copy = new TestFilter[count];
        System.arraycopy(filters, 0, copy, 0, count);

        return copy;
    }

    /**
     * Get a filter by name.
     *
     * @return Null if no match.
     */
    synchronized TestFilter getFilter(String name) {
        int count = filters.length;

        for (int i = 0; i < count; i++)
            if (name.equals(filters[i].getName()))
                return filters[i];

        // not found
        return null;
    }

    /**
     * Does the view contain the given filter.
     * Done by reference compare.
     */
    synchronized boolean contains(TestFilter f) {
        for (int i = 0; i < filters.length; i++)
            if (filters[i] == f)
                return true;

        // not found
        return false;
    }

    synchronized FilterSelectionHandler createFilterSelectionHandler() {
        FilterSelectionHandler fsh = new FilterSelectionHandler(this, uif);
        handlers = (FilterSelectionHandler[])DynamicArray.append(handlers, fsh);

        return fsh;
    }

    public synchronized void addObserver(Observer o) {
        if (o == null)
            return;

        if (obs == null)
            obs = new Observer[0];

        obs = (Observer[])DynamicArray.append(obs, o);
    }

    public synchronized void removeObserver(Observer o) {
        obs = (Observer[])DynamicArray.remove(obs, o);
    }

    /**
     * Notify all observers that a filter has changed state.
     * This call has no effect if the given filter is not the active
     * view filter.
     */
    synchronized void notifyUpdated(TestFilter f) {
        if (obs == null)    // this really should not happen
            return;

        for (int i = 0; i < obs.length; i++) {
            obs[i].filterUpdated(f);
        }   // for
    }

    /**
     * Show the filter editor.
     */
    synchronized void showEditorDialog() {
        if (fep == null)
            fep = new FilterEditorPanel(parentComponent, uif);

        fep.setVisible(true);
    }

    /**
     * Show the filter editor, with the given filter selected.
     * @param f the filter to show the user initially
     */
    synchronized void showEditorDialog(TestFilter f) {
        if (fep == null)
            fep = new FilterEditorPanel(parentComponent, uif);

        fep.setSelectedFilter(f);
        fep.setVisible(true);
    }

    /**
     * Hide the editor dialog.  No effect if the dialog isn't visible or
     * initialized.
     */
    synchronized void hideEditorDialog(Frame parent) {
        fep.setVisible(false);
    }

    private class Listener
        extends ComponentAdapter
        implements ObservableTestFilter.Observer
    {
        public void filterUpdated(ObservableTestFilter otf) {
            notifyUpdated(otf);
        }

        // ComponentListener
        public void componentHidden(ComponentEvent e) {
            fep.doReset();
        }
    }

    // too much overhead to impl. all the methods if we use a Vector
    // we'll accept the hit when we add a new filter, which isn't that
    // often
    private TestFilter[] filters = new TestFilter[0];
    private UIFactory uif;
    private ExecModel execModel;
    private Listener listener = new Listener();
    private Observer[] obs = new Observer[0];
    private FilterSelectionHandler[] handlers;

    //private JDialog editDialog;
    private FilterEditorPanel fep;
    private JComponent parentComponent;

    private static boolean debug = Debug.getBoolean(FilterConfig.class);

    private class FilterEditorPanel
        extends ToolDialog
        implements ListSelectionListener, ActionListener
    {
        FilterEditorPanel(Component parent, UIFactory uif) {
            super(parent, uif, "fconfig");
        }

        // ActionListener
        public void actionPerformed(ActionEvent e) {
            Object source = e.getSource();
            String result = null;

            if (source == doneBut) {

                if (mode == EDITABLE) {
                    //Debug.println("FC - in edit mode, attempting to save.");
                    result = doApply();
                }
                else {
                    //Debug.println("FC - not in edit mode, not attempting to save.");
                }

                if (result == null)
                    //OLD editDialog.hide();
                    setVisible(false);
                else {
                    // save failed...
                }
            }
            else if (source == applyBut) {
                result = doApply();
            }
            else if (source == resetBut) {
                if (mode == EDITABLE)
                    doReset();
            }
            else if (source == cancelBut) {
                if (mode == EDITABLE)
                    doReset();

                //OLD editDialog.hide();
                setVisible(false);
            }
            /*
            else if (source == createBut) {
                Object tf = (TestFilter)(leftList.getSelectedValue());
                if (!(tf instanceof ConfigurableTestFilter))
                    throw new IllegalStateException("");

                ConfigurableTestFilter ctf = (ConfigurableTestFilter)tf;

                FilterConfig.this.add(ctf.cloneInstance());
            }
            else if (source == deleteBut) {
                Object tf = (TestFilter)(leftList.getSelectedValue());
                if (!(tf instanceof ConfigurableTestFilter))
                    throw new IllegalStateException("");

                ConfigurableTestFilter ctf = (ConfigurableTestFilter)tf;

                FilterConfig.this.remove(ctf);
            }
            */

            if (result != null) {       // error occured
                uif.showError("fconfig.commit", result);
            }
        }

        void setSelectedFilter(TestFilter f) {
            if (listModel != null) {
                int ind = listModel.indexOf(f);
                if (ind >= 0)
                    selectIndex(ind);
            }
            else {
                // necessary for correct initilization, since the ToolDialog
                // does lazy initilization
                // initGUI() will process this later
                selectedFilter = f;
            }
        }

        // ListSelectionListener
        public void valueChanged(ListSelectionEvent e) {
            //int newSelected = e.getLastIndex();
            int newSelected = leftList.getSelectedIndex();
            // list selection has changed
            if (newSelected < 0) {
                selectIndex(0);
                lastSelected = 0;
            }
            else if (newSelected != lastSelected) {
                selectIndex(newSelected);
                lastSelected = newSelected;
            }
        }

        /**
         * Process a list selection change.  It is assumed that the selection
         * does not equal the current/last selection.  This should always be
         * called on the event thread.
         */
        private void selectIndex(int index) {
            leftList.setSelectedIndex(index);

            // update right panel
            selectedFilter = (TestFilter)(listModel.elementAt(index));
            if (selectedFilter instanceof ConfigurableTestFilter) {
                if (mode == -1 || mode == UNEDITABLE) {
                    nameCards.show(namePanel, NAMING_ACTIVE);
                    //deleteBut.setEnabled(true);
                    //createBut.setEnabled(true);
                    applyBut.setEnabled(true);
                    resetBut.setEnabled(true);
                    mode = EDITABLE;
                }

                ConfigurableTestFilter ctf = (ConfigurableTestFilter)selectedFilter;
                namingName.setText(ctf.getName());

                String cardKey = (String)(configPanelHash.get(ctf));
                configCards.show(configPanel, cardKey);
            }
            else if (selectedFilter instanceof TestFilter) {
                if (mode == -1 || mode == EDITABLE) {
                    nameCards.show(namePanel, NAMING_EMPTY);
                    configCards.show(configPanel, CONFIG_EMPTY);
                    //createBut.setEnabled(false);
                    //deleteBut.setEnabled(false);
                    applyBut.setEnabled(false);
                    resetBut.setEnabled(false);
                    mode = UNEDITABLE;
                }
            }
            else {
                // hummm
            }

            fillInfo(selectedFilter);
            leftList.requestFocus();
        }

        protected void initGUI() {
            TestSuite ts = execModel.getTestSuite();
            String tsName = ((ts == null ? uif.getI18NString("fconfig.dTitle.unknown") : ts.getName()));
            setI18NTitle("fconfig.dTitle", tsName);

            JPanel body = uif.createPanel("fe.body", false);
            body.setLayout(new GridBagLayout());

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.fill = GridBagConstraints.VERTICAL;
            gbc.anchor = GridBagConstraints.NORTHWEST;
            gbc.insets.left = 10;
            gbc.insets.right = 10;
            gbc.weighty = 1;
            gbc.weightx = 0;
            gbc.gridwidth = 1;
            gbc.gridheight = 1;

            leftList = uif.createList("fconfig.list");
            leftList.setModel(createListModel());
            leftList.setCellRenderer(RenderingUtilities.createFilterListRenderer());
            leftList.addListSelectionListener(this);
            leftList.setBorder(BorderFactory.createEtchedBorder());
            leftList.getInsets().left = 5;
            leftList.getInsets().right = 5;
            uif.setAccessibleInfo(leftList, "fconfig.list");

            JPanel spacer = new JPanel();
            spacer.setBorder(uif.createTitledBorder("fconfig.list"));
            spacer.setLayout(new BorderLayout());
            spacer.add(leftList, BorderLayout.CENTER);

            body.add(spacer, gbc);

            gbc.weightx = 1;
            gbc.fill = GridBagConstraints.BOTH;
            gbc.gridx = 1;
            JComponent rightPanel = createRightPanel();
            body.add(rightPanel, gbc);

            int dpi = uif.getDotsPerInch();
            body.setPreferredSize(new Dimension(7 * dpi, 5 * dpi));
            setBody(body);

            initButtons();

            setComponentListener(listener);

            //leftList.setNextFocusableComponent(rightPanel.getNextFocusableComponent());
            //rightPanel.setNextFocusableComponent(applyBut);
            //helpBut.setNextFocusableComponent(leftList);

            mode = -1;

            // process any stored state
            if (selectedFilter != null)
                setSelectedFilter(selectedFilter);
            else
                selectIndex(0);     // the default
        }

        private ListModel createListModel() {
            listModel = new DefaultListModel();

            for (int i = 0; i < filters.length; i++)
                listModel.addElement(filters[i]);

            return listModel;
        }

        private JComponent createRightPanel() {
            EMPTY_CONFIG = createEmptyItem("fconfig.empt.conf");
            EMPTY_NAMING = createEmptyItem("fconfig.empt.name");

            EMPTY_CONFIG.setName("config");
            EMPTY_NAMING.setName("naming");

            JPanel pan = new JPanel(new GridBagLayout());
            pan.setName("rightFilter");
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = GridBagConstraints.RELATIVE;
            gbc.fill = GridBagConstraints.BOTH;
            gbc.anchor = GridBagConstraints.NORTH;
            gbc.insets.left = 10;
            gbc.insets.right = 10;
            gbc.weighty = 0;
            gbc.weightx = 1;

            JComponent nextPanel = createInfoPanel();
            nextPanel.setBorder(uif.createTitledBorder("fconfig.panel.info"));
            pan.add(nextPanel, gbc);

            nextPanel = createNamingPanel();
            nextPanel.setBorder(uif.createTitledBorder("fconfig.panel.naming"));
            pan.add(nextPanel, gbc);

            nextPanel = createConfigPanel();
            nextPanel.setBorder(uif.createTitledBorder("fconfig.panel.config"));
            gbc.weighty = 1;
            pan.add(nextPanel, gbc);

            return pan;
        }

        /**
         * ui key should have uikey.txt, uikey.desc, and uikey values in
         * the bundle.  these are for the text itself, a11y description and
         * a11y name respectively.
         */
        private JComponent createEmptyItem(String uikey) {
            JTextField item = uif.createHeading(uikey);
            uif.setAccessibleInfo(item, uikey);
            item.setHorizontalAlignment(SwingConstants.CENTER);

            return item;
        }

        private JComponent createInfoPanel() {
            JPanel pan = new JPanel(new GridBagLayout());
            pan.setName("info");
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.weightx = 5;
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.fill = GridBagConstraints.NONE;
            gbc.anchor = GridBagConstraints.EAST;

            gbc.insets.left = 15;
            gbc.insets.right = 15;

            JLabel lab = uif.createLabel("fconfig.info.name");
            infoName = uif.createOutputField("fconfig.info.name", lab);
            infoName.setEditable(false);
            infoName.setBorder(BorderFactory.createEmptyBorder());
            lab.setDisplayedMnemonic(uif.getI18NString("fconfig.info.name.mne").charAt(0));
            lab.setHorizontalAlignment(SwingConstants.RIGHT);

            // row 1
            // label in first column
            pan.add(lab, gbc);

            // add text field in second column
            gbc.gridx = 1;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.anchor = GridBagConstraints.WEST;
            pan.add(infoName, gbc);

            lab = uif.createLabel("fconfig.info.desc");
            lab.setHorizontalAlignment(SwingConstants.RIGHT);
            infoDesc = uif.createTextArea("fconfig.info.desc", lab);
            infoDesc.setRows(3);
            infoDesc.setEditable(false);
            infoDesc.setBorder(BorderFactory.createEmptyBorder());
            infoDesc.setLineWrap(true);
            infoDesc.setWrapStyleWord(true);
            infoDesc.setOpaque(false);
            lab.setDisplayedMnemonic(uif.getI18NString("fconfig.info.desc.mne").charAt(0));

            // row 2
            // label in first column
            gbc.gridx = 0;
            gbc.gridy = 1;
            gbc.fill = GridBagConstraints.NONE;
            gbc.anchor = GridBagConstraints.NORTHEAST;
            pan.add(lab, gbc);

            // add text area in second column
            gbc.gridx = 1;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.anchor = GridBagConstraints.WEST;
            pan.add(infoDesc, gbc);

            /*
            // NOTE intentional space added below to defeat
            //  i18n check in build while this is commented out
            lab = uif.createLabel ("fconfig.info.reason");
            lab.setHorizontalAlignment(SwingConstants.RIGHT);
            infoReason = uif.createTextArea("fconfig.info.reason");
            infoReason.setRows(2);
            infoReason.setEditable(false);
            infoReason.setBorder(BorderFactory.createEmptyBorder());
            infoReason.setLineWrap(true);
            infoReason.setWrapStyleWord(true);
            infoReason.setOpaque(false);
            lab.setLabelFor(infoReason);

            // row 3
            // label in first column
            gbc.gridx = 0;
            gbc.gridy = 2;
            gbc.fill = GridBagConstraints.NONE;
            gbc.anchor = GridBagConstraints.NORTHEAST;
            pan.add(lab, gbc);

            // add text area in second column
            gbc.gridx = 1;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.anchor = GridBagConstraints.WEST;
            pan.add(infoReason, gbc);
            */
            return pan;
        }

        private JPanel createNamingPanel() {
            nameCards = new CardLayout();
            namePanel = new JPanel(nameCards);

            JPanel pan = new JPanel(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.weightx = 5;
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.fill = GridBagConstraints.NONE;
            gbc.anchor = GridBagConstraints.EAST;

            gbc.insets.left = 15;
            gbc.insets.right = 15;

            JLabel lab = uif.createLabel("fconfig.naming.name");
            namingName = uif.createOutputField("fconfig.naming.name", lab);
            namingName.setEditable(true);
            namingName.setEnabled(true);
            lab.setDisplayedMnemonic(uif.getI18NString("fconfig.naming.name.mne").charAt(0));
            lab.setHorizontalAlignment(SwingConstants.RIGHT);

            // row 1
            // label in first column
            pan.add(lab, gbc);

            gbc.gridx = 1;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            pan.add(namingName, gbc);

            namePanel.add(NAMING_ACTIVE, pan);
            namePanel.add(NAMING_EMPTY, EMPTY_NAMING);
            nameCards.show(namePanel, NAMING_EMPTY);

            return namePanel;
        }

        private JPanel createConfigPanel() {
            configCards = new CardLayout();
            configPanel = new JPanel(configCards);
            configPanelHash = new Hashtable();

            // insert panels?
            configPanel.add(CONFIG_EMPTY, EMPTY_CONFIG);

            for (int i = 0; i < listModel.getSize(); i++) {
                if (listModel.getElementAt(i) instanceof ConfigurableTestFilter) {
                    ConfigurableTestFilter ctf =
                        (ConfigurableTestFilter)listModel.getElementAt(i);
                    addConfigurableFilter(ctf);
                }
            }   // for

            return configPanel;
        }

        private void initButtons() {
            applyBut = uif.createButton("fconfig.edit.apply", this);
            resetBut = uif.createButton("fconfig.edit.reset", this);
            cancelBut = uif.createCancelButton("fconfig.edit.cancel", this);
            doneBut = uif.createButton("fconfig.edit.done", this);
            setButtons(new JButton[] { applyBut, resetBut, cancelBut, doneBut },
                       doneBut);
        }

        private void addConfigurableFilter(ConfigurableTestFilter ctf) {
            JComponent comp = ctf.getEditorPane();
            String thisName = "ctf" + ++configCounter;

            if (comp != null)
                configPanel.add(thisName, comp);
            else
                configPanel.add(thisName, EMPTY_CONFIG);

            // to lookup later
            configPanelHash.put(ctf, thisName);
        }

        private void removeConfigurableFilter(ConfigurableTestFilter ctf) {
            configPanelHash.remove(ctf);
        }

        private void fillInfo(TestFilter f) {
            if (f == null)
                return;

            if (f instanceof ConfigurableTestFilter) {
                infoName.setText(((ConfigurableTestFilter)(f)).getBaseName());
            }
            else
                infoName.setText(f.getName());

            infoDesc.setText(f.getDescription());
            //infoReason.setText(f.getReason());
        }

        private void fillNaming(ConfigurableTestFilter f) {
            namingName.setText(f.getName());
        }

        /**
         * Attempt the apply operation.
         * @return Non-null if the apply was successful, null otherwise.  If non-null
         *         the value is a localized error message for the user.
         */
        private String doApply() {
            if (mode == UNEDITABLE)
                throw new IllegalStateException("filter is uneditable, cannot apply changes");

            ConfigurableTestFilter ctf = (ConfigurableTestFilter)selectedFilter;

            // should check to see if it's changed
            String newName = namingName.getText();
            if (validateName(newName) != -1) {
                return uif.getI18NString("fconfig.edit.badName", newName);
            }
            else if (newName != null)
                ctf.setInstanceName(newName);

            String status = ctf.commitEditorSettings();

            if (handlers != null)
                for (int i = 0; i < handlers.length; i++)
                    handlers[i].updateFilterMetaInfo(ctf);

            return status;
        }

        void doReset() {
            // reset all known configurable filters
            for (int i = 0; i < listModel.getSize(); i++) {
                if (listModel.elementAt(i) instanceof
                    ConfigurableTestFilter) {
                    ConfigurableTestFilter ctf =
                        (ConfigurableTestFilter)listModel.elementAt(i);
                    ctf.resetEditorSettings();
                }
            }   // for
        }

        /**
         * @return The position of the invalid character.
         */
        private int validateName(String text) {
            for (int i = 0; i < text.length(); i++) {
                char c = text.charAt(i);
                if (Character.isLetterOrDigit(c) ||
                    c == '-' ||
                    c == '_' ||
                    c == '.' ||
                    c == ' ' ||
                    c == ',')
                    continue;
                else
                    return i;
            }   // for

            return -1;
        }

        private JSplitPane split;
        private JList leftList;
        private DefaultListModel listModel;
        private int lastSelected = -1;
        private TestFilter selectedFilter;

        // just to help track current state
        private int mode;
        //private boolean focusSet;
        private static final int EDITABLE = 0;
        private static final int UNEDITABLE = 1;

        // dialog buttons
        private JButton applyBut;
        private JButton doneBut;
        private JButton cancelBut;
        private JButton createBut;
        private JButton deleteBut;
        private JButton resetBut;

        // info panel components
        private JTextArea infoDesc;
        private JTextField infoName;
        //private JTextArea infoReason;

        // naming panel
        private CardLayout nameCards;
        private JPanel namePanel;
        private JTextField namingName;

        // config panel
        private CardLayout configCards;
        private JPanel configPanel;
        private Hashtable configPanelHash;
        private int configCounter;          // to make a unique string

        private JComponent EMPTY_CONFIG;
        private JComponent EMPTY_NAMING;
        private JComponent EMPTY_INFO;

        private int NUMBER;

        private static final String CONFIG_ACTIVE = "configa";
        private static final String CONFIG_EMPTY = "confige";
        private static final String NAMING_ACTIVE = "naminga";
        private static final String NAMING_EMPTY = "naminge";
        private static final String INFO_ACTIVE = "infoa";
        private static final String INFO_EMPTY = "infoe";
    }

}
