/*
 * @author  : Greg Wilton (Queensland Treasury)
 * @version :5.0 (2006-09-07)
 */
var Expandable = function (varName, header, content, button) {
	this.varName = varName;
	this.match = new this.Matcher(header, content);
	this.button = button;
	this.itemStore = new Array();
	this.cookie = new this.Cookie(varName);
};

Expandable.prototype.isSupported = function () {
	var ua = navigator.userAgent;
	var IE_OSX = ua.indexOf("MSIE 5.2") != -1 && ua.indexOf("Mac") != -1;
	return (document.getElementById && !IE_OSX) ? true : false;
};

Expandable.prototype.init = function (id, openRows, singeView) {
	if (this.isSupported()) {
		// initialize expandable system
		var section = document.getElementById(id);
		if (section != null) {
			var row = 0;
			var obj = section.firstChild;
			while (obj != null) {
				// find the header row
				if (this.match.isHeader(obj)) {
					var header = obj;
					var content = null;
					
					// find the content linked with the header row
					obj = obj.nextSibling;
					while (obj != null && !this.match.isHeader(obj)) {
						if (content == null && this.match.isContent(obj)) {
							content = obj;
						}
						obj = obj.nextSibling;
					}
					
					var button = this.formatItem(header, content, row);
					this.itemStore[row++] = new this.Item(
							header, button, content);
				
				} else {
					obj = obj.nextSibling;
				}
			}
		}
		
		// force only on item to be open at a time
		if (singeView) {
			if (openRows) {
				openRows = (openRows.length > 0) ? [openRows[0]] : [];
			}
			this.toggle = this.toggleAll;
		}
		
		// If user is returning use previously opened rows.
		if (this.cookie.values.length > 0) {
			openRows = this.cookie.values;
		}
		
		// open specified elements - if requested
		if (openRows) {
			for (var i = openRows.length - 1; i >= 0; i--) {
				var row = openRows[i];
				if (this.isExpandable(row)) {
					var obj = this.itemStore[row];
					this.open(obj.content, obj.button, row);
				}
			}
		}
	}
};

// extension point - overwrite if required
Expandable.prototype.formatItem = function (header, content, row) {
	// return button if one was created
	return null;
};

Expandable.prototype.toggle = function (row) {
	var items = this.itemStore;
	
	// If required objects are not present cancel the action
	if (!this.isExpandable(row)) { return; }
	
	// Process action
	var opening = items[row].content.style.display == "none";
	if (opening) {
		this.open(items[row].content, items[row].button, row);
	} else {
		this.closeAndScroll(row);
	}
};

Expandable.prototype.toggleAll = function (row) {
	var items = this.itemStore;
	
	// If required objects are not present close all open items
	if (!this.isExpandable(row)) {
		for (var i = items.length - 1; i >= 0; i--) {
			var button = items[i].button;
			var content = items[i].content;
			if (button && content) {
				var isOpen = content.style.display == "block";
				if (isOpen) {
					this.close(content, button, row);
				}
			}
		}
		return;
	}
	
	// Process action
	var opening = items[row].content.style.display == "none";
	if (opening) {
		var pos = this.getOffsetTop(items[row].header) - this.getScrollTop();
		var doScroll = false;
		for (var i = 0; i < items.length; i++) {
			var button = items[i].button;
			var content = items[i].content;
			if (content && button) {
				var isOpen = content.style.display == "block";
				if (isOpen && i < row) {
					var header = items[i].header;
					if (!doScroll && this.isAboveVisibleArea(header)) {
						doScroll = true;
					}
					this.close(content, button, i);
				} else if (i == row) {
					this.open(content, button, i);
					if (doScroll) {
						scrollTo(0, this.getOffsetTop(items[i].header) - pos);
					}
				} else if (isOpen) {
					this.close(content, button, i);
				}
			}
		}
	} else {
		this.closeAndScroll(row);
	}
};

Expandable.prototype.closeAndScroll = function (row) {
	var items = this.itemStore;
	var notVisible = this.isAboveVisibleArea(items[row].header);
	var header, pos;
	if (notVisible) {
		header = items[row + 1].header;
		pos = this.getOffsetTop(header) - this.getScrollTop();
	}
	this.close(items[row].content, items[row].button, row);
	if (notVisible) {
		scrollTo(0, this.getOffsetTop(header) - pos);
	}
}

Expandable.prototype.open = function (content, button, row) {
	content.style.display = "block";
	this.button.open(button, row);
	this.cookie.add(row);
}

Expandable.prototype.close = function (content, button, row) {
	content.style.display = "none";
	this.button.close(button, row);
	this.cookie.remove(row);
};

Expandable.prototype.getOffsetTop = function (node) {
	var y = 0;
	while (node && node.tagName != "BODY") {
		y += node.offsetTop;
		node = node.offsetParent;
	}
	return y;
};

Expandable.prototype.getScrollTop = function () {
	if (window.pageYOffset) {
		return window.pageYOffset;
	} else if (document.documentElement && document.documentElement.scrollTop) {
		return document.documentElement.scrollTop;
	} else {
		return document.body.scrollTop;
	}
};

Expandable.prototype.isAboveVisibleArea = function (header) {
	return this.getOffsetTop(header) < this.getScrollTop();
};

Expandable.prototype.isExpandable = function (row) {
	var items = this.itemStore;
	return items[row] && items[row].content && items[row].button;
}

/* *** */

Expandable.prototype.Matcher = function (header, content) {
	this.header = header.toUpperCase();
	this.content = content.toUpperCase();
};

Expandable.prototype.Matcher.prototype.isHeader = function (obj) {
	if (typeof(this.header) != "string") {
		for (var i = this.header.length - 1; i >= 0 ; i--) {
			if (obj.tagName == this.header[i]) {
				return true;
			}
		}
		return false;
	} else {
		return obj.tagName == this.header;
	}
};

Expandable.prototype.Matcher.prototype.isContent = function (obj) {
	return obj.tagName == this.content;
};

/* *** */

Expandable.prototype.Item = function (header, button, content) {
	this.header = header;
	this.button = button;
	this.content = content;
};

/* *** */

Expandable.prototype.Cookie = function (name) {
	this.name = name;
	this.values = this.get();
};

Expandable.prototype.Cookie.prototype.add = function (row) {
	var alreadyExists = false;
	
	for (var i = 0; i < this.values.length; i++) {
		if (this.values[i] == row) {
			alreadyExists = true;
			break;
		}
	}
	
	if (!alreadyExists) {
		this.values.push(row);
		this.save();
	}
};

Expandable.prototype.Cookie.prototype.get = function () {
	var cookie = document.cookie;
	var prefix = this.name + "=";
	
	// find the start of the value
	var start = cookie.indexOf("; " + prefix);
	if (start == -1) {
		start = cookie.indexOf(prefix);
		if (start != 0) {
			this.values = [];
		}
	} else {
		start += 2;
	}
	
	// find the end of the value
	var end = cookie.indexOf(";", start);
	if (end == -1) {
		end = cookie.length;
	}
	
	// Extract and format the values
	var cookieValue = unescape(cookie.substring(start + prefix.length, end));
	var cookieItems = cookieValue.split(';');
	if (document.location.toString() != cookieItems[0]) {
		return [];
	}
	
	return cookieItems[1].split(',');
};

Expandable.prototype.Cookie.prototype.remove = function (row) {
	for (var i = 0; i < this.values.length; i++) {
		if (this.values[i] == row) {
			this.values.splice(i, 1);
			this.save();
			break;
		}
	}
};

Expandable.prototype.Cookie.prototype.save = function () {
	var value = document.location.toString() + ";" + this.values.join(',');
	document.cookie = this.name + "=" + escape(value) + ";path=/;";
}

/* *** */

Array.prototype.toUpperCase = function () {
	var array = new Array();
	for (var i = this.length - 1; i >= 0; i--) {
		array[i] = this[i].toUpperCase();
	}
	return array;
};

if(!Array.prototype.push) {
	function array_push() {
		for (var i = 0; i < arguments.length; i++) {
			this[this.length] = arguments[i];
		}
		return this.length;
	};
	Array.prototype.push = array_push;
}

if(!Array.prototype.splice) {
	function array_splice(index, count) {
		if (arguments.length == 0) {
			return index;
		}
		if (typeof(index) != "number") {
			index = 0;
		}
		if (index < 0) {
			index = Math.max(0, this.length + index);
		}
		if (index > this.length) {
			if(arguments.length > 2) {
				index = this.length;
			} else {
				return [];
			}
		}
		if (arguments.length < 2) {
			count = this.length - index;
		}
		count = (typeof(count) == "number") ? Math.max(0, count) : 0;
		var removeArray = this.slice(index, index + count);
		var endArray = this.slice(index + count);
		this.length = index;
		for (var i = 2; i < arguments.length; i++) {
			this[this.length] = arguments[i];
		}
		for (var i = 0; i < endArray.length; i++) {
			this[this.length] = endArray[i];
		}
		return removeArray;
	};
	Array.prototype.splice = array_splice;
}

