/***********************************************************************************************************
 dhtml_base.js - Custom API for cross-platform element positioning, rendering and manipulation.
 Copyright 2004 - 2008, Robert I. Sadler (http://www.southerncape.co.za)
 
 Some functions based on / copied from :
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Goodman, D. 2002. Dynamic HTML: The Definitive Reference. (2nd ed.). O'Reilly. ISBN: 0-596-00316-1. [DH2]
 Goodman, D. 2003. JavaScript & DHTML Cookbook. O'Reilly. ISBN: 0-596-00467-2. [JDC]
 Turnbull, A. (http://www.twinhelix.com). [THX]

 Release 3.0 - Supports Internet Explorer 6 (in Standards-Compatiblility Mode) or newer; Firefox 2 or newer; and W3C
               DOM compatible browsers.
 
 I am working on the assumption that the browser is either fully W3C compliant or IE6/7 in Standards-
 Compatiblility Mode. It should also fail horribly in non-supported browsers! 
************************************************************************************************************/

function isNull(a) { return typeof a == 'object' && !a }

/***********************************************************************
 AddEvent Manager (c) 2005-2006 Angus Turnbull http://www.twinhelix.com
 Free usage permitted as long as this credit notice remains intact.
***********************************************************************/

if (typeof addEvent != 'function') {
	var addEvent = function(o, t, f, l) {
		var d = 'addEventListener', n = 'on' + t, rO = o, rT = t, rF = f, rL = l;
		if (o[d] && !l) return o[d](t, f, false);
		if (!o._evts) o._evts = {};
		if (!o._evts[t]) {
			o._evts[t] = o[n] ? { b: o[n] } : {};
			o[n] = new Function('e', 'var r = true, o = this, a = o._evts["' + t + '"], i; for (i in a) {' + 'o._f = a[i]; r = o._f(e||window.event) != false && r; o._f = null;' + '} return r');
			if (t != 'unload') addEvent(window, 'unload', function() {
 				removeEvent(rO, rT, rF, rL);
 				});
			}
		if (!f._i) f._i = addEvent._i++;
		o._evts[t][f._i] = f;
		};
	addEvent._i = 1;
	var removeEvent = function(o, t, f, l) {
		var d = 'removeEventListener';
		if (o[d] && !l) return o[d](t, f, false);
		if (o._evts && o._evts[t] && f._i) delete o._evts[t][f._i];
		};
	}
function cancelEvent(e, c) {
	e.returnValue = false;
	if (e.preventDefault) e.preventDefault();
	if (c) {
		e.cancelBubble = true;
		if (e.stopPropagation) e.stopPropagation();
		}
	};

// ** Global variables initialised upon load to let all browsers establish content objects. ** (DH, p.89)
var isCSS, isW3C, isIE6CSS;
function DHTML_init() {
	if (document.images) {
		isCSS = (document.body && document.body.style) ? true : false;
		isW3C = (isCSS && document.getElementById) ? true : false;
		isIE6CSS = (document.compatMode && document.compatMode.indexOf("CSS1") >= 0) ? true : false;
		}
	}

addEvent(window, 'load', DHTML_init);

// ** Convert element ID string or object reference into a valid element object reference ** (DH, p.90)
function getObject(e) {
	var o = ((typeof e == "string") && isW3C) ? document.getElementById(e) : e;
	return o;
	}

// ** Position an object at a specific pixel coordinate ** (DH, p.90)
function shiftObjectTo(e, x, y) {
	var o = getObject(e);
	if (o && isCSS) {
		var u = (typeof o.style.left == "string") ? "px" : 0 
		o.style.left = x + u;
		o.style.top = y + u;
		}
	}

// ** Move an object by x and/or y pixels ** (DH, p.91)
function shiftObjectBy(e, x, y) {
	var o = getObject(e);
	if (o && isCSS) {
		var u = (typeof o.style.left == "string") ? "px" : 0 
		o.style.left = getObjectX(o) + x + u;
		o.style.top = getObjectY(o) + x + u;
		}
	}

// ** Set the z-order of an object ** (DH, p.91)
function setObjectZ(e, z) {
	var o = getObject(e);
	if (o) {
		o.style.zIndex = z;
		}
	}

// ** Set the background color of an object ** (DH, p.91)
function setObjectBackground(e, c) {
	var o = getObject(e);
	if (o && isCSS) {
		o.style.backgroundColor = c;
		}
	}

// ** Set the visibility of an object to visible ** (DH, p.91)
function showObject(e) {
	var o = getObject(e);
	if (o) {
		o.style.visibility = "visible";
		}
	}

// ** Set the visibility of an object to hidden ** (DH, p.91)
function hideObject(e) {
	var o = getObject(e);
	if (o) {
		o.style.visibility = "hidden";
		}
	}

// ** Retrieve the x coordinate of a positionable object ** (DH, p.92)
function getObjectX(e)  {
	var o = getObject(e);
	var r = 0;
	if (document.defaultView) {
		var a = document.defaultView;
		var b = a.getComputedStyle(o, "");
		r = b.getPropertyValue("left");
		}
	else if (o.currentStyle) {
		r = o.currentStyle.left;
		}
	else if (o.style) {
		r = o.style.left;
		}
	return parseInt(r);
	}

// ** Retrieve the y coordinate of a positionable object ** (DH, p.92)
function getObjectY(e)  {
	var o = getObject(e);
	var r = 0;
	if (document.defaultView) {
		var a = document.defaultView;
		var b = a.getComputedStyle(o, "");
		r = b.getPropertyValue("top");
		}
	else if (o.currentStyle) {
		r = o.currentStyle.top;
		}
	else if (o.style) {
		r = o.style.top;
		}
	return parseInt(r);
	}

// ** Retrieve the rendered width of an object ** (DH, p.92)
function getObjectWidth(e)  {
	var o = getObject(e);
	var r = 0;
	if (o.offsetWidth) {
		r = o.offsetWidth;
		}
	else if (o.clip && o.clip.width) {
		r = o.clip.width;
		}
	else if (o.style && o.style.pixelWidth) {
		r = o.style.pixelWidth;
		}
	return parseInt(r);
	}

// ** Retrieve the rendered height of an object ** (DH, p.93)
function getObjectHeight(e)  {
	var o = getObject(e);
	var r = 0;
	if (o.offsetHeight) {
		r = o.offsetHeight;
		}
	else if (o.clip && o.clip.height) {
		r = o.clip.height;
		}
	else if (o.style && o.style.pixelHeight) {
		r = o.style.pixelHeight;
		}
	return parseInt(r);
	}

// ** Return the available content width space in browser window ** (DH, p.93)
function getInsideWindowWidth() {
	var r = 0;
	if (window.innerWidth) {
		r = window.innerWidth;
		}
	else if (isIE6CSS) {
		r = document.body.parentElement.clientWidth
		}
	else if (document.body && document.body.clientWidth) {
		r = document.body.clientWidth;
		}
	return parseInt(r);
	}

// ** Return the available content height space in browser window ** (DH, p.93)
function getInsideWindowHeight() {
	var r = 0;
	if (window.innerHeight) {
		r = window.innerHeight;
		}
	else if (isIE6CSS) {
		r = document.body.parentElement.clientHeight
		}
	else if (document.body && document.body.clientHeight) {
		r = document.body.clientHeight;
		}
	return parseInt(r);
	}

// ** Centre object on browser window ** (JDC, p.383)
function centerOnWindow(e) {
	var o = getObject(e);
	var sx = 0, sy = 0;
	if (document.body && typeof document.body.scrollTop != "undefined") {
		sx += document.body.scrollLeft;
		sy += document.body.scrollTop;
		if (document.body.parentNode && typeof document.body.parentNode.scrollTop != "undefined") {
			sx += document.body.parentNode.scrollLeft;
			sy += document.body.parentNode.scrollTop;
			}
		}
	else if (typeof window.pageXOffset != "undefined") {
		sx += window.pageXOffset;
		sy += window.pageYOffset;
		}
	var x = Math.round((getInsideWindowWidth()/2) - (getObjectWidth(o)/2)) + sx;
	var y = Math.round((getInsideWindowHeight()/2) - (getObjectHeight(o)/2)) + sy;
	shiftObjectTo(o, x, y);
	}

// ** Reading effective style sheet property values ** (JDC, p.333)
function getObjectStyle(e, i, c) {
	var o = getObject(e);
	var r = "";
	if (o.currentStyle) {
		r = o.currentStyle[i];
		}
	else if (window.getComputedStyle) {
		var a = window.getComputedStyle(o, "");
		r = a.getPropertyValue(c);
		}
	return r;
	}

// ** Set the width of an object **
function setObjectWidth(e, w) {
	var o = getObject(e);
	if (o && isCSS) {
		o.style.width = w + "px";
		}
	}

// ** Set the height of an object **
function setObjectHeight(e, h) {
	var o = getObject(e);
	if (o && isCSS) {
		o.style.height = h + "px";
		}
	}

// ** Return the parent of an object **
function getObjectParent(e) {
	var o = getObject(e);
	if (o) {
		var p = o.parentNode;
		}
	return p;
	}

// ** Get all the child nodes of an object **
function getObjectChildNodes(e) {
	var n = new Array();
	var a = getObject(e).childNodes;
	for (var i = 0; i < a.length; i++) {
		if (a[i].nodeType == 1) {
			n[n.length] = new Array(a[i], a[i].nodeName.toLowerCase(), a[i].id, a[i].className);
			if (a[i].childNodes.length > 0) {
				n = n.concat(getChildNodes(a[i]));
				}
			}
		}
	return n;
	}

function arrangeObjects(parentObject, maxObjectDisplay, maxRowDisplay, rowMarginBottom, maxObjectMargin, minObjectMargin, verticalAlignment, horizontalAlignment, objectFadeIn) {
	// ** define default values **
	if ((typeof maxObjectDisplay == "undefined") || (typeof maxObjectDisplay != "number")) { maxObjectDisplay = 0; }
	if ((typeof maxRowDisplay == "undefined") || (typeof maxRowDisplay != "number") || (maxRowDisplay <= 0)) { maxRowDisplay = 99; }
	if ((typeof rowMarginBottom == "undefined") || (typeof rowMarginBottom != "number")) { rowMarginBottom = 15; }
	if ((typeof maxObjectMargin == "undefined") || (typeof maxObjectMargin != "number")) { maxObjectMargin = 25; }
	if ((typeof minObjectMargin == "undefined") || (typeof minObjectMargin != "number")) { minObjectMargin = 0; }
	if ((typeof verticalAlignment == "undefined") || (typeof verticalAlignment != "string") || (verticalAlignment.search(/^(?:top|middle|bottom)$/i) == -1)) { verticalAlignment = "top"; }
	if ((typeof horizontalAlignment == "undefined") || (typeof horizontalAlignment != "string") || (horizontalAlignment.search(/^(?:left|centre|center|right)$/i) == -1)) { horizontalAlignment = "centre"; }
	var parentObjectWidth = getObjectWidth(parentObject);
	setObjectHeight(parentObject, 0);
	// ** get direct children of parent **
	var childObjects = new Array();
	var k = getObject(parentObject).childNodes;
	var j = 0;
	for (var i = 0; i < k.length; i++) {
		if (k[i].nodeType == 1) {
			hideObject(k[i]);
			var w = getObjectWidth(k[i]);
			if ((w + minObjectMargin * 2) < parentObjectWidth) {
				childObjects[j] = [k[i], w, getObjectHeight(k[i]), 0, 0];
				j++;
				}
			}
		}
	// ** determine maximum objects to display **
	if ((maxObjectDisplay <= 0) || (maxObjectDisplay > childObjects.length)) {
		maxObjectDisplay = childObjects.length;
		}
	var currentRowWidth = 0;
	var currentRowHeight = 0;
	var currentRowStartIndex = 0;
	var currentRowNumber = 1;
	var parentObjectHeight = 0;
	var i = 0;
	var endOfRow;
	while (i < maxObjectDisplay) {
		// ** Plaas items links langs mekaar **
		childObjects[i][3] = currentRowWidth;
		childObjects[i][4] = parentObjectHeight;
		// ** Voeg item by ry **
		currentRowWidth += childObjects[i][1];
		currentRowHeight = Math.max(currentRowHeight, childObjects[i][2]);
		// ** Is daar 'n volgende item? **
		if ((i < (maxObjectDisplay - 1))) {
			// ** Ja, daar is een ** Toets of dit kan inpas **
			if ((currentRowWidth + childObjects[i+1][1] + (minObjectMargin * (i - currentRowStartIndex + 1))) < parentObjectWidth) {
				// ** Ja, daar's plek **
				endOfRow = false;
				}
			else {
				// ** Nee, daar's nie nog plek nie **
				endOfRow = true;
				}
			}
		else {
			// Nee, daar's geen items meer nie **
			endOfRow = true;
			}
		// ** Vertoon ry? **
		if (endOfRow) {
			// ** Stel hoogte van ry **
			parentObjectHeight += currentRowHeight;
			setObjectHeight(parentObject, parentObjectHeight);
			// ** Bepaal spasie tussen elemente **
			var rowEmptySpace = parentObjectWidth - currentRowWidth;
			switch(horizontalAlignment.toLowerCase()) {
				case "left" :
					var marginObjectFirst = 0;
					var marginObjectLeft = minObjectMargin;
					break;
				case "centre" :
				case "center" :
					var marginObject = Math.floor(rowEmptySpace / (i - currentRowStartIndex));
					if (marginObject > maxObjectMargin) {
						var marginObjectFirst = Math.floor((rowEmptySpace - maxObjectMargin * (i - currentRowStartIndex)) / 2);
						var marginObjectLeft = maxObjectMargin;
						}
					else {
						var marginObjectFirst = 0;
						var marginObjectLeft = marginObject;
						}
					break;
				case "right" :
					var marginObjectFirst = rowEmptySpace;
					var marginObjectLeft = minObjectMargin;
					break;
				}
			// ** Vertoon elemente **
			for (var j = currentRowStartIndex; j <= i; j++) {
				childObjects[j][3] += marginObjectFirst + marginObjectLeft * (j - currentRowStartIndex);
				switch (verticalAlignment.toLowerCase()) {
					case "bottom" :
						childObjects[j][4] += currentRowHeight - childObjects[j][2];
						break;
					case "middle" :
						childObjects[j][4] += Math.floor((currentRowHeight - childObjects[j][2]) / 2);
						break;
					case "top" :
					default :
						break;
					}
				showObject(childObjects[j][0]);
				shiftObjectTo(childObjects[j][0], childObjects[j][3], childObjects[j][4]);
				}
			// ** Gaan ons aan of stop ons met hierdie ry? **
			if (currentRowNumber == maxRowDisplay) {
				break;
				}
			else if (i == (maxObjectDisplay - 1)) {
				break;
				}
			else {
				// ** Begin nuwe ry **
				currentRowStartIndex = ++i;
				currentRowWidth = 0;
				currentRowHeight = 0;
				currentRowNumber++;
				parentObjectHeight += rowMarginBottom;
				}
			}
		else {
			i++;
			}
		}
	}










