package org.jcon.ui.easylayout;

import java.awt.GridBagConstraints;
import java.awt.Insets;

/**
 * Represents a style used by EasyLayout. Its main responsiblity
 * is to carry the GridBagConstraints properties. The
 * initial values of these are the Default style and are
 * identical to GridBagConstraints' initial values.
 *
 * We have taken a very flexible approach to styles.
 * There are a variety of ways to use them, such as:
 *
 * 1. Use just EasyLayoutStyle to create constraints and
 * work directly with GridBagLayout. For this you would
 * need only this class.
 *
 * 2. Use just EasyLayout, which uses EasyLayoutStyle.
 * For this approach you need just 2 easy classes.
 *
 * 3. Use EasyLayout, EasyLayoutStyle and a class with a
 * method similar to EasyLayoutLibrary.storeAllStyles().
 * Use this approach if you want to design and reuse a
 * suite of styles with particular instances of EasyLayout.
 * For this approach you need 2 easy classes.
 *
 * 4. Suppose you wish to deploy a suite of styles to all
 * EasyLayout instances. Use EasyLayout, EasyLayoutStyle,
 * EasyLayoutRegistry and a class(s) implementing
 * EasyLayoutLibrary. This takes 4 easy classes.
 *
 * @author Jack Harich
 */
public class EasyLayoutStyle implements
    Cloneable, java.io.Serializable {

//---------- Protected Fields ----------------------------
protected GridBagConstraints gbConstraints = new GridBagConstraints();

protected String name;
protected String description; // For optional use

// Properties that map to GridBagConstraints
// Initially set to Default values
protected String    alignment = "Center";
protected String    stretch   = "None";

protected double    widthWeight  = 0;
protected double    heightWeight = 0;

protected Insets insets = new Insets(0, 0, 0, 0);

protected int       row    = 0;
protected int       column = 0;

protected int       gridWidth  = 1;
protected int       gridHeight = 1;

protected int       extraSizeWidth  = 0;
protected int       extraSizeHeight = 0;

//---------- Initialization ------------------------------
/** public EasyLayoutStyle() {
    // Do nothing
} */
public EasyLayoutStyle(String name) {
    this.name = name;
}
//---------- Superclass Overrides ------------------------
/**
 * Returns a deep copy of this style.
 */
public Object clone() {
    EasyLayoutStyle clone =  new EasyLayoutStyle(name);

    clone.gbConstraints = (GridBagConstraints)gbConstraints.clone();
    if (description != null) clone.description = description.intern();

    clone.alignment = alignment.intern();
    clone.stretch = stretch.intern();
    clone.widthWeight = widthWeight;
    clone.heightWeight = heightWeight;
    clone.insets = (Insets)insets.clone();

    clone.row = row;
    clone.column = column;
    clone.gridWidth = gridWidth;
    clone.gridHeight = gridHeight;
    clone.extraSizeWidth = extraSizeWidth;
    clone.extraSizeHeight = extraSizeHeight;

    return clone;
}
public String toString() {
    return "[name=" + name +
           ", alignment=" + alignment +
           ", stretch=" + stretch +
           ", widthWeight=" + widthWeight +
           ", heightWeight=" + heightWeight + ",\n" +

           " insets=(" + insets.top + ", " + insets.left +
           ", " + insets.bottom + ", " + insets.right + ")" +

           ", row=" + row +
           ", column=" + column + ",\n" +

           " gridWidth=" + gridWidth +
           ", gridHeight=" + gridHeight +

           ", extraSizeWidth=" + extraSizeWidth +
           ", extraSizeHeight=" + extraSizeHeight + "]";
}
//---------- Properties ----------------------------------
//----- Name
public void setName(String name) {
    this.name = name;
}
public String getName() {
    return name;
}
//----- Description
public void setDescription(String description) {
    this.description = description;
}
public String getDescription() {
    return description;
}
//---------- Style properties
//----- Alignment
/**
 * Sets the Alignment property. Valid values are "Center",
 * "Top", "Left", "Bottom" or "Right". Throws an IllegalArgumentException
 * if an invalid value is provided.
 */
public void setAlignment(String alignment) {
    String value = alignment.intern();
    if (value == "Center") {
        gbConstraints.anchor = GridBagConstraints.CENTER;
    } else if (value == "Top") {
        gbConstraints.anchor = GridBagConstraints.NORTH;
    } else if (value == "Left") {
        gbConstraints.anchor = GridBagConstraints.WEST;
    } else if (value == "Bottom") {
        gbConstraints.anchor = GridBagConstraints.SOUTH;
    } else if (value == "Right") {
        gbConstraints.anchor = GridBagConstraints.EAST;
    } else {
        throw new IllegalArgumentException("Unknown alignment '" + value + "'.");
    }
    this.alignment = value;
}
public String getAlignment() {
    return alignment;
}
//----- Insets
public void setInsetTop(int insetTop) {
    insets.top = insetTop;
    gbConstraints.insets.top = insetTop;
}
public void setInsetLeft(int insetLeft) {
    insets.left = insetLeft;
    gbConstraints.insets.left = insetLeft;
}
public void setInsetBottom(int insetBottom) {
    insets.bottom = insetBottom;
    gbConstraints.insets.bottom = insetBottom;
}
public void setInsetRight(int insetRight) {
    insets.right = insetRight;
    gbConstraints.insets.right = insetRight;
}
/**
 * Sets the 4 Inset properties.
 */
public void setInsets(int top, int left, int bottom, int right) {
    setInsetTop(top);
    setInsetLeft(left);
    setInsetBottom(bottom);
    setInsetRight(right);
}
public Insets getInsets() {
    return (Insets)insets.clone();
}
//----- Stretch
/**
 * Sets the Stretch property. Valid values are "None",
 * "Both", "Width" or "Height". Throws an IllegalArgumentException
 * if an invalid value is provided.
 *
 * "None" - The components normal size is used. This is
 * the most common value.
 *
 * "Both" - The component is stretched to fill its cells.
 *
 * "Width" - The component's width is stretched to fill
 * its cells but its normal height is used.
 *
 * "Height" - The component's height is stretched to fill
 * its cells but its normal width is used.
 */
public void setStretch(String stretch) {
    String value = stretch.intern();
    if (value == "None") {
        gbConstraints.fill = GridBagConstraints.NONE;
    } else if (value == "Both") {
        gbConstraints.fill = GridBagConstraints.BOTH;
    } else if (value == "Width") {
        gbConstraints.fill = GridBagConstraints.HORIZONTAL;
    } else if (value == "Height") {
        gbConstraints.fill = GridBagConstraints.VERTICAL;
    } else {
        throw new IllegalArgumentException("Unknown stretch '" + value + "'.");
    }
    this.stretch = value;
}
public String getStretch() {
    return stretch;
}
//----- WidthWeight
/**
 * Sets the WidthWeight property. This determines the amount
 * of width resizing a component receives if extra width is
 * available. A zero value causes no extra width.
 * See GridBagConstraints.weightx for full documentation.
 */
public void setWidthWeight(double widthWeight) {
  this.widthWeight = widthWeight;
  gbConstraints.weightx = widthWeight;
}
public double getWidthWeight() {
    return widthWeight;
}
//----- HeightWeight
/**
 * Sets the HeightWeight property. Similar to setWidthWeight().
 */
public void setHeightWeight(double heightWeight) {
  this.heightWeight = heightWeight;
  gbConstraints.weighty = heightWeight;
}
public double getHeightWeight() {
    return heightWeight;
}
//----- Column
/**
 * Sets the Column property. Zero means none, which causes
 * an add to the "next" column. One or more means adds will
 * be to that column.
 *
 * Note we use one based cell indexes, not zero based.
 */
public void setColumn(int column) {
    this.column = column;
    if (column == 0) {
        gbConstraints.gridx = GridBagConstraints.RELATIVE;
    } else {
        gbConstraints.gridx = column - 1;
    }
}
public int getColumn() {
    return column;
}
//----- Row
/**
 * Sets the Row property. Similar to setColumn().
 */
public void setRow(int row) {
    this.row = row;
    if (row == 0) {
        gbConstraints.gridy = GridBagConstraints.RELATIVE;
    } else {
        gbConstraints.gridy = row - 1;
    }
}
public int getRow() {
    return row;
}
//----- Column and Row
/**
 * A convenience method that sets the Row and Column.
 */
public void setRowColumn(int row, int column) {
    setRow(row);
    setColumn(column);
}
//----- GridWidth
/**
 * Sets the GridWidth property, which determines how many
 * cells wide the component will be, starting at its
 * Column. The usual value is one.
 *
 * A value of zero will cause the component to fill all
 * cells to the end of the row, starting at its column.
 * Remember to reset the GridWidth to one.
 * This can be achieved more readably with addEndRow().
 */
public void setGridWidth(int gridWidth) {
    this.gridWidth = gridWidth;
    if (gridWidth == 0) {
        gbConstraints.gridwidth = GridBagConstraints.REMAINDER;
    } else {
        gbConstraints.gridwidth = gridWidth;
    }
}
public int getGridWidth() {
    return gridWidth;
}
//----- GridHeight
/**
 * Sets the GridHeight property, which determines how many
 * cells high the component will be, starting at its
 * Row. The usual value is one.
 *
 * A value of zero will cause the component to fill all
 * cells to the end of the column, starting at its row.
 */
public void setGridHeight(int gridHeight) {
    this.gridHeight = gridHeight;
    if (gridHeight == 0) {
        gbConstraints.gridheight = GridBagConstraints.REMAINDER;
    } else {
        gbConstraints.gridheight = gridHeight;
    }
}
public int getGridHeight() {
    return gridHeight;
}
//----- GridWidth and GridHeight
/**
 * A convenience method that sets GridWidth and GridHeight.
 */
public void setGridWidthHeight(int gridWidth, int gridHeight) {
    setGridWidth(gridWidth);
    setGridHeight(gridHeight);
}
//----- ExtraSizeWidth
/**
 * Sets the ExtraSizeWidth property, which determines the
 * extra pixels added to a component's preferred size
 * during layout. The usual value is zero.
 * Note the value may be negative.
 */
public void setExtraSizeWidth(int extraSizeWidth) {
    this.extraSizeWidth = extraSizeWidth;
    gbConstraints.ipadx = extraSizeWidth;
}
public int getExtraSizeWidth() {
    return extraSizeWidth;
}
//----- ExtraSizeHeight
/**
 * Sets the ExtraSizeHeight property. Similar to
 * setExtraSizeWidth().
 */
public void setExtraSizeHeight(int extraSizeHeight) {
    this.extraSizeHeight = extraSizeHeight;
    gbConstraints.ipady = extraSizeHeight;
}
public int getExtraSizeHeight() {
    return extraSizeHeight;
}
//----- Other
/**
 * A convenience method that returns the already cast clone.
 */
public EasyLayoutStyle createClone() {
    return (EasyLayoutStyle)clone();
}
//---------- Package Methods -----------------------------
/**
 * Returns the GridBagConstraints this style currently
 * represents. These are not cloned.
 *
 * We have chosen not to expose GridBagConstraints to be
 * able to use a different underlying layout mechanism in
 * the future.
 */
GridBagConstraints getConstraints() {
    return gbConstraints;
}

} // End class
