/**
 *
 */
package com.tootsville.tootsbook.client.panel;

import java.util.LinkedList;

import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * WRITEME: Document this type. twheys@gmail.com Jan 19, 2010
 * 
 * @author <a href="mailto:twheys@gmail.com@resinteractive.com">Tim
 *         Heys</a>
 */
public class Box extends FlexTable {
	
	/**
	 * WRITEME: Document this type. twheys@gmail.com Jan 19, 2010
	 * 
	 * @author <a href="mailto:twheys@gmail.com@resinteractive.com">Tim
	 *         Heys</a>
	 */
	private static class AccentIcon {
		/**
		 * WRITEME
		 */
		private final Image image;
		
		/**
		 * WRITEME
		 */
		private final int xPos;
		
		/**
		 * WRITEME
		 */
		private final int yPos;
		
		/**
		 * @param accentImage WRITEME
		 * @param x WRITEME
		 * @param y WRITEME
		 */
		AccentIcon (final Image accentImage, final int x, final int y) {
			image = accentImage;
			xPos = x;
			yPos = y;
		}

		/**
		 * @return the image
		 */
		public Image getImage () {
			return image;
		}

		/**
		 * @return the x
		 */
		public int getX () {
			return xPos;
		}

		/**
		 * @return the y
		 */
		public int getY () {
			return yPos;
		}
	}
	
	/**
	 * WRITEME
	 */
	protected final Widget content;
	
	/**
	 * WRITEME
	 */
	private final Anchor footerLink;
	
	/**
	 * WRITEME
	 */
	private boolean hasFooter = true;
	
	/**
	 * WRITEME
	 */
	private boolean hasHeader = true;

	/**
	 * A height value for the header that will be used if
	 * {@link Box#useHeaderHeight} is true
	 */
	private int headerHeight = 0;
	
	/**
	 * WRITEME
	 */
	private String headerText = "";

	/**
	 * List of all images to be used around the box
	 */
	private final LinkedList <AccentIcon> images = new LinkedList <AccentIcon> ();

	/**
	 * Once this box has been built it cannot be built again.
	 */
	private boolean isBuilt = false;

	/**
	 * Boolean flag to determine whether we set a background image
	 * behind the content or not.
	 */
	private boolean useBackground = false;

	/**
	 * Boolean flag to determine whether we set a background image
	 * behind the header or not.
	 */
	private boolean useHeaderBackground = false;

	/**
	 * Are we using a border between the header and content
	 */
	private boolean useHeaderBorder = false;

	/**
	 * Boolean flag to determine whether or not to use the
	 * {@link Box#headerHeight} to explicitly set the height of the
	 * header
	 */
	private boolean useHeaderHeight = false;

	/**
	 * ShadowUser a margin around the box or not
	 */
	private boolean useMargin = true;
	
	/**
	 * Basic constructor. No header or footer will be provided. You MUST
	 * call {@link Box#pack()} after creating this instance.
	 * 
	 * @param w Widget to be added
	 */
	public Box (final Widget w) {
		this (w, "", "", "");
		hasHeader = false;
		hasFooter = false;
	}
	
	/**
	 * Create a box with a header. You MUST call {@link Box#pack()}
	 * after creating this instance.
	 * 
	 * @param w Widget to be added
	 * @param header String for text on header
	 */
	public Box (final Widget w, final String header) {
		this (w, header, "", "");
		hasFooter = false;
	}
	
	/**
	 * Create a box with a header and a link in the footer. You MUST
	 * call {@link Box#pack()} after creating this instance.
	 * 
	 * @param w Widget to be added
	 * @param header String for text on header
	 * @param footer String for link on footer
	 * @param click ClickHandler for footer instead of using a URL
	 */
	public Box (final Widget w, final String header,
			final String footer, final ClickHandler click) {
		setStyleName ("box");
		content = w;
		headerText = header;
		footerLink = new Anchor (footer, true, "javascript:;");
		footerLink.addClickHandler (click);
		footerLink.setStyleName ("head-foot-color");
	}
	
	/**
	 * Create a box with a header and a link in the footer. You MUST
	 * call {@link Box#pack()} after creating this instance.
	 * 
	 * @param w Widget to be added
	 * @param header String for text on header
	 * @param footer String for link on footer
	 * @param url URL for link on footer
	 */
	public Box (final Widget w, final String header,
			final String footer, final String url) {
		setStyleName ("box");
		content = w;
		headerText = header;
		footerLink = new Anchor (footer, true, url);
		footerLink.setStyleName ("head-foot-color");
	}
	
	/**
	 * <pre>
	 * twheys@gmail.com Jan 19, 2010
	 * </pre>
	 * 
	 * TO addAccentIcons WRITEME...
	 * 
	 * @return WRITEME
	 */
	private AbsolutePanel addAccentIcons () {
		System.out.println ("Adding accent icons.");
		final AbsolutePanel iconPanel = new AbsolutePanel ();
		iconPanel.setSize ("100%", "1px");
		iconPanel.setStyleName ("accent");
		for (final AccentIcon icon : images) {
			System.out.println ("Adding new icon.");
			iconPanel
					.add (icon.getImage (), icon.getX (), icon.getY ());
		}

		return iconPanel;
	}
	
	/**
	 * Add an image with an x and y coordinate relative positioning.
	 * 
	 * @param image The image to be added
	 * @param x x coordinate, vertical number of pixels
	 * @param y y coordinate, horizontal number of pixels
	 */
	public void addRelImage (final Image image, final int x, final int y) {
		images.add (new AccentIcon (image, x, y));
	}
	
	/**
	 * <pre>
	 * twheys@gmail.com Jan 19, 2010
	 * </pre>
	 * 
	 * TO buildAccentIcons WRITEME...
	 * 
	 * @param row WRITEME
	 */
	private void buildAccentIcons (final int row) {
		setWidget (row, 0, addAccentIcons ());
	}
	
	/**
	 * <pre>
	 * twheys@gmail.com Jan 19, 2010
	 * </pre>
	 * 
	 * TO buildAndInsertHeader WRITEME...
	 * 
	 * @param row WRITEME
	 * @return WRITEME
	 */
	private SimplePanel buildAndInsertHeader (final int row) {
		final Widget headerLabel = getHeaderChild (headerText);
		// headerLabel.setStyleName ("header-label");
		final SimplePanel header = new SimplePanel ();
		header.setWidget (headerLabel);
		insertRow (getRowCount ());
		setWidget (row, 0, header);
		getCellFormatter ().addStyleName (row, 0,
				"box-header head-foot-color box-border");
		if (useHeaderHeight) {
			header.setHeight (headerHeight + "px");
		}
		if (useHeaderBackground) {
			getCellFormatter ().addStyleName (row, 0,
					"box-header-background");
		}
		if (useHeaderBorder) {
			getCellFormatter ().addStyleName (row, 0,
					"box-header-border");
		}
		return header;
	}
	
	/**
	 * <pre>
	 * twheys@gmail.com Jan 14, 2010
	 * </pre>
	 * 
	 * TO getHeaderChild WRITEME...
	 * 
	 * @param text WRITEME
	 * @return WRITEME
	 */
	private Widget getHeaderChild (final String text) {
		if ( !"".equals (text)) {
			return new Label (text);
		}
		return new Anchor ("", true, "");
	}
	
	/**
	 * Build the box and make it visible on the display. This method
	 * MUST be called for something in a box to be displayed correctly.
	 * Once this method has been called you will not be able to add more
	 * images.
	 */
	public void pack () {
		if (isBuilt) {
			return;
		}
		int row = 0;
		if (useMargin) {
			setStyleName ("panel");
		}
		if (hasHeader && hasFooter) {
			// Header
			buildAndInsertHeader (row++ );

			// Box content
			insertRow (getRowCount ());
			setWidget (row, 0, content);
			getCellFormatter ().addStyleName (row, 0,
					"box-color box-contents box-border");
			if (useBackground) {
				getCellFormatter ().addStyleName (row, 0,
						"box-background");
			}
			row++ ;

			footerLink.setStyleName ("head-foot-color");
			final SimplePanel footer = new SimplePanel ();
			footer.setWidget (footerLink);
			insertRow (getRowCount ());
			setWidget (row, 0, footer);
			getCellFormatter ().addStyleName (row, 0,
					"box-footer head-foot-color box-border");
			row++ ;

			buildAccentIcons (row++ );
		} else if (hasHeader) {
			// Header
			buildAndInsertHeader (row++ );

			// Box content
			insertRow (getRowCount ());
			setWidget (row, 0, content);
			getCellFormatter ().addStyleName (row, 0,
					"box-color box-contents-no-footer box-border");
			if (useBackground) {
				getCellFormatter ().addStyleName (row, 0,
						"box-background");
			}
			row++ ;

			// Accent Icons
			buildAccentIcons (row++ );
		} else {
			// Box content
			insertRow (getRowCount ());
			setWidget (row, 0, content);
			getCellFormatter ()
					.addStyleName (row, 0,
							"box-color box-contents-no-footer-header box-border");
			if (useBackground) {
				getCellFormatter ().addStyleName (row, 0,
						"box-background");
			}
			row++ ;

			// Accent Icons
			buildAccentIcons (row++ );
		}
		setCellPadding (0);
		setCellSpacing (0);
		isBuilt = true;
	}

	/**
	 * Set this box to use the header border of the theme.
	 */
	public void removeMargin () {
		useMargin = false;
	}
	
	/**
	 * Explicitly set the height on the header
	 * 
	 * @param height WRITEME
	 */
	public void setHeaderHeight (final int height) {
		headerHeight = height;
		useHeaderHeight = true;
	}
	
	/**
	 * Set this box to use the background image of the theme.
	 */
	public void useBackground () {
		useBackground = true;
	}
	
	/**
	 * Set this box to use the background image of the theme.
	 */
	public void useHeaderBackground () {
		useHeaderBackground = true;
	}

	/**
	 * Set this box to use the header border of the theme.
	 */
	public void useHeaderBorder () {
		useHeaderBorder = true;
	}
}
