/*
 * $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.util.Map;

import javax.swing.JComponent;

import com.sun.javatest.ObservableTestFilter;
import com.sun.javatest.util.I18NResourceBundle;

/**
 * This class adds the capability to have a filter which is
 * reconfigurable throught the use of a GUI panel.  By definition, there
 * can be multiple instances of each <tt>ConfigurableTestFilter</tt> in
 * in the system at any one time.
 *
 * <p>
 * It is highly recommended that the GUI panel used to configure
 * this filter be a single panel, and not a complex tabbed or otherwise
 * "switchable" panel.
 *
 * <p>
 * Subclasses of this class should implement the abstract methods here and
 * those in ObservableTestFilter.
 *
 * @see com.sun.javatest.ObservableTestFilter
 */
abstract class ConfigurableTestFilter extends ObservableTestFilter {
    /**
     * Nameless filters are not allowed.
     */
    private ConfigurableTestFilter() {
    }

    /**
     * Utility constructor for subclasses.
     * @param name The name to give this filter instance.  Must never be null.
     * @param e The ExecTool that owns this instance of the filter.  Should never be null.
     * @throws IllegalArgumentException If the either parameter is null.
     */
    protected ConfigurableTestFilter(String name, ExecModel e) {
        if (name == null)
            throw new IllegalArgumentException(i18n.getString("ctf.nullName"));
        if (e == null)
            throw new IllegalArgumentException(i18n.getString("ctf.nullExec"));

        instanceName = name;
        execModel = e;
    }

    /**
     * Utility constructor for subclasses.
     * @param map The map containing previous filter settings.
     * @param e The ExecTool that owns this instance of the filter.
     * @throws IllegalStateException If the instance name is not present in the map or
     *         the exec model argument is null.
     */
    protected ConfigurableTestFilter(Map map, ExecModel e) {
        if (e == null)
            throw new IllegalArgumentException(i18n.getString("ctf.nullExec"));

        execModel = e;
        load(map);

    }

    /**
     * Create a new instance of this filter with the same associated exec model.
     * A default instance name will be supplied.
     */
    abstract ConfigurableTestFilter cloneInstance();

    /**
     * Overriden to create a new instance.
     * Settings from the original instance may not necessarily be copied.
     */
    public Object clone() {
        return cloneInstance();
    }

    /**
     * Get the basic (static) name for this filter.
     * This is different than <tt>getName()</tt> which returns a
     * customizable name.
     * @return The basic name for this filter.  Will never be null.
     */
    abstract String getBaseName();

    /**
     * Set the instance name.  This value should never be null.
     * Short meaningful names are recommended.
     *
     * @param text The name.
     * @throws IllegalArgumentException If the name parameter is null.
     * @see #getName()
     */
    void setInstanceName(String text) {
        if (text != null)
            instanceName = text;
        else
            throw new IllegalArgumentException(i18n.getString("ctf.nullName"));
    }

    /**
     * Load the state of this filter from a map.
     * This default implementation just loads the instance name.
     * @param map The map of strings to load from.
     * @return True if loading was sucessful and the filter is usable,
     *         false if the operation failed.
     * @throws IllegalStateException If the instance name is not present in the map.
     */
    boolean load(Map map) {
        instanceName = (String)(map.get(INSTANCE_KEY));

        if (instanceName == null)
            throw new IllegalStateException(i18n.getString("ctf.mapNoName"));

        return true;
    }

    /**
     * Save the state of this filter to a map.
     * This default implementation just saves the instance name.  You may use
     * any key strings except those starting with the string "meta".
     * @param map The map to save to.
     * @return True if saving was sucessful, false if the operation failed.
     */
    boolean save(Map map) {
        map.put(INSTANCE_KEY, instanceName);

        return true;
    }

    /**
     * This method should provide a component that the user can
     * use to manipulate the settings of a concrete configurable
     * filter instance.
     * <p>NOTE: This method will always be called on the event
     *   dispatch thread.
     * @return A compoenent that the user can use to reconfigure the
     *         filter.
     * @see #commitEditorSettings
     * @see #resetEditorSettings
     */
    abstract JComponent getEditorPane();

    /**
     * Commit the settings which are currently in the GUI editor.
     * Under successful conditions, the GUI settings are saved into
     * the state of this object, saved to disk if necessary, and
     * a settings changes is emitted to observers.  If a commit
     * operation fails, it is expected that the logical outer container
     * around the editor will force the user to cancel or correct
     * the settings in the GUI.
     * <p>NOTE: This method will always be called on the event
     *   dispatch thread.
     * @return null if committing was sucessful, an internationalized
     *         string helpful to the
     *         user is returned if the current settings are unacceptable.
     * @see com.sun.javatest.ObservableTestFilter#notifyUpdated
     */
    abstract String commitEditorSettings();

    /**
     * Reset the editor to the settings which reflect the last
     * committed state.  This method will typically be called if the
     * user explictly asks to restore the settings, or the user cancels
     * the editing operation.  No filter observer traffic is generated.
     * <p>NOTE: This method will always be called on the event
     *   dispatch thread.
     */
    abstract void resetEditorSettings();

    /**
     * Does the editor have any uncommitted changes?
     */
    abstract boolean isEditorChanged();

    protected String instanceName;
    protected ExecModel execModel;
    protected static final String INSTANCE_KEY = "instanceName";
    private static I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(ConfigurableTestFilter.class);
}
