/*
 * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
 * 
 * http://izpack.org/
 * http://izpack.codehaus.org/
 * 
 * Copyright 2006 Klaus Bartz
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 *     
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.izforge.izpack.installer;

import com.izforge.izpack.gui.IzPanelConstraints;
import com.izforge.izpack.gui.IzPanelLayout;
import com.izforge.izpack.gui.LayoutConstants;
import com.izforge.izpack.installer.IzPanel.Filler;

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

/**
 * This class manages the layout for IzPanels. The layout related methods in IzPanel delegates the
 * work to this class. Use the layout helper directly because the delegating methods in IzPanel will
 * be removed in the future.<br>
 * This layout helper works with a GridBagLayout or a IzPanelLayout as layout manager. The layout
 * manager has to be set at calling the method <code>startLayout</code>. This method has to be
 * called before the first add of a component to the IzPanel.<br>
 *
 * @author Klaus Bartz
 */
public class LayoutHelper implements LayoutConstants
{

    JComponent parent;

    /**
     * Indicates whether grid bag layout was started or not
     */
    protected boolean layoutStarted = false;

    /**
     * The default grid bag constraint.
     */
    protected Object defaultConstraints;

    /**
     * Current x position of grid.
     */
    protected int gridxCounter = -1;

    /**
     * Current y position of grid.
     */
    protected int gridyCounter = -1;

    /**
     * internal layout
     */
    protected LayoutManager2 izPanelLayout;

    /**
     * Layout anchor declared in the xml file with the guiprefs modifier "layoutAnchor"
     */
    protected static int ANCHOR = -1;

    protected static int X_STRETCH_TYPE = -1;

    protected static int Y_STRETCH_TYPE = -1;

    protected static double FULL_LINE_STRETCH_DEFAULT = -1.0;

    protected static double FULL_COLUMN_STRETCH_DEFAULT = -1.0;

    protected static Double INITIAL_STRETCH_DEFAULT = 1.0;

    protected static Double DOUBLE_ZERO = 0.0;

    /**
     * Look-up table for gap identifier to gap names for the x direction. The gap names can be used
     * in the XML installation configuration file. Be aware that case sensitivity should be used.
     */
    public final static String[] X_GAP_NAME_LOOK_UP = {"INTERNAL_USED", "labelXGap", "textXGab",
            "controlXGap", "paragraphXGap", "labelToTextXGap", "labelToControlXGap",
            "textToLabelXGap", "controlToLabelXGap", "controlToTextXGap", "textToControlXGap",
            "firstXGap", "INTERNAL_USED", "INTERNAL_USED", "filler1XGap", "filler2XGap",
            "filler3XGap", "filler4XGap", "filler5XGap"};

    /**
     * Look-up table for gap identifier to gap names for the y direction. The gap names can be used
     * in the XML installation configuration file. Be aware that case sensitivity should be used.
     */
    public final static String[] Y_GAP_NAME_LOOK_UP = {"INTERNAL_USED", "labelYGap", "textYGab",
            "controlYGap", "paragraphYGap", "labelToTextYGap", "labelToControlYGap",
            "textToLabelYGap", "controlToLabelYGap", "controlToTextYGap", "textToControlYGap",
            "firstYGap", "INTERNAL_USED", "INTERNAL_USED", "filler1YGap", "filler2YGap",
            "filler3YGap", "filler4YGap", "filler5YGap"};

    /**
     * Identifier of x gap for all default x gaps.
     */
    public final static String ALL_X_GAP = "allXGap";

    /**
     * Identifier of x gap for all default y gaps.
     */
    public final static String ALL_Y_GAP = "allYGap";

    /**
     * Only useable constructor. Creates a layout manager for special purpose.
     *
     * @param parent for which this layout manager will be used
     */
    public LayoutHelper(JComponent parent)
    {
        this();
        this.parent = parent;
        izPanelLayout = new GridBagLayout();
        parent.setLayout(izPanelLayout);
        gridyCounter++;
    }

    /**
     * The default constructor is only useable by derived classes.
     */
    protected LayoutHelper()
    {
        super();
    }

    /**
     * Returns whether the used layout is a GridBagLayout or not.
     *
     * @return whether the used layout is a GridBagLayout or not
     */
    private boolean isGridBag()
    {
        return (izPanelLayout instanceof GridBagLayout);
    }

    /**
     * Returns whether the used layout is an IzPanelLayout or not.
     *
     * @return whether the used layout is an IzPanelLayout or not
     */
    private boolean isIzPanel()
    {
        return (izPanelLayout instanceof IzPanelLayout);
    }

    // ------------------- Common Layout stuff -------------------- START ---

    /**
     * Start layout determining. If it is needed, a dummy component will be created as first row.
     * This will be done, if the IzPack guiprefs modifier with the key "layoutAnchor" has the value
     * "SOUTH" or "SOUTHWEST". The earlier used value "BOTTOM" and the declaration via the IzPack
     * variable <code>IzPanel.LayoutType</code> are also supported.
     *
     * @param layout layout to be used by this layout helper
     */
    public void startLayout(LayoutManager2 layout)
    {
        if (layoutStarted)
        {
            return;
        }
        izPanelLayout = layout;
        if (isGridBag())
        {
            startGridBagLayout();
            return;
        }
        // TODO: impl for IzPanelLayout
        if (isIzPanel())
        {
            startIzPanelLayout();
        }
    }

    /**
     * Special start method for IzPanelLayout. Called from <code>startLayout</code>.
     */
    private void startIzPanelLayout()
    {
        IzPanelLayout.setAnchor(getAnchor());
        IzPanelLayout.setXStretchType(getXStretchType());
        IzPanelLayout.setYStretchType(getYStretchType());
        IzPanelLayout.setFullLineStretch(getFullLineStretch());
        IzPanelLayout.setFullColumnStretch(getFullColumnStretch());
        getXGap(LABEL_GAP); // This call triggers resolving external setting if not already done.
        getYGap(LABEL_GAP); // This call triggers resolving external setting if not already done.
        parent.setLayout(izPanelLayout);
        // parent.add(IzPanelLayout.createGap(TOP_GAP, VERTICAL));
    }

    /**
     * Complete layout determining. If it is needed, a dummy component will be created as last row.
     * This will be done, if the IzPack guiprefs modifier with the key "layoutAnchor" has the value
     * "NORTH" or "NORTHWEST". The earlier used value "TOP" and the declaration via the IzPack
     * variable <code>IzPanel.LayoutType</code> are also supported.
     */
    public void completeLayout()
    {
        if (isGridBag())
        {
            completeGridBagLayout();
        }
        // TODO: impl for IzPanelLayout
    }

    /**
     * Returns the default constraints of this panel.
     *
     * @return the default constraints of this panel
     */
    public Object getDefaultConstraints()
    {
        startLayout(izPanelLayout);
        return defaultConstraints;
    }

    /**
     * Sets the default constraints of this panel to the given object.
     *
     * @param constraints which should be set as default for this object
     */
    public void setDefaultConstraints(Object constraints)
    {

        startLayout(izPanelLayout);
        if ((isGridBag() && !(constraints instanceof GridBagConstraints))
                || (isIzPanel() && !(constraints instanceof IzPanelConstraints)))
        {
            throw new IllegalArgumentException(
                    "Layout and constraints have to be from the same type.");
        }
        defaultConstraints = constraints;
    }

    /**
     * Resets the grid counters which are used at getNextXConstraints and getNextYConstraints.
     */
    public void resetGridCounter()
    {
        gridxCounter = -1;
        gridyCounter = -1;
    }

    /**
     * Returns a newly created constraints with the given values and the values from the default
     * constraints for the other parameters.
     *
     * @param gridx value to be used for the new constraint
     * @param gridy value to be used for the new constraint
     * @return newly created constraints with the given values and the values from the default
     *         constraints for the other parameters
     */
    public Object getNewConstraints(int gridx, int gridy)
    {
        if (isGridBag())
        {
            GridBagConstraints retval = (GridBagConstraints) ((GridBagConstraints) getDefaultConstraints())
                    .clone();
            retval.gridx = gridx;
            retval.gridy = gridy;
            return (retval);
        }
        if (isIzPanel())
        {
            IzPanelConstraints retval = (IzPanelConstraints) ((IzPanelConstraints) getDefaultConstraints())
                    .clone();
            retval.setXPos(gridx);
            retval.setYPos(gridy);
            return (retval);
        }
        return (null);
    }

    /**
     * Returns a newly created constraints with the given values and the values from the
     * defaultGridBagConstraints for the other parameters.
     *
     * @param gridx      value to be used for the new constraint
     * @param gridy      value to be used for the new constraint
     * @param gridwidth  value to be used for the new constraint
     * @param gridheight value to be used for the new constraint
     * @return newly created constraints with the given values and the values from the default
     *         constraints for the other parameters
     */
    public Object getNewConstraints(int gridx, int gridy, int gridwidth, int gridheight)
    {
        Object retval = getNewConstraints(gridx, gridy);
        if (isGridBag())
        {
            GridBagConstraints gbc = (GridBagConstraints) retval;
            gbc.gridwidth = gridwidth;
            gbc.gridheight = gridheight;
        }
        if (isIzPanel())
        {
            IzPanelConstraints gbc = (IzPanelConstraints) retval;
            gbc.setXWeight(gridwidth);
            gbc.setYWeight(gridheight);
        }
        return (retval);
    }

    /**
     * Returns a newly created constraints for the next column of the current layout row.
     *
     * @return a newly created constraints for the next column of the current layout row
     */
    public Object getNextXConstraints()
    {
        gridxCounter++;
        return (getNewConstraints(gridxCounter, gridyCounter));
    }

    /**
     * Returns a newly created constraints with column 0 for the next row.
     *
     * @return a newly created constraints with column 0 for the next row
     */
    public Object getNextYConstraints()
    {
        gridyCounter++;
        gridxCounter = 0;
        return (getNewConstraints(0, gridyCounter));
    }

    /**
     * Returns a newly created constraints with column 0 for the next row using the given
     * parameters.
     *
     * @param gridwidth  width for this constraint
     * @param gridheight height for this constraint
     * @return a newly created constraints with column 0 for the next row using the given parameters
     */
    public Object getNextYConstraints(int gridwidth, int gridheight)
    {
        gridyCounter++;
        gridxCounter = 0;
        return (getNewConstraints(0, gridyCounter, gridwidth, gridheight));
    }

    // ------------------- Common Layout stuff -------------------- END ---

    // ------------------- GridBag Layout stuff -------------------- START ---

    /**
     * Start layout determining. If it is needed, a dummy component will be created as first row.
     * This will be done, if the IzPack guiprefs modifier with the key "layoutAnchor" has the value
     * "SOUTH" or "SOUTHWEST". The earlier used value "BOTTOM" and the declaration via the IzPack
     * variable <code>IzPanel.LayoutType</code> are also supported.
     */
    private void startGridBagLayout()
    {
        if (layoutStarted)
        {
            return;
        }
        layoutStarted = true;
        if (izPanelLayout == null || !(izPanelLayout instanceof GridBagLayout))
        {
            izPanelLayout = new GridBagLayout();
        }
        GridBagConstraints dgbc = new GridBagConstraints();
        dgbc.insets = new Insets(0, 0, getYGap(LABEL_GAP), 0);
        dgbc.anchor = GridBagConstraints.WEST;
        defaultConstraints = dgbc;
        parent.setLayout(izPanelLayout);
        switch (getAnchor())
        {
            case SOUTH:
            case SOUTH_WEST:
                // Make a header to push the rest to the bottom.
                Filler dummy = new Filler();
                GridBagConstraints gbConstraint = (GridBagConstraints) getNextYConstraints();
                gbConstraint.weighty = 1.0;
                gbConstraint.fill = GridBagConstraints.BOTH;
                gbConstraint.anchor = GridBagConstraints.WEST;
                parent.add(dummy, gbConstraint);
                break;
            default:
                break;
        }
        // TODO: impl for layout type CENTER, ...
    }

    /**
     * Complete layout determining. If it is needed, a dummy component will be created as last row.
     * This will be done, if the IzPack guiprefs modifier with the key "layoutAnchor" has the value
     * "NORTH" or "NORTHWEST". The earlier used value "TOP" and the declaration via the IzPack
     * variable <code>IzPanel.LayoutType</code> are also supported.
     */
    private void completeGridBagLayout()
    {
        switch (getAnchor())
        {
            case NORTH:
            case NORTH_WEST:
                // Make a footer to push the rest to the top.
                Filler dummy = new Filler();
                GridBagConstraints gbConstraint = (GridBagConstraints) getNextYConstraints();
                gbConstraint.weighty = 1.0;
                gbConstraint.fill = GridBagConstraints.BOTH;
                gbConstraint.anchor = GridBagConstraints.WEST;
                parent.add(dummy, gbConstraint);
                break;
            default:
                break;
        }
    }

    /**
     * Returns the anchor as value declared in GridBagConstraints. Possible are NORTH, NORTHWEST,
     * SOUTH, SOUTHWEST and CENTER. The values can be configured in the xml description file with
     * the variable "IzPanel.LayoutType". The old values "TOP" and "BOTTOM" from the xml file are
     * mapped to NORTH and SOUTH.
     *
     * @return the anchor defined in the IzPanel.LayoutType variable.
     */
    public static int getAnchor()
    {
        if (ANCHOR >= 0)
        {
            return (ANCHOR);
        }
        AutomatedInstallData idata = AutomatedInstallData.getInstance();
        String todo;
        if (idata instanceof InstallData
                && ((InstallData) idata).guiPrefs.modifier.containsKey("layoutAnchor"))
        {
            todo = ((InstallData) idata).guiPrefs.modifier.get("layoutAnchor");
        }
        else
        {
            todo = idata.getVariable("IzPanel.LayoutType");
        }
        if (todo == null) // No command, no work.
        {
            ANCHOR = CENTER;
        }
        else if ("EAST".equalsIgnoreCase(todo))
        {
            ANCHOR = EAST;
        }
        else if ("WEST".equalsIgnoreCase(todo))
        {
            ANCHOR = WEST;
        }
        else if ("TOP".equalsIgnoreCase(todo) || "NORTH".equalsIgnoreCase(todo))
        {
            ANCHOR = NORTH;
        }
        else if ("BOTTOM".equalsIgnoreCase(todo) || "SOUTH".equalsIgnoreCase(todo))
        {
            ANCHOR = SOUTH;
        }
        else if ("SOUTHWEST".equalsIgnoreCase(todo) || "SOUTH_WEST".equalsIgnoreCase(todo))
        {
            ANCHOR = SOUTH_WEST;
        }
        else if ("SOUTHEAST".equalsIgnoreCase(todo) || "SOUTH_EAST".equalsIgnoreCase(todo))
        {
            ANCHOR = SOUTH_EAST;
        }
        else if ("NORTHWEST".equalsIgnoreCase(todo) || "NORTH_WEST".equalsIgnoreCase(todo))
        {
            ANCHOR = NORTH_WEST;
        }
        else if ("NORTHEAST".equalsIgnoreCase(todo) || "NORTH_EAST".equalsIgnoreCase(todo))
        {
            ANCHOR = NORTH_EAST;
        }
        else if ("CENTER".equalsIgnoreCase(todo))
        {
            ANCHOR = CENTER;
        }
        return (ANCHOR);
    }

    /**
     * Returns the gap which should be used between the given gui objects for the x direction. The
     * value will be configurable by guiprefs modifiers. Valid values are all entries in the static
     * String array X_GAP_NAME_LOOK_UP of this class. There are constant ints for the indexes of
     * this array.
     *
     * @param gapId index in array GAP_NAME_LOOK_UP for the needed gap
     * @return the gap depend on the xml-configurable guiprefs modifier
     */
    public static int getXGap(int gapId)
    {
        gapId = IzPanelLayout.verifyGapId(gapId);
        if (IzPanelLayout.getDefaultXGap(GAP_LOAD_MARKER) >= 0)
        {
            return (IzPanelLayout.getDefaultXGap(gapId));
        }
        AutomatedInstallData idata = AutomatedInstallData.getInstance();
        if (!(idata instanceof InstallData))
        {
            return (IzPanelLayout.getDefaultXGap(gapId));
        }
        String var = null;
        InstallData id = (InstallData) idata;
        int commonDefault = -1;
        if (id.guiPrefs.modifier.containsKey(ALL_X_GAP))
        {
            try
            {
                commonDefault = Integer.parseInt(id.guiPrefs.modifier.get(ALL_X_GAP));
            }
            catch (NumberFormatException nfe)
            {
                // Do nothing else use the default value.
                // Need to set it again at this position??
            }

        }
        for (int i = 0; i < X_GAP_NAME_LOOK_UP.length; ++i)
        {
            int currentDefault = 0;
            if (commonDefault >= 0)
            {
                currentDefault = commonDefault;
            }
            else
            {
                var = id.guiPrefs.modifier.get(X_GAP_NAME_LOOK_UP[i]);
                if (var != null)
                {
                    try
                    {
                        currentDefault = Integer.parseInt(var);
                    }
                    catch (NumberFormatException nfe)
                    {
                        // Do nothing else use the default value.
                        // Need to set it again at this position??
                    }
                }
            }
            IzPanelLayout.setDefaultXGap(currentDefault, i);
        }
        IzPanelLayout.setDefaultXGap(0, GAP_LOAD_MARKER); // Mark external settings allready
        // loaded.
        return (IzPanelLayout.getDefaultXGap(gapId));
    }

    /**
     * Returns the gap which should be used between the given gui objects for the y direction. The
     * value will be configurable by guiprefs modifiers. Valid values are all entries in the static
     * String array Y_GAP_NAME_LOOK_UP of this class. There are constant ints for the indexes of
     * this array.
     *
     * @param gapId index in array GAP_NAME_LOOK_UP for the needed gap
     * @return the gap depend on the xml-configurable guiprefs modifier
     */
    public static int getYGap(int gapId)
    {
        gapId = IzPanelLayout.verifyGapId(gapId);
        if (IzPanelLayout.getDefaultYGap(GAP_LOAD_MARKER) >= 0)
        {
            return (IzPanelLayout.getDefaultYGap(gapId));
        }
        AutomatedInstallData idata = AutomatedInstallData.getInstance();
        if (!(idata instanceof InstallData))
        {
            return (IzPanelLayout.getDefaultYGap(gapId));
        }
        String var = null;
        InstallData id = (InstallData) idata;
        int commonDefault = -1;
        if (id.guiPrefs.modifier.containsKey(ALL_Y_GAP))
        {
            try
            {
                commonDefault = Integer.parseInt(id.guiPrefs.modifier.get(ALL_Y_GAP));
            }
            catch (NumberFormatException nfe)
            {
                // Do nothing else use the default value.
                // Need to set it again at this position??
            }

        }
        for (int i = 0; i < Y_GAP_NAME_LOOK_UP.length; ++i)
        {
            int currentDefault = 0;
            if (commonDefault >= 0)
            {
                currentDefault = commonDefault;
            }
            else
            {
                var = id.guiPrefs.modifier.get(Y_GAP_NAME_LOOK_UP[i]);
                if (var != null)
                {
                    try
                    {
                        currentDefault = Integer.parseInt(var);
                    }
                    catch (NumberFormatException nfe)
                    {
                        // Do nothing else use the default value.
                        // Need to set it again at this position??
                    }
                }
            }
            IzPanelLayout.setDefaultYGap(currentDefault, i);
        }
        IzPanelLayout.setDefaultYGap(0, GAP_LOAD_MARKER); // Mark external settings allready
        // loaded.
        return (IzPanelLayout.getDefaultYGap(gapId));
    }

    /**
     * Returns the used stretch type for the x direction. Possible are NO_STRETCH, RELATIVE_STRETCH
     * and ABSOLUTE_STRETCH. The stretch type will be used at rows where one or more components has
     * a stretch value greater than 0.0 in the constraints. If NO_STRETCH is used, no stretch will
     * be performed. If ABSOLUTE_STRETCH is used, parts of the unused area are given to the
     * components depending on the unmodified stretch value. At RELATIVE_STRETCH first the hole
     * stretch for a row will be computed. Relative to this value the unused area will be splited.<br>
     * The default type is ABSOLUTE_STRETCH. With the modifier "layoutXStretchType" of the "info"
     * section of the installation configuration file this can be changed.
     *
     * @return used stretch type
     */
    public static int getXStretchType()
    {
        if (X_STRETCH_TYPE > -1)
        {
            return (X_STRETCH_TYPE);
        }
        X_STRETCH_TYPE = ABSOLUTE_STRETCH;
        String var = ((String) getModifierValue(null, "RELATIVE_STRETCH", null,
                "layoutXStretchType"));
        if (var != null)
        {
            if ("RELATIVE_STRETCH".equalsIgnoreCase(var) || "RELATIVE".equalsIgnoreCase(var))
            {
                X_STRETCH_TYPE = RELATIVE_STRETCH;
            }
            else if ("ABSOLUTE_STRETCH".equalsIgnoreCase(var) || "ABSOLUTE".equalsIgnoreCase(var))
            {
                X_STRETCH_TYPE = ABSOLUTE_STRETCH;
            }
            else if ("NO_STRETCH".equalsIgnoreCase(var) || "NO".equalsIgnoreCase(var))
            {
                X_STRETCH_TYPE = NO_STRETCH;
            }
        }
        return (X_STRETCH_TYPE);
    }

    /**
     * Returns the used stretch type for the y direction. Possible are NO_STRETCH, RELATIVE_STRETCH
     * and ABSOLUTE_STRETCH. The stretch type will be used at rows where one or more components has
     * a stretch value greater than 0.0 in the constraints. If NO_STRETCH is used, no stretch will
     * be performed. If ABSOLUTE_STRETCH is used, parts of the unused area are given to the
     * components depending on the unmodified stretch value. At RELATIVE_STRETCH first the hole
     * stretch for a row will be computed. Relative to this value the unused area will be splited.<br>
     * The default type is ABSOLUTE_STRETCH. With the modifier "layoutYStretchType" of the "info"
     * section of the installation configuration file this can be changed.
     *
     * @return used stretch type
     */
    public static int getYStretchType()
    {
        if (Y_STRETCH_TYPE > -1)
        {
            return (Y_STRETCH_TYPE);
        }
        Y_STRETCH_TYPE = ABSOLUTE_STRETCH;
        String var = ((String) getModifierValue(null, "RELATIVE_STRETCH", null,
                "layoutYStretchType"));
        if (var != null)
        {
            if ("RELATIVE_STRETCH".equalsIgnoreCase(var) || "RELATIVE".equalsIgnoreCase(var))
            {
                Y_STRETCH_TYPE = RELATIVE_STRETCH;
            }
            else if ("ABSOLUTE_STRETCH".equalsIgnoreCase(var) || "ABSOLUTE".equalsIgnoreCase(var))
            {
                Y_STRETCH_TYPE = ABSOLUTE_STRETCH;
            }
            else if ("NO_STRETCH".equalsIgnoreCase(var) || "NO".equalsIgnoreCase(var))
            {
                Y_STRETCH_TYPE = NO_STRETCH;
            }
        }
        return (Y_STRETCH_TYPE);
    }

    /**
     * Returns the default value for stretching to a full line. With the modifier
     * "layoutFullLineStretch" of the "info" section of the installation configuration file this can
     * be changed. Valid are doubles for the value. This setting is possible to give panels a chance
     * to center the controls in x direction also a control uses stretching.
     *
     * @return the default value for stretching to a full line
     */

    public static double getFullLineStretch()
    {
        FULL_LINE_STRETCH_DEFAULT = (Double) getModifierValue(
                FULL_LINE_STRETCH_DEFAULT, INITIAL_STRETCH_DEFAULT, DOUBLE_ZERO,
                "layoutFullLineStretch");
        return (FULL_LINE_STRETCH_DEFAULT);
    }

    /**
     * Returns the default value for stretching to a full column. With the modifier
     * "layoutFullColumnStretch" of the "info" section of the installation configuration file this
     * can be changed. Valid are doubles for the value. This setting is possible to give panels a
     * chance to center the controls in y direction also a control uses stretching.
     *
     * @return the default value for stretching to a full column
     */

    public static double getFullColumnStretch()
    {
        FULL_COLUMN_STRETCH_DEFAULT = (Double) getModifierValue(FULL_COLUMN_STRETCH_DEFAULT, INITIAL_STRETCH_DEFAULT, DOUBLE_ZERO,
                "layoutFullColumnStretch");
        return (FULL_COLUMN_STRETCH_DEFAULT);
    }

    private static Object getModifierValue(Object currentVal, Object defaultVal, Object readLimit,
                                           String key)
    {
        if (defaultVal instanceof Integer)
        {
            if ((Integer) currentVal >= (Integer) readLimit)
            {
                return (currentVal);
            }
        }
        if (defaultVal instanceof Double)
        {
            if ((Double) currentVal >= (Double) readLimit)
            {
                return (currentVal);
            }
        }
        Object retval = defaultVal;
        AutomatedInstallData idata = AutomatedInstallData.getInstance();
        if (!(idata instanceof InstallData))
        {
            return (retval);
        }
        String var = null;
        if (((InstallData) idata).guiPrefs.modifier.containsKey(key))
        {
            var = ((InstallData) idata).guiPrefs.modifier.get(key);
            if (var != null)
            {
                try
                {
                    if (defaultVal instanceof Integer)
                    {
                        return (Integer.parseInt(var));
                    }
                    if (defaultVal instanceof Double)
                    {
                        return (Double.parseDouble(var));
                    }
                    return (var);
                }
                catch (NumberFormatException nfe)
                {
                    // Do nothing else use the default value.
                    // Need to set it again at this position??
                }
            }
        }
        return (retval);
    }

    /**
     * Returns the layout manager which current used by this layout helper. The layout manager
     * implements LayoutManager2. It can be a GridBagLayout or a IzPanelLayout.
     *
     * @return current used layout manager
     */
    public LayoutManager2 getLayout()
    {
        return izPanelLayout;
    }

    /**
     * Sets the given layout manager for this layout helper to be used.
     *
     * @param izPanelLayout layout manager to be used
     */
    public void setLayout(LayoutManager2 izPanelLayout)
    {
        this.izPanelLayout = izPanelLayout;
    }

}
