/* Copyright (c) 2011, Geert Bergman (geert@scrivo.nl)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of "Scrivo" nor the names of its contributors may be
 *    used to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id: AnchorLayout.js 738 2013-07-12 18:38:39Z geert $
 */

"use strict";

SUI.AnchorLayout = SUI.defineClass(
	/** @lends SUI.AnchorLayout.prototype */{

	/** @ignore */ baseClass: SUI.Box,

	/**
	 * @class
	 * <p>SUI.AnchorLayout is the the component that handles the layout of
	 * anchored boxes. Anchoring means that child boxes can be positioned
	 * relative to the edges of the anchor layout box.
	 * </p>
	 * <p>Suppose you have an input field with a label. In this situation
	 * the label has a fixed size and if the form is enlarged and you only
	 * want the input field to resize.
	 * </p>
	 * <p>This is easy to accomplish with an anchor layout. The label will
	 * have a fixed width and will be anchored to the left side of the
	 * container box (an instance of SUI.AnchorLayout). The input field will
	 * be anchored on the left and right of the container box, setting the
	 * left to a value slightly larger that the right side of the label and
	 * the right to zero. When resizing the container the label will always
	 * be shown at its fixed width and the rest of the width will be used
	 * for the input field.
	 * </p>
	 * <p>Or in code:</p>
	 * var b = new SUI.AnchorLayout({
	 *    top: 10, left 10, width: 800, height: 800
	 *
	 *
	 *
	 * can contain other box elements. It is essentially nothing more than a
	 * SUI.Box with a list of children. It knows how to deal with anchored
	 * boxes.
	 *
	 * @augments SUI.Box
	 *
	 * @description
	 * Construct a SUI.AnchorLayout component.
	 *
	 * @constructs
	 * @param see base class
	 */
	initializer: function(arg) {

		// anchors default to all sides
		if (!arg.anchor) {
			arg.anchor = {left:true,right:true,top:true,bottom:true};
		}

		SUI.AnchorLayout.initializeBase(this, arg);

		// start with an empty children's list
		this.children = [];
	},

	/**
	 * The list of children of this container.
	 * @type SUI.Box[]
	 * @deprecated Will be moved to a getter setter function
	 */
	children: null,

	/**
	 * Add an box to the container. Add it to the document tree and to
	 * the container's list of children.
	 * @param {SUI.AnchorLayout} child box to add
	 * @param {SUI.AnchorLayout} parent Container to add box to (none for this)
	 */
	add: function(child, parent) {
		this.children.push(child);
		child.parent(parent || this);
	},

	/**
	 * Display the Container. Set the CSS positions of the element's box(es)
	 * and for the children of the box.
	 */
	display: function() {

		SUI.AnchorLayout.parentMethod(this, "display");

		for (var i=0; i<this.children.length; i++) {
			this.children[i].display();
		}
	},

	/**
	 * Lay out the Container. Calculate the position of the Container and
	 * it's contents.
	 */
	layOut: function() {
		// call layOut for the children of the Container
		this._layoutChildren();
	},

	/**
	 * Remove a child box.
	 * @param {SUI.Box} child a reference to the box to remove
	 * @param {SUI.AnchorLayout} parent Container to remove box from (none for
	 *     this)
	 */
	remove: function(child, parent) {

		// Find the index in the list of child containers
		var i = this.children.indexOf(child);
		// none found is an error
		if (i === -1) {
			throw "Trying to remove a nonexisting SUI.AnchorLayout";
		}
		// Remove it form the DOM tree ...
		(parent || this).el().removeChild(child.el());
		// ... and from the list
		this.children.splice(i,1);
	},

	/**
	 * Layout the children of the Container. Use the anchors of the children to
	 * place them on the client area of the Container.
	 * @private
	 */
	_layoutChildren: function() {

		for (var i=0; i<this.children.length; i++) {

			var c = this.children[i];

			// do the width calculation using the left and right anchors and
			// the available client width
			if (c.anchor.left && c.anchor.right) {
				c.width(c.parent().clientWidth() - c.left() - c.right());
			} else if (c.anchor.right) {
				c.left(c.parent().clientWidth() - c.width() - c.right());
			} else if (c.anchor.left) {
				c.right(c.parent().clientWidth() - c.width() - c.left());
			}

			// do the height calculation using of the top and bottom anchors
			// and the available client height
			if (c.anchor.top && c.anchor.bottom) {
				c.height(c.parent().clientHeight() - c.top() - c.bottom());
			} else if (c.anchor.bottom) {
				c.top(c.parent().clientHeight() - c.height() - c.bottom());
			} else if (c.anchor.top) {
				c.bottom(c.parent().clientHeight() - c.height() - c.top());
			}

			// now do the child's layOut
			c.layOut();
		}
	}

});