import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;

/**
 * A convenience subclass of GridBagConstraints that uses chainable setters and
 * Enumerations to ease the use of the GridBagConstraints class.
 * 
 * @author pchapman
 */
public class GBConstraints extends GridBagConstraints
{
	private static final long serialVersionUID = 1L;

	/**
	 * @see java.awt.GridBagConstraints#gridx
	 */
	public GBConstraints setGridX(int gridx)
	{
		this.gridx = gridx;
		return this;
	}

	/**
	 * @see java.awt.GridBagConstraints#gridy
	 */
	public GBConstraints setGridY(int gridy)
	{
		this.gridy = gridy;
		return this;
	}

	/**
	 * @see java.awt.GridBagConstraints#gridwidth
	 */
	public GBConstraints setGridWidth(int gridwidth)
	{
		this.gridwidth = gridwidth;
		return this;
	}

	/**
	 * @see java.awt.GridBagConstraints#gridheight
	 */
	public GBConstraints setGridHeight(int gridheight)
	{
		this.gridheight = gridheight;
		return this;
	}

	/**
	 * @see java.awt.GridBagConstraints#weightx
	 */
	public GBConstraints setWeightX(double weightx)
	{
		this.weightx = weightx;
		return this;
	}

	/**
	 * @see java.awt.GridBagConstraints#weighty
	 */
	public GBConstraints setWeightY(double weighty)
	{
		this.weighty = weighty;
		return this;
	}

	public enum Anchor {
		Center(CENTER), East(EAST), North(NORTH), NorthEast(NORTHEAST),
		NorthWest(NORTHWEST), South(SOUTH), SouthEast(SOUTHEAST),
		SouthWest(SOUTHWEST), West(WEST);

		private int value;
		Anchor(int value)
		{
			this.value = value;
		}
		int getValue()
		{
			return value;
		}
	}

	/** 
	 * @see java.awt.GridBagConstraints#anchor
	 */
	public GBConstraints setAnchor(Anchor anchor)
	{
		this.anchor = anchor.getValue();
		return this;
	}

	public enum Fill {
		Both(BOTH), Horizontal(HORIZONTAL), None(NONE), Vertical(VERTICAL);

		private int value;
		Fill(int value)
		{
			this.value = value;
		}
		int getValue()
		{
			return value;
		}
	}

	/**
	 * @see java.awt.GridBagConstraints#fill
	 */
	public GBConstraints setFill(Fill fill)
	{
		this.fill = fill.getValue();
		return this;
	}

	/**
	 * @see java.awt.GridBagConstraints#insets
	 */
	public GBConstraints setInsets(Insets insets)
	{
		this.insets = insets;
		return this;
	}
	
	private Insets getNonNullInsets()
	{
		if (insets == null) {
			insets = new Insets(0, 0, 0, 0);
		}
		return insets;
	}

	/**
	 * Adjusts the bottom inset.
	 * @see java.awt.GridBagConstraints#insets
	 */
	public GBConstraints setInsetsBottom(int bottom)
	{
		getNonNullInsets().bottom = bottom;
		return this;
	}

	/**
	 * Adjusts the left inset.
	 * @see java.awt.GridBagConstraints#insets
	 */
	public GBConstraints setInsetsLeft(int left)
	{
		getNonNullInsets().left = left;
		return this;
	}

	/**
	 * Adusts the right inset.
	 * @see java.awt.GridBagConstraints#insets
	 */
	public GBConstraints setInsetsRight(int right)
	{
		getNonNullInsets().right = right;
		return this;
	}

	/**
	 * Adusts the top inset.
	 * @see java.awt.GridBagConstraints#insets
	 */
	public GBConstraints setInsetsTop(int top)
	{
		getNonNullInsets().top = top;
		return this;
	}
	
	/**
	 * @see java.awt.GridBagConstraints#insets
	 * @see java.awt.Insets#Insets(int, int, int, int)
	 */
	public GBConstraints setInsets(int top, int left, int bottom, int right)
	{
		this.insets = new Insets(top, left, bottom, right);
		return this;
	}

	/**
	 * @see java.awt.GridBagConstraints#ipadx
	 */
	public GBConstraints setIPadX(int ipadx)
	{
		this.ipadx = ipadx;
		return this;
	}

	/**
	 * @see java.awt.GridBagConstraints#ipady
	 */
	public GBConstraints setIPadY(int ipady)
	{
		this.ipady = ipady;
		return this;
	}

	/**
	 * A convenience method to clone this object and cast it into a
	 * GBConstraints type.
	 */
	public GBConstraints copy()
	{
		return (GBConstraints)clone();
	}

	/**
	 * An example of using GBConstraints
	 */
	public static final void main(String[] args)
	{
		final JFrame frame = new JFrame("A Test");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		Container cont = frame.getContentPane();
		cont.setLayout(new GridBagLayout());

		// Create a default GBConstraints object that holds the settings most
		// used.
		GBConstraints defaultConstraints =
			new GBConstraints().setFill(Fill.None)
					.setGridWidth(1).setGridHeight(1).setInsets(5, 5, 5, 5)
					.setWeightX(0).setWeightY(0);
		
		// Create a label that will center itself at the top
		cont.add(
			new JLabel("My Really Nice Header"),
			defaultConstraints.copy()
				.setAnchor(Anchor.North).setGridY(0).setGridX(0)
				.setGridWidth(GBConstraints.REMAINDER)
		);

		// A JTextArea that takes up any extra vertical space
		JScrollPane scrollPane = new JScrollPane(new JTextArea());
		scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
		scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		cont.add(
			scrollPane,
			defaultConstraints.copy()
				.setGridY(1).setGridX(0).setGridWidth(GBConstraints.REMAINDER)
				.setWeightY(1).setFill(Fill.Both)
		);

		// some buttons at the bottom of the frame
		// put a place holder to the left of the buttons so that the buttons
		// are "pushed to the right"
		JPanel empty = new JPanel();
		empty.setPreferredSize(new Dimension(0, 0));
		cont.add(
			empty,
			defaultConstraints.copy()
				.setGridY(2).setGridX(0).setWeightX(1).setInsets(0,0,0,0) 
		);
		JButton okbutton = new JButton("OK");
		okbutton.setMnemonic('O');
		cont.add(
			okbutton,
			defaultConstraints.copy()
				.setAnchor(Anchor.SouthEast).setGridY(2).setGridX(1)
		);
		JButton cancelbutton = new JButton("Cancel");
		cancelbutton.setMnemonic('C');
		cont.add(
			cancelbutton,
			defaultConstraints.copy()
				.setAnchor(Anchor.SouthEast).setGridY(2).setGridX(2)
		);
		// Make them try to be the same size.
		okbutton.setPreferredSize(cancelbutton.getPreferredSize());

		frame.pack();
		SwingUtilities.invokeLater(
			new Runnable() {
				public void run() {
					frame.setVisible(true);
				}
			}
		);
	}

}

