// Utilities hjælpe klasse
// 
// Copyright 2006-2008 René Lønstrup @ RLdesign.dk
// 
// May not be used commercially without permission from the author.
//
// Version: 1.1.1.6
//
//
// CHANGELOG:
//
// 25/04/2008
//     1.1.1.5 -> 1.1.1.6
//           Extended defineObject to work in a multiple-frame environment
//           Extended makeElement to work in a multiple-frame environment
// 20/04/2008
//     1.1.1.4 -> 1.1.1.5
//           Fixed bug in new function SetOffsetPosition
// 15/04/2008
//     1.1.1.3 -> 1.1.1.4
//           Added new function ToggleDisplay
// 13/04/2008
//     1.1.1.2 -> 1.1.1.3
//           Change name of function SetOffsetPosition to SetPositionToOffset
//           Added new function SetOffsetPosition
//           Tweaked function CenterObject a little bit
// 07/04/2008
//     1.1.1.1 -> 1.1.1.2
//           Added function GetCursorPosition
// 07/04/2008
//     1.1.1.0 -> 1.1.1.1
//           Added function InsertAfter
//           Added function PrependChild
// 23/03/2008
//     1.1.0.9 -> 1.1.1.0
//           Added function GetHighestZIndex
//           Added function CenterObject
//           Added function GetCssValue
//           Added function SetOffsetPosition
// 22/03/2008
//     1.1.0.8 -> 1.1.0.9
//           Fixed another bug in GetOpacity
// 21/03/2008
//     1.1.0.7 -> 1.1.0.8
//           Fixed bug in GetOpacity
//           Fixed bug in GetMargins and GetPaddings which meant that they didn't parse the values correctly, thus
//           wrongly returning NaN-values
//           Added functions GetWindowSize and GetPageSize which should be used in place of the seperate functions for
//           height and width.
//           Added function SetDisplay which set the display property of an object
//           Added function GetOpacity to join SetOpacity
// 14/03/2008
//     1.1.0.6 -> 1.1.0.7
//           Fixed a bug in GetOffsetPosition making it useless i IE6 when run on an advanced page-layout
// 11/03/2008
//     1.1.0.5 -> 1.1.0.6
//           Fixed a couple of bugs in Serialize, and added an extra arguments-switch to force it out of
//           running the supplied object through DefineObject - so the function also works with strings with commas
// 10/03/2008
//     1.1.0.4 -> 1.1.0.5
//           Added error-handling to DefineObject to avoid error when passing an ID of a non-existing object
// 09/03/2008
//     1.1.0.3 -> 1.1.0.4
//           Added function GetOffsetPosition to get top left position of element
//           Changed functions GetPaddings and GetMargins to correctly return an Object instead of an Array
// 06/03/2008
//     1.1.0.2 -> 1.1.0.3
//           Fixed bug caused by a misspelled variable i DefineEventRelatedTarget
// 02/03/2008
//     1.1.0.1 -> 1.1.0.2
//           Removed dependancy of RLdesign.js file.
// 24/02/2008
//     1.1.0.0 -> 1.1.0.1
//           Added 'get count' switch to Serialize-function, which returns the number of serialized items
// 23/02/2008
//     1.0.0.0 -> 1.1.0.0
//           Added function Serialize which serializes data and from to an input field


if (!RLdesign) {
	var RLdesign = function() { };
}
RLdesign.Utils = function() {
	return {
	
		// returns a crossbrowser event object
		DefineEvent: function(e) {
			return e || window.event;
		},
		
		// returns the target for the event in question, typically a click-event
		// ie. in the case of a click-event, the target is the element being clicked on
		DefineEventTarget: function(e) {
			var ev = RLdesign.Utils.DefineEvent(e);
			var element = ev.srcElement || ev.target;
			if (element.nodeType == 3) element = element.parentNode; // defeat Safari bug
			return element;
		},
		
		// returns the related target from the event
		// used in conjunction with mouseover / -out events, and returns the element from which the mouse came / goes
		// ie. in the case of a mouseover, returns the element from which the mouse came, and vice versa for mouseout
		DefineEventRelatedTarget: function(e) {
			var t = e.relatedTarget;
			if (!t && (e.type == "mouseover" || e.type == "mouseout")) {
				t = (e.type == "mouseout") ? e.toElement : e.fromElement;
			}
			return t;
		},
		
		// tries to return an object from an arbitrary argument that can be a string or an object
		// if successfully finding an object, either from a search for the object-id or the object itself, 
		// returns the object. If unsuccessful, returns null
		DefineObject: function(el, d) {
//			if (typeof(el) === "string" && (el.indexOf("(") != -1 || el.indexOf("[") != -1)) alert((el.indexOf("(") != -1));
			var doc = (d) ? d : document;
			var elem = null;
			// if el is an object
			if (typeof(el) == "object") {
				try {
					elem = el;
				}
				catch (ex) {
					elem = null;
				}
			}
			// if el is the id of an html-object
			else if (doc.getElementById(el)) {
				try {
					elem = doc.getElementById(el);
				}
				catch (ex) {
					elem = null;
				}
			}
			// if el is a string representation of an document.getElementById - or similar statement
			else if (typeof(el) == "string" && (el.indexOf("(") != -1 || el.indexOf("[") != -1)) {
				try {
					eval("elem = " + el);
				}
				catch (ex) {
					elem = null;
				}
			}
			// last resort
			else if (typeof(el) == "string") {
				try {
					eval("elem = " + el);
				}
				catch (ex) {
					elem = null;
				}
			}
			return elem;
		},
		
		// returns a crossbrowser return code designed to prevent further events i mozilla browser, if need be
		DefineReturnCode: function (e,r) {
			var ev = RLdesign.Utils.DefineEvent(e);
			if (r == false) {
				if (ev.stopPropagation) ev.stopPropagation();
				else if (ev.cancelBubble) ev.cancelBubble = true;
				if (ev.preventDefault) ev.preventDefault();
				else if (ev.returnValue) ev.returnValue = false;
			}
			else {
				if(typeof(ev.returnValue) == "string") ev.returnValue = r;
			}
			return r;
		},

		// returns the keycode for the key that was pressed during the event		
		DefineEventKeyCode: function(e) {
			var ev = RLdesign.Utils.DefineEvent(e);
			var keycode = 0;
			if (ev.which) keycode = ev.which; // Netscape4
			else if (ev.keyCode) keycode = ev.keyCode; // IE
			else if (ev.charCode) keycode = ev.charCode; // Gecko
			return keycode;
		},

		// returns a boolean representation of whether the shift key was pressed during the event		
		DefineEventShiftKey: function(e) {
			var ev = RLdesign.Utils.DefineEvent(e);
			var bShift = false;
			if (e.shiftKey) { bShift = e.shiftKey } // IE etc
			else if (e.modifiers) { // Netscape 4
				if (e.modifiers & 4) { // bitwise AND to see if shift is pressed
					bShift = true;
				}
			}
			return bShift;
		},
		
		// evaluates whether the given argument object is an array, returning a boolean
		IsArray: function(a) {
			return (a && a.length && typeof(a) != "string" && !a.tagName && !a.alert && typeof(a[0]) != "undefined");
		},

		// evaluates whether the given argument object is an object, returning a boolean
		IsObject: function(o) {
			return (o && o.length == undefined && typeof(o) == "object" && !o.alert);
		},
		
		// clears the specified global interval variable (specified as a string), if exists
		ClearInterval: function(sInterval) {
			var bIntervalExist = !!window[sInterval];
			if (bIntervalExist) window.clearInterval(window[sInterval]);
		},
		
		// clears the specified global timeout variable (specified as a string), if exists
		ClearTimeout: function(sTimeout) {
			var bTimeoutExist = !!window[sTimeout];
			if (bTimeoutExist) window.clearTimeout(window[sTimeout]);
		},
		
		// replaces a given set of characters ending at the cursors position in a textfield
		ReplaceBeforeCursor: function(obj, sValue, iLength, bSelectRange) {
			var elem = RLdesign.Utils.DefineObject(obj);
			if (elem == null || (elem.tagName.toLowerCase() != "textarea" && (elem.tagName.toLowerCase() != "input") || elem.type.toLowerCase() != "text")) return;
			if (iLength == null) iLength = sValue.length;
			if (document.selection) {
				elem.focus();
				var sel = document.selection.createRange();
				sel.moveStart("character", iLength*-1);
				sel.moveEnd("character", 0);
				sel.select();
				sel.text = sValue;
				if (bSelectRange) {
					sel = document.selection.createRange();
					sel.moveStart("character", sValue.length*-1);
					sel.moveEnd("character", 0);
				}
				sel.select();
			}
			else if (elem.selectionStart || elem.selectionStart == "0") {
				var startPos = obj.selectionStart - iLength;
				if (startPos < 0) startPos = 0;
				var endPos = elem.selectionEnd;
				elem.value = elem.value.substring(0, startPos) + sValue + elem.value.substring(endPos, elem.value.length);
				elem.focus();
			}
		},
		
		// replaces a given set of characters starting at the cursors position in a textfield
		ReplaceAfterCursor: function(obj, sValue, iLength, bSelectRange) {
			var elem = RLdesign.Utils.DefineObject(obj);
			if (elem == null || (elem.tagName.toLowerCase() != "textarea" && (elem.tagName.toLowerCase() != "input") || elem.type.toLowerCase() != "text")) return;
			if (iLength == null) iLength = sValue.length;
			if (document.selection) {
				elem.focus();
				var sel = document.selection.createRange();
				if (sel.text.length != iLength) {
					sel.moveStart("character", 0);
					sel.moveEnd("character", iLength);
				}
				sel.select();
				sel.text = sValue;
				if (bSelectRange) {
					sel = document.selection.createRange();
					sel.moveStart("character", 0);
					sel.moveEnd("character", sValue.length);
				}
				sel.select();
			}
			else if (elem.selectionStart || elem.selectionStart == "0") {
				var startPos = elem.selectionStart;
				var endPos = elem.selectionEnd;
				elem.value = elem.value.substring(0, startPos) + sValue + elem.value.substring(endPos, elem.value.length);
				if (bSelectRange) {
					elem.setSelectionRange(startPos, startPos + iLength);
				}
				elem.focus();
			}
		},
		
		// inserts a given textstring at the cursors position in a textfield
		InsertAtCursor: function(obj, sValue, bSelectRange) {
			var elem = RLdesign.Utils.DefineObject(obj);
			if (elem == null || (elem.tagName.toLowerCase() != "textarea" && (elem.tagName.toLowerCase() != "input") || elem.type.toLowerCase() != "text")) return;
			if (document.selection) {
				elem.focus();
				sel = document.selection.createRange();
				sel.text = sValue;
				if (bSelectRange) {
					sel = document.selection.createRange();
					sel.moveStart("character", sValue.length*-1);
					sel.moveEnd("character", 0);
					sel.select();
				}
			}
			else if (elem.selectionStart || elem.selectionStart == "0") {
				var startPos = elem.selectionStart;
				var endPos = elem.selectionEnd;
				elem.value = elem.value.substring(0, startPos) + sValue + elem.value.substring(endPos, elem.value.length);
				if (bSelectRange) {
					elem.setSelectionRange(startPos, startPos+1);
				}
				elem.focus();
			}
			else {
				elem.value += sValue;
				elem.focus();
			}
		},
		
		// sets the cursors position relative to its current position in a textfield
		SetRelativeCursorPosition: function(obj, iLength) {
			var elem = RLdesign.Utils.DefineObject(obj);
			if (elem == null || (elem.tagName.toLowerCase() != "textarea" && (elem.tagName.toLowerCase() != "input") || elem.type.toLowerCase() != "text")) return;
			if (document.selection) {
				elem.focus();
				var sel = document.selection.createRange();
				sel.moveStart("character", iLength);
				sel.moveEnd("character", iLength);
				sel.select();
			}
			else if (elem.selectionStart || elem.selectionStart == "0") {
				var startPos = elem.selectionStart + iLength;
				elem.setSelectionRange(startPos, startPos);
				elem.focus();
			}
		},
		
		// selects a range of characters in a textfield
		SelectRange: function(obj, iStart, iLength) {
			var elem = RLdesign.Utils.DefineObject(obj);
			if (elem == null || (elem.tagName.toLowerCase() != "textarea" && (elem.tagName.toLowerCase() != "input") || elem.type.toLowerCase() != "text")) return;
			if (elem.createTextRange) {
				var oRange = elem.createTextRange();
				oRange.moveStart("character", iStart);
				oRange.moveEnd("character", iLength - elem.value.length);
				oRange.select();
			}
			else if (elem.selectionStart || elem.selectionStart == "0") {
				elem.setSelectionRange(iStart, iLength);
			}
			elem.focus();
		},

		// creates a given html element in memory and returns the element
		MakeElement: function(tag, attrs, text, d) {
			var doc = (d) ? d : document;
			var e = doc.createElement(tag);
			if (attrs) {
				for (var key in attrs) {
					if (typeof(attrs[key]) == "function") continue; // defeat bug caused by adding custom functions to arrays
					if (key == "class") { e.className = attrs[key]; }
					else if (key == "id") { e.id = attrs[key]; }
					else { e.setAttribute(key, attrs[key]); }
				}
			}
			if (text) e.appendChild(doc.createTextNode(text));
			return e;
		},
		
		InsertAfter: function(parent, node, referenceNode) {
			parent.insertBefore(node, referenceNode.nextSibling);
		},

		PrependChild: function(parent, node) {
			parent.insertBefore(node, parent.firstChild);
		},

		SetDisplay: function(obj, sParam) {
			obj = RLdesign.Utils.DefineObject(obj);
			obj.style.display = (sParam) ? sParam : "";
		},
		
		// sets opacity in a cross-browser sort-of way (doesn't work in pre-9 operas)
		SetOpacity: function(obj, iOpacity, bRelative, iDirection) {
			iDirection = (iDirection && iDirection < 0) ? -1 : 1;
			oElem = RLdesign.Utils.DefineObject(obj);
			if (oElem == null) return;
			if (bRelative) {
				iOpacity = iOpacity * iDirection;
/*  NOT WORKING! - Figure out opacity when first time (should possibly be 100% but seen as "" (empty string)  */
//						if (oElem.filter) oElem.filter.item("DXImageTransform.Microsoft.Alpha").opacity += iOpacity;
//						oElem.style.KHTMLOpacity += (iOpacity / 100); // Safari<1.2, Konqueror
//						oElem.style.MozOpacity += (iOpacity / 100); // Older Mozilla and Firefox
//						oElem.style.opacity += (iOpacity / 100); // Safari 1.2, newer Firefox and Mozilla, CSS3
				oElem.style.opacity = oElem.style.opacity*1 + (iOpacity / 100); // Safari 1.2, newer Firefox and Mozilla, CSS3
			}
			else {
				iOpacity = (iOpacity == 100) ? 99.999 : iOpacity;
				oElem.style.filter = "alpha(opacity:" + iOpacity + ")"; // IE/Win
				oElem.style.KHTMLOpacity = iOpacity / 100; // Safari<1.2, Konqueror
				oElem.style.MozOpacity = iOpacity / 100; // Older Mozilla and Firefox
				oElem.style.opacity = iOpacity / 100; // Safari 1.2, newer Firefox and Mozilla, CSS3
			}
		},
		
		GetOpacity: function(obj) {
			var opacity = (parseInt(obj.style.width) == obj.offsetWidth) ? 100 : 0;
			if (obj.style.opacity) {opacity = Math.round(obj.style.opacity * 100);}
			else if (obj.style.MozOpacity) {opacity = Math.round(obj.style.MozOpacity * 100);}
			else if (obj.style.KHTMLOpacity) {opacity = Math.round(obj.style.KHTMLOpacity * 100);}
			else if (obj.style.filter) {
				var filter = obj.style.filter;
//				var pattern = /opacity\b[^=]*=(.*?)\)/;
				var pattern = /\(opacity:(.*?)\)/;
				oRegex = filter.match(pattern);
				if (typeof(oRegex) == "object") {
					var match = oRegex[1];
					opacity = (match != null) ? parseInt(match) : opacity;
				}
			}
			return opacity;
		},
		
		// converts first character of textstring to uppercase while lowercasing the rest of the string
		UcFirst: function(sText) {
			var sLower = sText.toLowerCase();
			sFirst = sLower.substring(0,1);
			sRest = sLower.substring(1);
			return sFirst.toUpperCase() + sRest;
		},
		
		// returns a boolean representation of whether the given argument is numeric
		IsNumeric: function(sInput) {
			var sValidChars = "0123456789,.-";
			sInput = sInput.toString();
			if (sInput.length == 0) return false;
			var bResult = true;
			for (var i = 0; i < sInput.length; i++) {
				cChar = sInput.charAt(i);
				if (sValidChars.indexOf(cChar) == -1) {
					bResult = false;
					break;
				}
			}
			return bResult;
		},
		
		// rounds a number off to a default of two decimal places.
		// The amount decimals can be customized by providing a second (optional) argument in the form of an int
		RoundNumber: function(fNumber) {
			var rlength = (arguments.length == 2) ? parseInt(arguments[1]) : 2; // The number of decimal places to round to
			var returnNumber = parseFloat(fNumber);
			if (returnNumber.toFixed) { // if browser supports js 1.5 method of rounding
				returnNumber = returnNumber.toFixed(rlength);
			}
			else { // if legacy browser
				if (returnNumber > 8191 && returnNumber < 10485) { // workaround for javascript bug
					returnNumber = returnNumber - 5000;
					returnNumber = Math.round(returnNumber * Math.pow(10,rlength)) / Math.pow(10,rlength);
					returnNumber = returnNumber + 5000;
				}
				else {
					returnNumber = Math.round(returnNumber * Math.pow(10,rlength)) / Math.pow(10,rlength);
				}
			}
			return returnNumber;
		},
	
		GetCursorPosition: function(e) {
			var ev = RLdesign.Utils.DefineEvent(e);
			var pos = new Object();
				pos["top"] = 0;
				pos["left"] = 0;
			if (ev.pageX || ev.pageY) 	{
				pos["left"] = ev.pageX;
				pos["top"] = ev.pageY;
			}
			else if (ev.clientX || ev.clientY) 	{
				pos["left"] = ev.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
				pos["top"] = ev.clientY + document.body.scrollTop + document.documentElement.scrollTop;
			}
			return pos;
		},
	
		// returns the height and width of the current browser window
		GetWindowSize: function() {
			var size = new Object();
				size["width"] = null;
				size["height"] = null;
			var y, x = null;
			if (self.innerHeight && self.innerWidth) { // all except Explorer
				y = self.innerHeight;
				x = self.innerWidth;
			}
			else if (document.documentElement && document.documentElement.clientHeight && document.documentElement.clientWidth) { // Explorer 6 Strict Mode
				y = document.documentElement.clientHeight;
				x = document.documentElement.clientWidth;
			}
			else if (document.body) { // other Explorers
				y = document.body.clientHeight;
				x = document.body.clientWidth;
			}
			size["height"] = parseInt(y);
			size["width"] = parseInt(x);
			return size;
		}, 
		
		// returns the height of the current browser window
		GetWindowHeight: function() {
			var y = null;
			if (self.innerHeight) { // all except Explorer
				y = self.innerHeight;
			}
			else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
				y = document.documentElement.clientHeight;
			}
			else if (document.body) { // other Explorers
				y = document.body.clientHeight;
			}
			return parseInt(y);
		}, 

		// returns the width of the current browser window
		GetWindowWidth: function() {
			var x = null;
			if (self.innerWidth) { // all except Explorer
				x = self.innerWidth;
			}
			else if (document.documentElement && document.documentElement.clientWidth) { // Explorer 6 Strict Mode
				x = document.documentElement.clientWidth;
			}
			else if (document.body) { // other Explorers
				x = document.body.clientWidth;
			}
			return parseInt(x);
		},
		
		// returns the width and height of the current page (or more precisely, the width/height of the body element of the page)
		GetPageSize: function() {
			var size = new Object();
				size["width"] = null;
				size["height"] = null;
			var scrollWidth = parseInt(document.body.scrollWidth);
			var offsetWidth = parseInt(document.body.offsetWidth);
			var scrollHeight = parseInt(document.body.scrollHeight);
			var offsetHeight = parseInt(document.body.offsetHeight);
			size["width"] = (scrollWidth > offsetWidth) ? scrollWidth : offsetWidth;
			size["height"] = (scrollHeight > offsetHeight) ? scrollHeight : offsetHeight;
			return size;
		}, 

		// returns the height of the current page (or more precisely, the height of the body element of the page)
		GetPageHeight: function() {
			var y = null;
			var scrollHeight = parseInt(document.body.scrollHeight);
			var offsetHeight = parseInt(document.body.offsetHeight);
			if (scrollHeight > offsetHeight) { // all but Explorer Mac
				y = scrollHeight;
			}
			else { // Explorer Mac - would also work in Explorer 6 Strict, Mozilla and Safari
				y = offsetHeight;
			}
			return y;
		}, 

		// returns the width of the current page (or more precisely, the width of the body element of the page)
		GetPageWidth: function() {
			var x = null;
			var scrollWidth = parseInt(document.body.scrollWidth);
			var offsetWidth = parseInt(document.body.offsetWidth);
			if (scrollWidth > offsetWidth) { // all but Explorer Mac
				x = scrollWidth;
			}
			else { // Explorer Mac - would also work in Explorer 6 Strict, Mozilla and Safari
				x = offsetWidth;
			}
			return x;
		}, 

		// returns the scrolling offset on both the horizontal and the vertical axis
		GetScrollingOffset: function() {
			var offset = new Object();
				offset["vertical"] = parseInt(RLdesign.Utils.GetVerticalScrollingOffset());
				offset["horizontal"] = parseInt(RLdesign.Utils.GetHorizontalScrollingOffset());
			return offset;
		},

		// returns the scrolling offset on the vertical axis, measured from the top of the page
		GetVerticalScrollingOffset: function() {
			var y = null;
			if (self.pageYOffset) { // all except Explorer
				y = self.pageYOffset;
			}
			else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict
				y = document.documentElement.scrollTop;
			}
			else if (document.body) { // all other Explorers
				y = document.body.scrollTop;
			}
			return parseInt(y);
		},
		
		// returns the scrolling offset on the horizontal axis, measured from the left edge of the page
		GetHorizontalScrollingOffset: function() {
			var x = null;
			if (self.pageXOffset) { // all except Explorer
				x = self.pageXOffset;
			}
			else if (document.documentElement && document.documentElement.scrollLeft) { // Explorer 6 Strict
				x = document.documentElement.scrollLeft;
			}
			else if (document.body) { // all other Explorers
				x = document.body.scrollLeft;
			}
			return parseInt(x);
		}, 
		
		// gets top left position of object
		GetOffsetPosition: function(obj) {
			var oNode = RLdesign.Utils.DefineObject(obj);
			var iLeft = 0;
			var aReturn = new Object();
				aReturn["top"] = 0;
				aReturn["left"] = 0;
			if (oNode.offsetParent) {
				do {
					aReturn["left"] += parseInt(oNode.offsetLeft);
					aReturn["top"] += parseInt(oNode.offsetTop);
				} while (oNode = oNode.offsetParent);
			}
			else if (oNode.getBoundingClientRect) { // IE only method of finding elements position / dimension
				aReturn["top"] = oNode.getBoundingClientRect().top - 2; // minus two to counteract IE upper-left corner anomaly
				aReturn["left"] = oNode.getBoundingClientRect().left - 2; // minus two to counteract IE upper-left corner anomaly
			}
			else {
				while (oNode.tagName.toLowerCase() != "body") {
					aReturn["left"] += parseInt(oNode.offsetLeft);
					aReturn["top"] += parseInt(oNode.offsetTop);
					oNode = oNode.offsetParent;
				}
			}
			return aReturn;
		},
		
		// centers an object relative to the browser-window
		CenterObject: function (obj, horizontal, vertical) {
			var h = (horizontal === null) ? false : horizontal;
			var v = (vertical === null) ? false : vertical;
			var o = RLdesign.Utils.DefineObject(obj);
			if (!o) return;

			var width = parseInt(o.offsetWidth);
			var height = parseInt(o.offsetHeight);
			var windowSize = RLdesign.Utils.GetWindowSize();
			if (h) o.style.left = Math.floor((windowSize["width"] - width) / 2) + "px";
			if (v) o.style.top = Math.floor((windowSize["height"] - height) / 2) + "px";
		},

		// positions an object relative to the browser-window
		//
		// Usage:
		//     Centering the object horizontally and vertically:
		//     [Utils].SetOffsetPosition(myObject, "center", "center");
		//     Centering the object horizontally and fixing its position to 20 pixel from the top:
		//     [Utils].SetOffsetPosition(myObject, "center", 20);
		SetOffsetPosition: function (obj, horizontal, vertical) {
			var h = (horizontal === null || (isNaN(horizontal) && horizontal != "center")) ? 0 : horizontal;
			var v = (vertical === null || (isNaN(vertical) && vertical != "center")) ? 0 : vertical;
			var o = RLdesign.Utils.DefineObject(obj);
			if (!o) return;

			var position = new Object();
				position["left"] = parseInt(RLdesign.Utils.GetCssValue(o, "left"));
				position["top"] = parseInt(RLdesign.Utils.GetCssValue(o, "top"));
			var scroll = RLdesign.Utils.GetScrollingOffset();
			
			if (h === "center") RLdesign.Utils.CenterObject(o, true, false);
			else o.style.left = scroll["horizontal"] + h + "px";
			if (v === "center") RLdesign.Utils.CenterObject(o, false, true);
			else o.style.top = scroll["vertical"] + v + "px";
		},
		
		SetPositionToOffset: function (obj, horizontal, vertical) {
			var h = (horizontal === null) ? true : horizontal;
			var v = (vertical === null) ? true : vertical;
			var o = RLdesign.Utils.DefineObject(obj);
			if (!o) return;

			var position = new Object();
				position["left"] = parseInt(RLdesign.Utils.GetCssValue(o, "left"));
				position["top"] = parseInt(RLdesign.Utils.GetCssValue(o, "top"));
			var scroll = RLdesign.Utils.GetScrollingOffset();
			if (h) o.style.left = scroll["horizontal"] + position["left"] + "px";
			if (v) o.style.top = scroll["vertical"] + position["top"] + "px";
		},
		
		// returns an object of the top, bottom, left and right margins of the given object
		GetMargins: function(obj) {
			var elem = RLdesign.Utils.DefineObject(obj);
			var aReturn = new Object();
				aReturn["top"] = 0;
				aReturn["bottom"] = 0;
				aReturn["left"] = 0;
				aReturn["right"] = 0;
			if (elem == null) return aReturn; // returns default values if no correct object was specified
			var cStyle = null;
			if (elem.currentStyle) {
				cStyle = elem.currentStyle;
			}
			else if (document.defaultView && document.defaultView.getComputedStyle) {
				cStyle = document.defaultView.getComputedStyle(elem, "");
			}
			if (cStyle) {
				aReturn["top"] = parseInt(cStyle.marginTop);
				aReturn["bottom"] = parseInt(cStyle.marginBottom);
				aReturn["left"] = parseInt(cStyle.marginLeft);
				aReturn["right"] = parseInt(cStyle.marginRight);
			}
			else {
				aReturn["top"] = parseInt(elem.style.marginTop);
				aReturn["bottom"] = parseInt(elem.style.marginBottom);
				aReturn["left"] = parseInt(elem.style.marginLeft);
				aReturn["right"] = parseInt(elem.style.marginRight);
			}
			return aReturn;
		},
		
		// returns an object of the top, bottom, left and right paddings of the given object
		GetPaddings: function(obj) {
			var elem = RLdesign.Utils.DefineObject(obj);
			var aReturn = new Object();
				aReturn["top"] = 0;
				aReturn["bottom"] = 0;
				aReturn["left"] = 0;
				aReturn["right"] = 0;
			if (elem == null) return aReturn;
			var cStyle = null;
			if (elem.currentStyle) {
				cStyle = elem.currentStyle;
			}
			else if (document.defaultView && document.defaultView.getComputedStyle) {
				cStyle = document.defaultView.getComputedStyle(elem, "");
			}
			if (cStyle) {
				aReturn["top"] = parseInt(cStyle.paddingTop);
				aReturn["bottom"] = parseInt(cStyle.paddingBottom);
				aReturn["left"] = parseInt(cStyle.paddingLeft);
				aReturn["right"] = parseInt(cStyle.paddingRight);
			}
			else {
				aReturn["top"] = parseInt(elem.style.paddingTop);
				aReturn["bottom"] = parseInt(elem.style.paddingBottom);
				aReturn["left"] = parseInt(elem.style.paddingLeft);
				aReturn["right"] = parseInt(elem.style.paddingRight);
			}
			return aReturn;
		},
		
		// returns the z-index value of the given object
		GetZIndex: function(obj) {
			var elem = RLdesign.Utils.DefineObject(obj);
			if (elem == null) return;
			var cStyle = null;
			if (elem.currentStyle) {
				cStyle = elem.currentStyle;
			}
			else if (document.defaultView && document.defaultView.getComputedStyle) {
				cStyle = document.defaultView.getComputedStyle(elem, "");
			}
			var sNum;
			if (cStyle) {
				sNum = Number(cStyle.zIndex);
			}
			else {
				sNum = Number(elem.style.zIndex);
			}
			return sNum;
		},
	
		GetHighestZIndex: function(oRoot, sTag) {
			if (!document.getElementsByTagName) return 0;
			var root =(!oRoot) ? document : oRoot;
			var tag = (!sTag) ? "*" : sTag;
			var allElems = root.getElementsByTagName(tag);
			var maxZIndex = 0;
			for (var i = 0; i < allElems.length; i++) {
				var elem = allElems[i];
				var cStyle = null;
				if (elem.currentStyle) {cStyle = elem.currentStyle;}
				else if (document.defaultView && document.defaultView.getComputedStyle) {
					cStyle = document.defaultView.getComputedStyle(elem, "");
				}
				var sNum;
				if (cStyle) {
					sNum = Number(cStyle.zIndex);
				}
				else {
					sNum = Number(elem.style.zIndex);
				}
				if (!isNaN(sNum)) {
					maxZIndex = Math.max(maxZIndex, sNum);
				}
			}
			return maxZIndex;
		},
		
		GetCssValue: function(obj, sCss) {
			var elem = RLdesign.Utils.DefineObject(obj);
			if (elem == null) return;
			var cStyle = null;
			if (elem.currentStyle) {
				cStyle = elem.currentStyle;
			}
			else if (document.defaultView && document.defaultView.getComputedStyle) {
				cStyle = document.defaultView.getComputedStyle(elem, "");
			}
			var sValue;
			if (cStyle) {
				sValue = cStyle[sCss];
			}
			else {
				sValue = elem.style[sCss];
			}
			return sValue;
		},
		
		ToggleDisplay: function(obj, sProp) {
			var elem = RLdesign.Utils.DefineObject(obj);
			if (elem == null) return;
			
			if (sProp != undefined && sProp != null) {
				elem.style.display = sProp;
			}
			else {
				var sProp = RLdesign.Utils.GetCssValue(obj, "display");
				if (sProp == "none") elem.style.display = "block";
				else elem.style.display = "none";
			}
		},

		// removes any child nodes of the given object
		ClearChildElements: function(obj) {
			var elem = RLdesign.Utils.DefineObject(obj);
			if (elem == null) return;
			if (elem.hasChildNodes()) {
				while (elem.childNodes.length >= 1) {
					elem.removeChild(elem.firstChild);       
				} 
			}
		},
		
		// Enables moving of options in a select
		ReorderSelectOption: function(obj, delta) {
			var oSelect = RLdesign.Utils.DefineObject(obj);
			if (oSelect == null || oSelect.tagName.toLowerCase() != "select" || oSelect.options.length <= 0) return false; // end if not <select>
			var bMoveAbsolute = (arguments.length == 4) ? !!(arguments[3]) : false;
			var iOptionIndex = (arguments.length >= 3) ? parseInt(arguments[2]) : oSelect.selectedIndex;
			var iDelta = parseInt(delta);

			var iNewIndex = null;
			
			// determine which index position the selected option should be moved to
			if (bMoveAbsolute && iDelta >= 0 && iDelta < oSelect.options.length) {
				// if absolute position and not out of range
				iNewIndex = iDelta;
			}
			else if (iDelta == 1 || iDelta == -1) {
				// if relative position - outer edge values should loop around to other end of list
				// ie. move down from start, go to end and vice versa
				iNewIndex = (iOptionIndex + iDelta);
				if (iNewIndex == -1) { iNewIndex = oSelect.options.length-1; }
				else if (iNewIndex == oSelect.options.length) { iNewIndex = 0; }
			}
			else {
				// if all else fails, set new index the same as old index
				iNewIndex = iOptionIndex;
			}
			
			if (iNewIndex == iOptionIndex) return false; // end if old index == new index, thus no reason to go further

			var tmpOption = oSelect.options[iOptionIndex]; // build temp option in memory to store information
			oSelect.options[iOptionIndex] = new Option(oSelect.options[iNewIndex].text, oSelect.options[iNewIndex].value);
			oSelect.options[iNewIndex] = new Option(tmpOption.text, tmpOption.value);
			oSelect.selectedIndex = iNewIndex;
			
			return true;
		},
		
		Serialize: function(o, action, seperator, value) {
			var obj = (arguments.length > 4 && arguments[4]) ? o : RLdesign.Utils.DefineObject(o);
			switch (action.toLowerCase()) {
				case "add":
					obj.value = (obj.value == "") ? value : obj.value + seperator + value;
					break;
				case "remove":
					var aValues = obj.value.split(seperator);
					var sValues = "";
					for (var i = 0; i < aValues.length; i++) {
						if (aValues[i] != value) {
							sValues = (sValues == "") ? aValues[i] : sValues + seperator + aValues[i];
						}
					}
					obj.value = sValues;
					break;
				case "get":
				case "fetch":
					if (obj.tagName != null && obj.value != null) {
						obj = obj.value;
					}
					return obj.split(seperator);
					break;
				case "length":
				case "count":
				case "getlength":
				case "getcount":
					if (obj.tagName != null && obj.value != null) {
						obj = obj.value;
					}
					return obj.split(seperator).length;
					break;
			}
		}
	}
} ();

