
var BSDClass = {
	create: function() {
    	return function() {
    		if(this.initialize) {
	      		this.initialize.apply(this, arguments);
	      	} else if(this.className) {
				BSDLogUtils.error("Couldn't find initialize function for class " + this.className);		      	
			} else {
				BSDLogUtils.error("Couldn't find initialize function for class " + arguments);		      	
	      	}
    	}
  	}
}
BSDStringUtils = {
	DEPENDENCIES: new Array(),
	VERSION: 1.1,
	
	toCamelCaseRegex: /-([a-z])/,
	
	toCamelCase: function(value) {
		var regex = BSDStringUtils.toCamelCaseRegex;
		for(; regex.test(value); value = value.replace(regex, RegExp.$1.toUpperCase()) );
		return value;
	},
	
	trimRegex: /^\s+|\s+$/g,
	
	trim: function(value) {
		var regex = BSDStringUtils.trimRegex;
		value = value.replace(regex, '');
		return value;
	},
	
	equalsTrimmed: function(value1, value2) {
		if(!value1 && !value2) {
			return true;
		}
		if(!value1) {
			return false;
		}
		if(!value2) {
			return false;
		}
		value1 = BSDStringUtils.trim(value1);
		value2 = BSDStringUtils.trim(value2);
		return value1 == value2;
	},

	startsWith: function(value, starting) {
		if(!value) {
			return false;
		}
		var regex = new RegExp("^" + starting, "g");
		if(regex.exec(value)) {
			return true;
		}
		return false;
	},
		
	endsWith: function(value, ending) {
		if(!value) {
			return false;
		}
		var regex = new RegExp(ending + "$", "g");
		if(regex.exec(value)) {
			return true;
		}
		return false;
	},
	
	stripWhitespace: function(value) {
		return value.replace(/\s/g, '');
	},
	
	truncate: function(value, length) {
		if(value.length > length) {
			value = value.substring(0, length);
		}
		return value;
	},
	
	brToLB: function(value) {
		if(!value) {
			return value;
		}
		value = value.replace("<br/>", "\n");
		value = value.replace("<br>", "\n");
		return value;
	},
	
	lbToBR: function(value) {
		if(!value) {
			return value;
		}
		value = value.replace("\r\n", "<br/>");
		value = value.replace("\r", "<br/>");
		value = value.replace("\n", "<br/>");
		return value;
	}
	
	
}

BSDTypeUtils = {
	DEPENDENCIES: new Array(),
	
	isArray: function(value) {
	    return BSDTypeUtils.isObject(value) && value.constructor == Array;		
	},
	
	isBoolean: function(value) {	
		return typeof value == 'boolean';
	},
		
	isEmpty: function(value) {
	    var i, v;
	    if (isObject(value)) {
	        for (i in value) {
	            v = value[i];
	            if (BSDTypeUtils.isUndefined(v) && BSDTypeUtils.isFunction(v)) {
	                return false;
	            }
	        }
	    }
	    return true;
	}, 
	
	isFunction: function(value) {
	    return typeof value == 'function';	
	},
	
	isNull: function(value) {
		return value == nulll;
	},
	
	isNumber: function(value) {
		return typeof value == 'number'; // && BSDTypeUtils.isFinite(value);
	},
	
	isObject: function(value) {
		return (value && typeof value == 'object');
	},

	isString: function(value) {
		return typeof value == 'string';
	},
	
	isUndefined: function(value) {
		return typeof value == 'undefined';
	}
	
}

var bsdObjectsByClassHash;

BSDDOMUtils = {
	DEPENDENCIES: new Array("BSDStringUtils", "BSDTypeUtils"),
	VERSION: 1.1,

	setElementValue: function(element, value) {
		if(element.innerHTML) {
			element.innerHTML = value;
		} else if(element.nodeType == 1) {
			var children = element.childNodes;
			for(i = 0; children && i < children.length; i++) {
				var currentChild = children[i];
				element.removeChild(currentChild);
			}
			var newTextNode = document.createTextNode(value);
			element.appendChild(newTextNode);
		} else {
			alert("Couldn't set value for node type " + element.nodeType);
		}
	},

	getAttributeValue: function(element, attributeName) {

		if(!element) {
			return;
		}
		if(element.getAttribute) {
			var currentAttribute = element.getAttribute(attributeName);
			if(currentAttribute) {
				return currentAttribute;
			}
		} else if(element.attributes) {
			var currentAttr = element.attributes[attributeName];
			if(currentAttr) {
				return currentAttr.value;
			}
		} else {

		}	



		
	},
	
	setAttributeValue: function(element, attributeName, attributeValue) {
		element.setAttribute(attributeName, attributeValue);
	},

	removeAttribute: function(element, attributeName) {
		element.removeAttribute(attributeName);
	},

	getObjectById: function(id, doc) {
		if(!doc) {
			doc = document;
		}
		
	    if(doc.getElementById) {
	        return doc.getElementById(id);
	    } else if(doc.all) {
	        return doc.all[id];
	    } else if(doc.layers) {
	        return doc.layers[id];
	    }	
	},
	
	getParentObjectByClass: function(element, className) {
		if(BSDDOMUtils.containsClass(element, className)) {
			return element;
		} else if(element.parentNode) {
			return this.getParentObjectByClass(element.parentNode, className);
		} else {

		}		
	},

	getParentObjectById: function(element, objectId) {
		if(element.id == objectId) {
			return element;
		} else if(element.parentNode) {
			return this.getParentObjectById(element.parentNode, objectId);
		} else {

		}		
	},

	getParentObjectByNodeName: function(element, nodeName, includeCurrent) {
		if(includeCurrent && element.nodeName && element.nodeName.toLowerCase() == nodeName.toLowerCase()) {

			return element;
		}
		if(element.parentNode == element || !element.parentNode || !element.parentNode.nodeName) {

			return null;
		}
		if(element.parentNode.nodeName.toLowerCase() == nodeName.toLowerCase()) {

			return element.parentNode;
		} else {

			return BSDDOMUtils.getParentObjectByNodeName(element.parentNode, nodeName);
		}
	},
	
	getObjectByNodeNameFromParent: function(parent, nodeName, includeCurrent) {
		if(includeCurrent && parent.nodeName && parent.nodeName.toLowerCase() == nodeName) {
			return parent;
		}
		for(var i = 0; i < parent.childNodes.length; i++) {
			var currentChild = parent.childNodes[i];
			if(currentChild.nodeName && currentChild.nodeName.toLowerCase() == nodeName) {
				return currentChild;
			}
		}
		for(var i = 0; i < parent.childNodes.length; i++) {
			var result = BSDDOMUtils.getObjectByNodeNameFromParent(parent.childNodes[i], nodeName, true);
			if(result) {
				return result;
			}
		}
		
	},

	getObjectByIdFromParent: function(parent, id, elementClassToIgnore) {
		if(!parent) {
			return;
		}
		var children = parent.childNodes;
		if(!children) {
			return null;
		}
		if(arguments.length > 3) {
			elementClassToIgnore = new Array();
			for(var i = 2; i < arguments.length; i++) {
				BSDArrayUtils.append(elementClassToIgnore, arguments[i]);
			}
		}
		
		for(var i = 0; i < children.length; i++) {
			var currentChild = children[i];
			if(currentChild.id == id && (!elementClassToIgnore || !BSDDOMUtils.containsClass(currentChild, elementClassToIgnore))) {
				return currentChild;
			}
		}
		for(var i = 0; i < children.length; i++) {
			var currentChild = children[i];
			if(!elementClassToIgnore || !BSDDOMUtils.containsClass(currentChild, elementClassToIgnore)) {
				var childValue = BSDDOMUtils.getObjectByIdFromParent(currentChild, id, elementClassToIgnore);
				if(childValue != null) {
					return childValue;
				}
			}
		}
	    return null;
	}, 

	getObjectByIdPrefixFromParent: function(parent, idPrefix, elementClassToIgnore) {
		var children = parent.childNodes;
		if(!children) {
			return null;
		}
		
		if(arguments.length > 3) {
			elementClassToIgnore = new Array();
			for(var i = 2; i < arguments.length; i++) {
				BSDArrayUtils.append(elementClassToIgnore, arguments[i]);
			}
		}
		
		for(var i = 0; i < children.length; i++) {
			var currentChild = children[i];
			if(currentChild.id && currentChild.id.indexOf(idPrefix) == 0 && (!elementClassToIgnore || !BSDDOMUtils.containsClass(currentChild, elementClassToIgnore))) {
				return currentChild;
			}
		}
		for(var i = 0; i < children.length; i++) {
			var currentChild = children[i];
			if(!elementClassToIgnore || !BSDDOMUtils.containsClass(currentChild, elementClassToIgnore)) {
				var childValue = BSDDOMUtils.getObjectByIdPrefixFromParent(currentChild, idPrefix, elementClassToIgnore);
				if(childValue != null) {
					return childValue;
				}
			}
		}
	    return null;
	}, 

	getObjectsByClass: function(className, parentElement, elementArray, elementClassToIgnore) {
		if(parentElement || elementArray || elementClassToIgnore) {
			return BSDDOMUtils.getObjectsByClassInternal(className, parentElement, elementArray, elementClassToIgnore);
		}
		if(document.getElementsByClassName) {
			return document.getElementsByClassName(className);
		}
		if(!bsdObjectsByClassHash) {
			BSDDOMUtils.buildObjectsByClassHash();
		} 
		
		var elementArray = bsdObjectsByClassHash[className];
		if(!elementArray) {

			elementArray = new Array();
		} 
		
		return elementArray;		
	},

	buildObjectsByClassHash: function() {
		bsdObjectsByClassHash = new Array();
		BSDDOMUtils.buildObjectsByClassHashByElement(document, true);
	},

	buildObjectsByClassHashByElement: function(parentElement) {
		if(!parentElement) {
			BSDLogUtils.error("Got null parentElement for buildObjectsByClassHashByElement");
			return;
		}
		if(parentElement.className) {
	        var split = parentElement.className.split(/\s+/);
	        for(var j = 0; j < split.length; j++) {
	        	var currentClassName = split[j];
	        	if(currentClassName.length < 1) {
	        		continue;
	        	}
				var classElements = bsdObjectsByClassHash[currentClassName];
				if(!classElements) {
					classElements = new Array();
					bsdObjectsByClassHash[currentClassName] = classElements;
				}
				classElements[classElements.length] = parentElement;				
			}			
		}
		
		
		var childNodes = parentElement.childNodes;
		for(var i = 0; childNodes && i < childNodes.length; i++) {
			var currentChild = childNodes[i];
			BSDDOMUtils.buildObjectsByClassHashByElement(currentChild);
		} 
		
	},
	
	getObjectsByClassInternal: function(className, parentElement, elementArray, elementClassToIgnore) {
		if(!elementArray) {
			elementArray = new Array();
		}
		if(!className) {
			return elementArray;
		}
		if(!parentElement) {
			parentElement = document;
		}
	    var children = parentElement.childNodes;
	    if(!children) {
	   		return elementArray;
	    }
	    for(var i = 0; i < children.length; i++) {
	        var currentChild = children[i];
		    if(currentChild.nodeType != 1) {
			    continue;
	        }	
	        
	        var split = currentChild.className.split(/\s+/);
	        for(var j = 0; j < split.length; j++) {
	        	var currentClassName = split[j];
	        	if(!currentClassName || currentClassName.length < 1) {
	        		continue;
	        	}

			    if(currentClassName == className) {
			        var index = elementArray.length;
			        elementArray[index] = currentChild;
		        } else if(elementClassToIgnore && currentClassName == elementClassToIgnore) {

		        	continue;
		        }
		    }	        
	        
		    BSDDOMUtils.getObjectsByClass(className, currentChild, 
							elementArray, elementClassToIgnore);
	    }
	    return elementArray;
	},
	
	getObjectsById: function(id, parentElement, elementArray) {
		if(!elementArray) {
			elementArray = new Array();
		}
		if(!id) {
			return elementArray;
		}
		if(!parentElement) {
			parentElement = document;
		}
	    var children = parentElement.childNodes;
	    if(!children) {
	   		return elementArray;
	    }
	    for(var i = 0; i < children.length; i++) {
	        var currentChild = children[i];
		    if(currentChild.nodeType != 1) {
			    continue;
	        }	
		    if(currentChild.id == id) {
		        var index = elementArray.length;
		        elementArray[index] = currentChild;
	        }
		    BSDDOMUtils.getObjectsById(id, currentChild, 
							elementArray);
	    }
	    return elementArray;
	},

	getObjectsByNodeName: function(parentElement, nodeName, elementArray) {
		if(!elementArray) {
			elementArray = new Array();
		}
		if(!nodeName) {
			return elementArray;
		}
		if(!parentElement) {
			BSDLogUtils.error("ERROR: Got null parentElement for getObjectsByNodeName()");
			return;
		}
	    var children = parentElement.childNodes;
	    if(!children) {
	   		return null;
	    }
	    for(var i = 0; i < children.length; i++) {
	        var currentChild = children[i];
		    if(currentChild.nodeType != 1) {
			    continue;
	        }	
		    if(currentChild.nodeName == nodeName) {
		        var index = elementArray.length;
		        elementArray[index] = currentChild;
	        }
		    BSDDOMUtils.getObjectsByNodeName(currentChild, nodeName, 
							elementArray);
	    }
	    return elementArray;
	},

	getRootElement: function() {
		if(document.documentElement) {
			return document.documentElement;
		}
		return null;
	},
	
	getNextElementSibling: function(element) {
		var sibling = element.nextSibling;
		while(sibling && sibling.nodeType != 1) {
			sibling = sibling.nextSibling;
		}
		return sibling;
	},

	getPreviousElementSibling: function(element) {
		var sibling = element.previousSibling;
		while(sibling && sibling.nodeType != 1) {
			sibling = sibling.previousSibling;
		}
		return sibling;
	},
	
	getElementStyle: function(element, styleName) {
		if(!element.style) {

			return;
		}
		var ieStyleName = BSDStringUtils.toCamelCase(styleName);
		var styleValue = element.style[ieStyleName];
	    if(!styleValue) {
			if(document.defaultView && document.defaultView.getComputedStyle) {
	        	var cssStyleValue = document.defaultView.getComputedStyle(element, "");
	        	if(!cssStyleValue) {
	        		return null;
	        	}
	        	styleValue = cssStyleValue.getPropertyValue(styleName);

	      	} else if(element.currentStyle) {
	        	styleValue = element.currentStyle[ieStyleName];
	      	}
	  	}

		if(styleValue == 'auto') {
			return null;
		}
	  	return styleValue;
	},
	
 
	elementContainsStyle: function(element, stylePropertyName, stylePropertyValue) {
	    stylePropertyValue = stylePropertyValue.toLowerCase();
	    if(element.style && element.style[stylePropertyName] &&
						element.style[stylePropertyName].toLowerCase() == stylePropertyValue) {
			return true;
	    }
	    return false;
	},

	setElementStyle: function(element, stylePropertyName, stylePropertyValue) {
		BSDDOMUtils.changeElementStyle(element, stylePropertyName, stylePropertyValue);
	},
		
	changeElementStyle: function(element, stylePropertyName, stylePropertyValue) {
	    var elementStyle = element.style;
	    if(elementStyle) {
	    	try {
			    elementStyle[stylePropertyName] = stylePropertyValue;
			} catch (err) {  


			}
		}
		if(stylePropertyName == 'background-color') {
			element.style.backgroundColor = stylePropertyValue;
		} else if(stylePropertyName == 'font-family') {
			element.style.fontFamily = stylePropertyValue;
		} else if(stylePropertyName == 'text-align') {
			element.style.textAlign = stylePropertyValue;
		}
	},
	
	cloneElementStyle: function(source, target, stylePropertyName) {
		if(stylePropertyName) {
			var value = BSDDOMUtils.getElementStyle(source, stylePropertyName);
			if(value) {

				BSDDOMUtils.changeElementStyle(target, stylePropertyName, value);
			}
			return value;
		}
	},
	
	cloneAllElementStyles: function(source, target) {
		for(var styleName in source.style) {
			if(styleName) {
				BSDDOMUtils.cloneElementStyle(source, target, styleName);
			}
		}
	
	},
	
	getElementMargin: function(source, tryChildren) {
		var margin = BSDDOMUtils.getElementStyle(source, 'margin');
		var iTop = 0;
		var iRight = 0;
		var iLeft = 0;
		var iBottom = 0;
		if(margin) {
			var split = margin.split(/\s*px\s*/i);
			if(split.length < 1 && margin.length > 0) {
				iTop = parseInt(margin);
			}
			if(split.length > 0) {
				iTop = parseInt(split[0]);
			}
			if(split.length > 1) {
				iRight = parseInt(split[1]);
			}
			if(split.length > 2) {
				iBottom = parseInt(split[2]);
			}
			if(split.length > 3) {
				iLeft = parseInt(split[3]);
			}			
		}
		
		var marginTop = BSDDOMUtils.getElementStyle(source, 'margin-top');
		if(marginTop && marginTop.length > 2) {
			iTop = marginTop.replace(/\s*px\s*/i, '');
		}
		var marginRight = BSDDOMUtils.getElementStyle(source, 'margin-right');
		if(marginRight && marginRight.length > 2) {
			iRight = marginRight.replace(/\s*px\s*/i, '');
		}
		var marginBottom = BSDDOMUtils.getElementStyle(source, 'margin-bottom');
		if(marginBottom && marginBottom.length > 2) {
			iBottom = marginBottom.replace(/\s*px\s*/i, '');
		}
		var marginLeft = BSDDOMUtils.getElementStyle(source, 'margin-left');
		if(marginLeft && marginLeft.length > 2) {
			iLeft = marginLeft.replace(/\s*px\s*/i, '');
		}

		if(tryChildren && iTop == 0 && iRight == 0 && iBottom == 0 && iLeft == 0) {

			var marginChild = null;
			for(var i = 0; i < source.childNodes.length; i++) {
				var currentChild = source.childNodes[i];
				if(currentChild.nodeType == 1 && !BSDVisibilityUtils.isObjectHidden(currentChild)) {
					if(!marginChild) {
						marginChild = currentChild;
					} else {
						marginChild = null;
						break;
					}
				}
				if(marginChild) { 
					return BSDDOMUtils.getElementMargin(marginChild, false);
				}
			}		
		}
		
		var margin = new Object();
		
		margin.margin = iTop + 'px ' + iRight + 'px ' + iBottom + 'px ' + iLeft + 'px';
		margin.top = iTop;
		margin.right = iRight;
		margin.bottom = iBottom;
		margin.left = iLeft;


		return margin;
	},

	
	getElementWidth: function(element) {
		var iWidth = element.offsetWidth;
		if(iWidth && iWidth > 0) {
			return iWidth;
		}
		var width = BSDDOMUtils.getElementStyle(element, 'width');
		if(width && width.length > 0) {
			width = width.replace(/\s*px\s*/i, '');
			return parseInt(width);
		}
		
		width = BSDDOMUtils.getAttributeValue(element, 'width');		
		if(width && width.length > 0) {
			return parseInt(width);
		}
		return 0;
	},
	
	getElementHeight: function(element) {
		var iHeight = element.offsetHeight;
		if(iHeight && iHeight > 0) {
			return iHeight;
		}
		var height = BSDDOMUtils.getElementStyle(element, 'height');
		if(height && height.length > 0) {
			height = height.replace(/\s*px\s*/i, '');
			return parseInt(height);
		}
		height = BSDDOMUtils.getAttributeValue(element, 'height');
		if(height && height.length > 0) {
			return parseInt(height);
		}
		return 0;
	},
	
	cloneElement: function(sourceElement, doShallowClone) {
		var deep = true;
		if(doShallowClone) {
			deep = false;
		}
		return sourceElement.cloneNode(deep);
	},
    

	cloneElementDimensions: function(source, target, deltaWidth, deltaHeight) {
	    var newWidth = source.offsetWidth;
	    var newHeight = source.offsetHeight;
	    if(deltaWidth) {
			newWidth += deltaWidth;
	    }
	    if(deltaHeight) {
			newHeight += deltaHeight;
	    }
	    BSDDOMUtils.changeElementStyle(target, 'width', newWidth);
	    BSDDOMUtils.changeElementStyle(target, 'height', newHeight);
	},

	cloneDimensions: function(sourceDimensions, target) { 
	    BSDDOMUtils.changeElementStyle(target, 'width', sourceDimensions.width);
	    BSDDOMUtils.changeElementStyle(target, 'height', sourceDimensions.height);	
	},
	
	cloneElementMargins: function(source, target, tryChildren) {
		var margin = BSDDOMUtils.getElementMargin(source, tryChildren);
		BSDDOMUtils.changeElementStyle(target, 'margin', margin.margin);

		return margin.margin != '0px 0px 0px 0px';		
	},

	createElement: function(nodeName, parent, id, className) {
		var element = document.createElement(nodeName);	
		if(parent) {
			parent.appendChild(element);
		}
		if(id) {
			element.id = id;
		}
		if(className) {
			element.className = className;
		}
		return element;
	},
	
	removeElement: function(element) {
		var parent = element.parentNode;
		if(!parent) {
			return;
		}
		if(element.nodeName == 'TR') {
			while(parent && parent.nodeName != 'TABLE') {
				parent = parent.parentNode;
			}
			if(parent) {
				parent.deleteRow(element.rowIndex);
			} else {
				BSDLogUtils.error("ERROR: Couldn't find table parent for row to remove");
			}
		} else {
			parent.removeChild(element);
		}
	},
	
	getPreviousSiblingElement: function(element) {
		var sibling = element.previousSibling;
		while(sibling && sibling.nodeType != 1) {
			sibling = sibling.previousSibling;
		}
		return sibling;
	},
	
	getNextSiblingElement: function(element) {
		var sibling = element.nextSibling;
		while(sibling && sibling.nodeType != 1) {
			sibling = sibling.nextSibling;
		}
		return sibling;
	},
	
	setCursor: function(element, cursorName) {
		BSDDOMUtils.changeElementStyle(element, 'cursor', cursorName);
	},

	setMoveCursor: function(element) {
		BSDDOMUtils.setCursor(element, 'move');
	},
	
	setDefaultCursor: function(element) {
		BSDDOMUtils.setCursor(element, 'default');
	},
	
	setClass: function(element, className) {
		element.className = className;
	},
	
	addClass: function(element, className, prepend) {
		if(element.className) {
			if(prepend) {
				element.className = className + " " + element.className;
			} else {
				element.className += " " + className;
			}
		} else {
			element.className = className;
		}
	},
	
	removeClass: function(element, className) {
		if(!element.className || element.className.length < 1) {
			return;
		}
		var newClassName = "";
		var split = element.className.split(/\s+/);
	    for(var i = 0; i < split.length; i++) {
	        var currentClassName = split[i];
	        if(!currentClassName || currentClassName.length < 1) {
	        	continue;
	        }

			if(currentClassName != className) {
				newClassName += currentClassName;
				if(i < split.length -1) {
					newClassName += " ";
				}
			}
		}
		element.className = newClassName;
	},
	
	containsClass: function(element, className) {
		if(!element.className || !className) {
			return false;
		}
		var multipleClasses = BSDTypeUtils.isArray(className);
        var split = element.className.split(/\s+/);
        for(var j = 0; j < split.length; j++) {
        	var currentClassName = split[j];
        	if(!currentClassName || currentClassName.length < 1) {
        		continue;
        	}

        	if(multipleClasses && BSDArrayUtils.contains(className, currentClassName)) {
        		return true;
		    } else if(currentClassName == className) {
		    	return true;
	        } 
	    }		
	    return false;
	},
	
	addChild: function(element, child) {
		element.appendChild(child);
	},
	
	moveElement: function(element, newParent) {
		BSDDOMUtils.removeElement(element);
		BSDDOMUtils.addChild(newParent, element);
	},
	
	replaceElement: function(oldElement, newElement) {
		oldElement.parentNode.replaceChild(newElement, oldElement);
	},
	
	replaceElementByIdAndHtml: function(oldElementId, newElementHtml) {
		var oldElement = BSDDOMUtils.getObjectById(oldElementId);
		if(!oldElement) {
			BSDLogUtils.warning("Couldn't find element to replace with id: " + oldElementId);
			return;
		}
		newElementHtml = newElementHtml.replace(/scripx/g, 'script');
		alert(newElementHtml);
		oldElement.innerHTML = newElementHtml;
		if(oldElement.childNodes.length == 1) {
			BSDDOMUtils.replaceElement(oldElement, oldElement.childNodes[0]);
		}
		
	},
	
	replaceElementByParentId: function(parentElementId) {
		var parentElement = BSDDOMUtils.getObjectById(parentElementId);
		if(!parentElement) {
			BSDLogUtils.warning("Couldn't find parent element to replace with id: " + parentElementId);
			return;
		}

		var elementsToMove = new Array();
		for(var i = 0; i < parentElement.childNodes.length; i++) {

			var currentElement = parentElement.childNodes[i];

			if(currentElement.nodeType != 1) {
				continue;
			}
			var targetId = BSDDOMUtils.getAttributeValue(currentElement, 'rid');
			if(!targetId) {
				BSDLogUtils.warning("Couldn't find target id for element to replace: " + currentElement.id);
				continue;
			}
			var target = BSDDOMUtils.getObjectById(targetId);
			if(!target) {
				BSDLogUtils.warning("Couldn't find target element to replace: " + targetId);
				continue;
			}
			
			var currentHolder = new Object();
			currentHolder.source = currentElement;
			currentHolder.target = target;
			elementsToMove[elementsToMove.length] = currentHolder;
		}
		for(var i = 0; i < elementsToMove.length; i++) {
			var currentHolder = elementsToMove[i];
			BSDDOMUtils.replaceElement(currentHolder.target, currentHolder.source);

		}
	

	},
	
	addText: function(element, text) {
		var textNode = document.createTextNode(text);
		element.appendChild(textNode);
	},
	
	setText: function(element, text) {
		if(!element || !element.childNodes) {
			BSDLogUtils.error("Cannot set text on null element");
			return;
		}
		if(element.nodeName && element.nodeName.toLowerCase() == 'input') {
			element.value = text;
		} else if(element.nodeName && element.nodeName.toLowerCase() == 'select') {
			if(!text || text.length < 1) {
				if(element.options && element.options.length > 0) {
					element.options[0].selected = true;
					return;
				}
			}
			for(var i = 0; i < element.childNodes.length; i++) {
				var currentChild = element.childNodes[i];
				var value = currentChild.value;
				if(value && value == text) {
					currentChild.selected = true;
					break;
				} else if(!value && BSDDOMUtils.getText(element) == text) {
					currentChild.selected = true;
					break;
				}
			}
		} else {			
			for(var i = 0; i < element.childNodes.length; i++) {
				if(element.childNodes[i].nodeType == 3) {
					element.removeChild(element.childNodes[i]);
					i--;
				} 
			}
			BSDDOMUtils.addText(element, text);
		}
		
	},
	
	setTextById: function(elementId, text, parentElement) {
		var element;
		if(parentElement) {
			element = BSDDOMUtils.getObjectByIdFromParent(parentElement, elementId);
		} else {
			element = BSDDOMUtils.getObjectById(elementId);
		}
		if(!element) {
			return;
		}
		BSDDOMUtils.setText(element, text);
	},
	
	getText: function(element) {
		var text = "";
		if(!element) {
			return text;
		}
		if(element.nodeName && element.nodeName.toLowerCase() == 'input') {
			return element.value;
		}
		
		if(!element.childNodes) {
			return text;
		}
		for(var i = 0; i < element.childNodes.length; i++) {
			if(element.childNodes[i].nodeType == 3) {
				text += element.childNodes[i].nodeValue;
			}		
		}
		return text;
	},
	
	getTextById: function(elementId) {
		var element = BSDDOMUtils.getObjectById(elementId);
		if(!element) {
			return;
		}
		return BSDDOMUtils.getText(element);	
	},
	
	appendElementToRoot: function(element) {
		if(document.body) {
			document.body.appendChild(element);
		} else {
			for(var i = 0; i < document.childNodes.length; i++) {
				document.childNodes[i].appendChild(element);
			}
		}
	},
	
	clear: function(element) {
		if(element.nodeName.toLowerCase() == 'table' && element.tBodies && element.tBodies.length > 0) {
			for(var i = 0; i < element.tBodies.length; i++) {

				BSDDOMUtils.clear(element.tBodies[i]);
			}
		} else {
		    while(element.childNodes.length > 0) {

				element.removeChild(element.childNodes[0]);
			}
		}	
	},
	
	getContainsChildElements: function(element, exceptionClass) {
		if(!element || !element.childNodes) {
			return false;
		}
		for(var i = 0; i < element.childNodes.length; i++) {
			var currentChild = element.childNodes[i];
			if(exceptionClass && BSDDOMUtils.containsClass(currentChild, exceptionClass)) {
				continue;
			}
			if(currentChild.nodeType == 1) {
				return true;
			}
		}
		return false;
	},
	
	insertAfter: function(existingElement, newElement) {
		var parentNode = existingElement.parentNode;
		if(!parentNode) {
			return false;
		}
		if(existingElement.nextSibling) {
			parentNode.insertBefore(newElement, existingElement.nextSibling);
		} else {
			parentNode.appendChild(newElement);
		}
		
		return true;
	},
	
	insertBefore: function(existingElement, newElement) {
		var parentNode = existingElement.parentNode;
		if(!parentNode) {
			return false;
		}

		if(existingElement.nodeName.toUpperCase() == 'TR' && !newElement.nodeName.toUpperCase() == 'TR') {
			var row = document.createElement('tr');
			if(!newElement.nodeName.toUpperCase() == 'TD') {
				var column = document.createElement('td');
				column.appendChild(newElement);
				row.appendChild(column);
			} else {
				row.appendChild(newElement);
			}
			newElement = row;
		} 

		parentNode.insertBefore(newElement, existingElement);
		
		return true;
	},
	
	insertChild: function(parentElement, newElement, index) {
		if(!parentElement) {
			BSDLogUtils.error("Got null parentElement for insertChild");
			return;
		}
		var childNodes = parentElement.childNodes;
		if(index && childNodes.length > index) {
			BSDDOMUtils.insertBefore(childNodes[index], newElement);
		} else {
			BSDDOMUtils.addChild(parentElement, newElement);
		}
	},
	
	getElementParentIndex: function(element) {
		var parentNode = element.parentNode;
		for(var i = 0; i < parentNode.childNodes.length; i++){
			if(parentNode.childNodes[i] == element) {
				return i;
			}
		}
	},
	
	appendAsRow: function(table, rowContents) {
		var row = document.createElement('tr');
		var column = document.createElement('td');
		
		column.innerHTML = rowContents;
		table.tBodies[0].appendChild(row);
		row.appendChild(column);
	},
	
	setInnerHTML: function(element, content) {
  		if(element.nodeName.toUpperCase() == 'TABLE') {
  			BSDDOMUtils.clear(element);
  			if(BSDStringUtils.startsWith(content, '<tr') && element.tBodies && element.tBodies.length > 0) {
  				element.tBodies[0].innerHTML = content;
  			} else {
				BSDDOMUtils.appendAsRow(element, content);
			}
  		} else {
	  		element.innerHTML = content;
	  	}
	
	},
	
	getFrameDocument: function(frame) {
		if(frame.contentDocument) {
			return frame.contentDocument;
		} else {
			return frame.document; //ie
		}
	}
	

}
BSDVisibilityUtils = {
	DEPENDENCIES: new Array("BSDDOMUtils"),
	VERSION: 1.0,
		
	switchById: function(current,next) {
	    var currentObj = BSDDOMUtils.getObjectById(current);
	    var nextObj = BSDDOMUtils.getObjectById(next);
	    if(!currentObj || ! nextObj) {
	    		return;
	    }
	    var nextObjDisplay = nextObj.style.display;
	    var nextObjVisibility = nextObj.style.visibility;
	    nextObj.style.display = currentObj.style.display;
	    nextObj.style.visibility = currentObj.style.visibility;
	    currentObj.style.display = nextObjDisplay;
	    currentObj.style.visibility = nextObjVisibility;
	},
	
	showByClass: function(className) {
		var objects = BSDDOMUtils.getObjectsByClass(className);
		for(var i = 0; i < objects.length; i++) {
			BSDVisibilityUtils.showObject(objects[i]);
		}
	},
	
	showByClassAndParentId: function(className, parentId) {
		var parent = BSDDOMUtils.getObjectById(parentId);	
		BSDVisibilityUtils.showByClassAndParent(className, parent);
	},
	
	showByClassAndParent: function(className, parent) {
		var objects = BSDDOMUtils.getObjectsByClass(className, parent);
		for(var i = 0; i < objects.length; i++) {
			BSDVisibilityUtils.showObject(objects[i]);
		}
	},
	
	hideByClass: function(className) {
		var objects = BSDDOMUtils.getObjectsByClass(className);
		for(var i = 0; i < objects.length; i++) {
			BSDVisibilityUtils.hideObject(objects[i]);
		}
	},
	
	hideByClassAndParentId: function(className, parentId) {
		var parent = BSDDOMUtils.getObjectById(parentId);
		BSDVisibilityUtils.hideByClassAndParent(className, parent);
	},
	
	hideByClassAndParent: function(className, parent) {
		var objects = BSDDOMUtils.getObjectsByClass(className, parent);
		for(var i = 0; i < objects.length; i++) {
			BSDVisibilityUtils.hideObject(objects[i]);
		}
	},
	
	showById: function(objectName) {
	    var object = BSDDOMUtils.getObjectById(objectName);
	    BSDVisibilityUtils.showObject(object);
	    return object;
	},
	
	showObject: function(object) {
		if(!object) {
			return;
		}
		object.style.display = "";
		object.style.visibility = "visible";
	},
	
	hideById: function(objectName) {
	    var object = BSDDOMUtils.getObjectById(objectName);
		BSDVisibilityUtils.hideObject(object);
		return object;
	},
	
	hideObject: function(object) {
		if(!object) {
			return;
		}
	    object.style.display = "none";
	    if((object.nodeName == 'TR' || object.nodeName == 'TD') && object.visibility) {
	    	object.style.visibility = "collapse";
	    } else if(object.visibility) {
		    object.style.visibility = "hidden";
	    }
	},
	
	showByObject: function(currentObj, nextObj) {
	    BSDVisibilityUtils.showObject(nextObj);
	    BSDVisibilityUtils.hideObject(currentObj);
	},
	
	isObjectHidden: function(object) {
	    if(object.style && object.style.display && object.style.display.toLowerCase() == 'none') {
			return true;
	    }
	    return false;
	},
	
	toggleObject: function(object) {
		if(BSDVisibilityUtils.isObjectHidden(object)) {
			BSDVisibilityUtils.showObject(object);
		} else {
			BSDVisibilityUtils.hideObject(object);		
		}
	},
	
	switchByNameAndJustify: function(switchObjectName, justifyObjectName) {
	    var switchObj = BSDDOMUtils.getObjectById(switchObjectName);
	    var justifyObj = BSDDOMUtils.getObjectById(justifyObjectName);
	
	    var existingHeight = 0;
	    if(!BSDVisibilityUtils.isObjectHidden(justifyObj)) {
			existingHeight = parseInt(justifyObj.style.height);
	    }
	    if(BSDVisibilityUtils.isObjectHidden(switchObj)) {
			showObject(switchObj);
			if(existingHeight > 0) { 
		    		switchObj.style.height = (existingHeight/2) + "%";
		    		justifyObj.style.height = (existingHeight/2) + "%";
			} 
	    } else {
	 		BSDVisibilityUtils.hideObject(switchObj);
			if(existingHeight > 0) { 
		    		switchObj.style.height = '0%';
		    		justifyObj.style.height = (existingHeight*2) + "%";
			} 
	    }
	},
	
	showIfSelected: function(object, searchValue, objectIdToShow) {

		if(object.value && object.value == searchValue) {
	       	BSDVisibilityUtils.showById(objectIdToShow);
	  	} else {
	       	BSDVisibilityUtils.hideById(objectIdToShow);
	   	}
	},

	showIfSelectedById: function(objectId, searchValue, objectIdToShow) {
		var object = BSDDOMUtils.getObjectById(objectId);
		BSDVisibilityUtils.showIfSelected(object, searchValue, objectIdToShow);
	}

}


BSDLogUtils = {
	DEPENDENCIES: new Array("BSDDOMUtils", "BSDClass"),
	VERSION: 1.1,

	isLogWindowEnabled: false,
	
	debugEnabled: true,
	warningEnabled: true,
	errorEnabled: true,
	
	logStatements: new Array(),

	showLogWindow: function() {
		var logElement = BSDLogUtils.logElement;
		if(!logElement) {
			logElement = BSDDOMUtils.getObjectById("BSDLogWindow");
		}

		if(!logElement) {
			logElement = BSDDOMUtils.createElement("div");
			logElement.id = "BSDLogWindow";
			BSDDOMUtils.changeElementStyle(logElement, 'position', 'absolute');			
			BSDDOMUtils.changeElementStyle(logElement, 'text-align', 'left');	
			BSDLogUtils.logElement = logElement;
			document.body.appendChild(logElement);

			BSDLogUtils.showLogStatements();
		}
		BSDDOMUtils.changeElementStyle(logElement, "top", 0); // + currentScrollPosition.y);
		BSDDOMUtils.changeElementStyle(logElement, "left", 450); // + currentScrollPosition.x);
				
	},

	showLogStatements: function() {
		var logElement = BSDLogUtils.logElement;
		for(var i = 0; i < BSDLogUtils.logStatements.length; i++) {
			var currentStatement = BSDLogUtils.logStatements[i];
			if(currentStatement.isError && !BSDLogUtils.errorEnabled) {
				continue;
			} else if(currentStatement.isWarning && !BSDLogUtils.warningEnabled) {
				continue;
			} else if(currentStatement.isDebug && !BSDLogUtils.debugEnabled) {
				continue;
			}
			
			BSDLogUtils.displayLogStatement(currentStatement);
		}
	},
	
	displayLogStatement: function(statement) {
		var logElement = BSDLogUtils.logElement;

		var statementElement = BSDDOMUtils.createElement("div", logElement, null, "BSDLogStatement");			
		statementElement.statementId = statement.id;

		var statementDateElement = BSDDOMUtils.createElement("span", statementElement, null, "BSDLogStatementDate");
		statementDateElement.innerHTML = statement.date.getHours() + ":" + statement.date.getMinutes() + ":" + statement.date.getSeconds();

		var statementTypeElement = BSDDOMUtils.createElement("span", statementElement, null, "BSDLogStatementType");
		statementTypeElement.innerHTML = statement.type;
		
		var statementMsgElement = BSDDOMUtils.createElement("span", statementElement, null, "BSDLogStatementMessage");
		statementMsgElement.innerHTML = statement.message;

	},		
	
	error: function(message) {
		var newStatement = new BSDLogStatement(BSDLogUtils.logStatements.length, "ERROR", message);
		BSDArrayUtils.append(BSDLogUtils.logStatements, newStatement);
		if(BSDLogUtils.errorEnabled) {
			BSDLogUtils.displayLogStatement(newStatement);		
		}
	},
	
	warning: function(message) {
		var newStatement = new BSDLogStatement(BSDLogUtils.logStatements.length, "WARNING", message);
		BSDArrayUtils.append(BSDLogUtils.logStatements, newStatement);
		if(BSDLogUtils.warningEnabled) {
			BSDLogUtils.displayLogStatement(newStatement);		
		}
	},
	
	debug: function(message) {
		var newStatement = new BSDLogStatement(BSDLogUtils.logStatements.length, "DEBUG", message);
		BSDArrayUtils.append(BSDLogUtils.logStatements, newStatement);
		if(BSDLogUtils.debugEnabled) {
			BSDLogUtils.displayLogStatement(newStatement);		
		}
	},
	
	registerEvent: function(element, type, func) {
	    if(element.addEventListener) {
			element.addEventListener(type, func, true);
	    } else if(element.attachEvent) {
			element.attachEvent('on' + type, func);
	    } else {
	    	alert("ERROR: Couldn't register event: " + type + " " + func);
	    }

	},
	
	recordImageTime: function(src) {
		var image = new Image();
		image.src = src;
		var breakBlock = BSDDOMUtils.getObjectById('kcmBreakBlock');
		if(!breakBlock) {
			breakBlock = document.body;
		}
		BSDDOMUtils.insertChild(breakBlock, image, 0);

	}
	
}

if(BSDLogUtils.isLogWindowEnabled) {
	BSDLogUtils.registerEvent(window, "load", BSDLogUtils.showLogWindow);
}


BSDLogStatement = BSDClass.create();
BSDLogStatement.prototype = {

	className: "BSDLogStatement",
	initialize: function(id, type, message) {
		this.id = id;
	    this.type = type;
		this.message = message;
		this.date = new Date();
	},
	
	isError: function() {
		if(this.type == 'ERROR') {
			return true;
		}
		return false;
	},

	isWarning: function() {
		if(this.type == 'WARNING') {
			return true;
		}
		return false;
	},

	isDebug: function() {
		if(this.type == 'DEBUG') {
			return true;
		}
		return false;
	}

}

BSDColorUtils = {
	DEPENDENCIES: new Array(),
	
	rgbColorToHex: function(rgb) {  
		if(!rgb) {
			return;
		}
		var color = '#';  
  		if(rgb.slice(0,4) == 'rgb(') {  
    			var cols = rgb.slice(4, rgb.length-1).split(',');  
    			var i=0; do { color += this.toColorPart(parseInt(cols[i])) } while (++i<3);  
  		} else {  
    			if(rgb.slice(0,1) == '#') {  
	      			if(rgb.length==4) { 
	      				for(var i=1;i<4;i++) {
	      					color += (rgb.charAt(i) + rgb.charAt(i)).toLowerCase();  
	      				}
	      			}
	      			if(rgb.length==7) {
	      				color = rgb.toLowerCase();  
	      			}
    			}  
  		}  
  		if(color.length == 7) {
  			return color;
  		}
  		return rgb;
	},
	
	toColorPart: function(intValue) {
	    var digits = intValue.toString(16);
	    if (intValue < 16) return '0' + digits;
	    return digits;
  	},
  	
  	rgbRegex: /\s*rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,?\s*(\d+)?\s*\)\s*/,
  	
  	incrementRGBColor: function(rgbColor, incrementValue) {
  		if(!incrementValue) {
  			incrementValue = 50;
  		}

  		var rIncrementValue = incrementValue;
  		var gIncrementValue = incrementValue;
  		var bIncrementValue = incrementValue;
  		if(incrementValue.length && incrementValue.length > 2) {
  			rIncrementValue = incrementValue[0];
  			gIncrementValue = incrementValue[1];
  			bIncrementValue = incrementValue[2];
  		}
  		
  		var regexResult = rgbColor.match(BSDColorUtils.rgbRegex);
  		if(regexResult != null && regexResult.length > 0) {
  			var r = parseInt(regexResult[1]);
  			var g = parseInt(regexResult[2]);
  			var b = parseInt(regexResult[3]);
  			if(regexResult.length > 4) {
  				var a = parseInt(regexResult[4]);
  				if(a == 0 || (r > 245 && g > 245 && b > 245)) {
  					rIncrementValue = -1 * Math.abs(rIncrementValue);
  					gIncrementValue = -1 * Math.abs(gIncrementValue);
  					bIncrementValue = -1 * Math.abs(bIncrementValue);
  					r = 255;
  					g = 255;
  					b = 255;
  				}
  			}
  			r += rIncrementValue;
  			g += gIncrementValue;
  			b += bIncrementValue;

  			rgbColor = "rgb(" + r + "," + g + "," + b + ")";
  		} else if(rgbColor.toLowerCase() == "transparent") {
  			var r = 255 - Math.abs(rIncrementValue);
  			var g = 255 - Math.abs(gIncrementValue);
  			var b = 255 - Math.abs(bIncrementValue);
  			rgbColor = "rgb(" + r + ", " + g + ", " + b + ")";
  		} else {
  			BSDLogUtils.debug("No rgb match: [" + rgbColor + "]");
  		}
  		return rgbColor;
  	}

}	
BSDHighlightUtils = {
	DEPENDENCIES: new Array("BSDColorUtils", "BSDDOMUtils", "BSDLogUtils"),

	highlightElement: function(element, newColor, incrementValue) {
		if(element.oldBGColor) {
			return;
		}
		var currentBGColor = BSDDOMUtils.getElementStyle(element, 'background-color');

		if(!element.oldBGColor) {
			element.oldBGColor = BSDColorUtils.rgbColorToHex(currentBGColor);
		}
		if(!newColor) {
			newColor = BSDColorUtils.incrementRGBColor(currentBGColor, incrementValue);
			newColor = BSDColorUtils.rgbColorToHex(newColor);
		} 
		element.style.backgroundColor = newColor;

	},
	
	unHighlightElement: function(element) {
		var oldBGColor = element.oldBGColor;
		if(!oldBGColor) {
			oldBGColor = null;
		}	

		element.style.backgroundColor = oldBGColor;
		element.oldBGColor = null;
	},
	
	setMoveCursor: function(element) {
		if(element.oldCursor) {
			return;
		}
		var oldCursor = BSDDOMUtils.getElementStyle(element, 'cursor');
		if(!oldCursor) {
			oldCursor = "default";
		}
		element.style.cursor = "move";
		element.oldCursor = oldCursor;

	},
	
	unSetMoveCursor: function(element) {
		var oldCursor = element.oldCursor;
		element.style.cursor = oldCursor;
		element.oldCursor = null;

	},
	
	setBorderOnElement: function(element, width, newColor, incrementValue) {
		if(element.oldBorder) {
			return;
		}
		
		if(!width) {
			width = 1;
		}
		if(!newColor) {
			var currentBGColor = BSDDOMUtils.getElementStyle(element, 'background-color');
			if(!currentBGColor) {
				hexColor = "#555";
			} else {
				newColor = BSDColorUtils.incrementRGBColor(currentBGColor, incrementValue);
				newColor = BSDColorUtils.rgbColorToHex(newColor);
			}
		}
		var oldBorder = BSDDOMUtils.getElementStyle(element, "border");
		if(oldBorder) {
			element.oldBorder = oldBorder;
		}
		var newBorder = " " + width + "px solid " + newColor;

		BSDDOMUtils.changeElementStyle(element, "border", newBorder);
		BSDLogUtils.debug("Set element border: " + newBorder);

		
	},
	
	unSetBorderOnElement: function(element) {
		var oldBorder = element.oldBorder;
		if(!oldBorder) {
			oldBorder = "none";
		}
		BSDDOMUtils.changeElementStyle(element, "border", oldBorder);
		element.oldBorder = null;
	},
	
	highlightElementByOverlay: function(element) {
		if(element.bsdHighlightOverlay) {
			return;
		}
		var highlightElement = BSDDOMUtils.createElement("div", document.body);
		highlightElement.className = 'BSDHighlightedBox';
		var positionX = BSDLocationUtils.getObjectLocationX(element);
		var positionY = BSDLocationUtils.getObjectLocationY(element);
		var adjustX = 5;
		if(positionX < adjustX) {
			adjustX = positionX;
		}
		var adjustY = 5;
		if(positionY < adjustY) {
			adjustY = positionY;
		}
		var width = 5 + adjustX;
		var height = 5 + adjustY;
		BSDLocationUtils.makeElementAbsolutelyPositioned(highlightElement);
		BSDLocationUtils.cloneElementLocation(element, highlightElement, -adjustX, -adjustY, width, height);
		element.bsdHighlightOverlay = highlightElement;
	},
	
	unHighlightElementByOverlay: function(element) {
		if(!element.bsdHighlightOverlay) {
			return;
		}
		BSDDOMUtils.removeElement(element.bsdHighlightOverlay);
		element.bsdHighlightOverlay = null;
	}
	
	
	
}
BSDArrayUtils = {
	DEPENDENCIES: new Array("BSDTypeUtils"),
	
	insert: function(array, value, index) {
		if(array.splice && BSDTypeUtils.isArray(value)) {
			for(var i = 0; i < value.length; i++) {
				array.splice(index + i, 0, value[i]);
			}		
		} else if(array.splice) {
			array.splice(index, 0, value);
		} else if(BSDTypeUtils.isArray(value)) {
			for(var i = array.length - 1 + value.length; i > index; i--) {
				array[i] = array[i-1];			
			}
			for(var i = 0; i < value.length; i++) {
				array[index + i] = value[i];
			}		
		} else {
			for(var i = array.length; i > index; i--) {
				array[i] = array[i-1];			
			}
			array[index] = value;
		}
	},
	
	append: function(array, value) {
		if(array.push && !BSDTypeUtils.isArray(value)) {
			array.push(value);
		} else if(BSDTypeUtils.isArray(value)) {
			var j = 0;
			var newLength = array.length + value.length;
			for(var i = array.length; i < newLength; i++) {
				array[i] = value[j];
				j++
			}
		} else {	
			array[array.length] = value;
		}
	},
	
	deleteElement: function(array, index, count) {
		if(!count) {
			count = 1;
		}
		if(array.splice) {
			array.splice(index, count);
			return array;
		} else {
			var newArray = new Array();
			for(var i = 0; i < array.length; i++) {
				if(i < index && i >= index + count) {
					BSDArrayUtils.append(newArray, array[i]);
				}
			}
			return newArray;
		}
	}, 
	
	replace: function(array, index, value) {
		array[index] = value;
	},
	
	copy: function(sourceArray, targetArray) {
		var j = targetArray.length;
		for(var i = 0; i < sourceArray.length; i++) {
			targetArray[j + i] = sourceArray[i];
		}
	},
	
	toCommaDelimitedString: function(sourceArray) {
		var value = "";
		for(var i = 0; i < sourceArray.length; i++) {
			value += sourceArray[i];
			if(i < sourceArray.length - 1) {
				value += ",";
			}
		}	
		return value;
	},
	
	insertUnique: function(array, value, index) {
		for(var i = 0; i < array.length; i++) {
			if(array[i] == value) {
				BSDArrayUtils.deleteElement(array, i);
				break;
			}
		}
		BSDArrayUtils.insert(array, value, index);
	},
	
	contains: function(array, value) {
		for(var i = 0; i < array.length; i++) {
			if(array[i] == value) {
				return true;
			}
		}
		return false;
	}
}

BSDTimeoutUtils = {
	DEPENDENCIES: new Array("BSDArrayUtils"),

	setTimeout: function(functionName, timeInMillis) {
		var argsString = BSDTimeoutUtils.getArgumentsString(2, arguments);
		window.setTimeout(functionName + argsString, timeInMillis);
	},

	setManagedTimeout: function(timeInMillis) {
		var argsString = BSDTimeoutUtils.getArgumentsString(1, arguments);
		window.setTimeout("BSDTimeoutUtils.handleTimeout" + argsString, timeInMillis);
	},
		
	timeoutManagers: new Object(),
	
	addTimeoutManager: function(newManager) {
		BSDTimeoutUtils.timeoutManagers[newManager.key] = newManager;
	},
	
	handleTimeout: function(managerKey, timeoutRequestId) {

		var manager = BSDTimeoutUtils.timeoutManagers[managerKey];
		if(!manager) {
			alert("Couldn't find timeout manager with key: " + managerKey);
			return;
		}
		manager.handleTimeout(timeoutRequestId);
	},
	
	getArgumentsString: function(beginningIndex, argsArray) {
		var argsString = "(";
		for(var i = beginningIndex; i < argsArray.length; i++) {
			if(i > 1) {
				argsString += ", ";
			}
			var isString = typeof(argsArray[i]) == 'string';
			if(isString) {
				argsString += "'";
			}
			argsString += argsArray[i];
			if(isString) {
				argsString += "'";
			}
		}	
		argsString += ")";
		return argsString;
	}
	
	
}

BSDTimeoutManager = BSDClass.create();
BSDTimeoutManager.DEPENDENCIES = new Array("BSDClass", "BSDTimeoutUtils");
BSDTimeoutManager.prototype = {

	className: "BSDTimeoutManager",
	initialize: function(key) {
		this.key = key;
		this.timeoutRequestHash = new Object();
		BSDTimeoutUtils.addTimeoutManager(this);
   	},
   	
	setTimeout: function(timeoutRequest, timeoutInMillis) {
		this.timeoutRequestHash[timeoutRequest.timeoutRequestId] = timeoutRequest;
		var timeoutId = BSDTimeoutUtils.setManagedTimeout(timeoutInMillis, this.key, timeoutRequest.timeoutRequestId);
		timeoutRequest.timeoutId = timeoutId;
		return timeoutId;
	},
	
	handleTimeout: function(timeoutRequestId) {

		var timeoutRequest = this.timeoutRequestHash[timeoutRequestId];
		if(!timeoutRequest) {
			BSDLogUtils.debug("Couldn't find timeout request: " + timeoutRequestId);
			return;
		}		
		
		timeoutRequest.execute();
		timeoutRequest[timeoutRequestId] = null;
	}


}

BSDTimeoutRequest = BSDClass.create();
BSDTimeoutRequest.prototype = {

	initialize: function(timeoutRequestId, timeoutTarget, timeoutFunction, timeoutFunctionArgs) {
		this.creationDate = new Date();
		this.timeoutRequestId = timeoutRequestId;
		this.timeoutTarget = timeoutTarget;
		this.timeoutFunction = timeoutFunction;
		this.timeoutFunctionArgs = timeoutFunctionArgs;
   	},
   	
	execute: function() {

		if(this.timeoutFunction) {
			if(this.timeoutFunction.apply) {
				if(!this.timeoutFunctionArgs) {
					this.timeoutFunctionArgs = new Array(); //IE doesn't allow null args
				}
				this.timeoutFunction.apply(this.timeoutTarget, this.timeoutFunctionArgs);
			}
		}
	}


}
BSDAnimatedElement = BSDClass.create();
BSDAnimatedElement.DEPENDENCIES = new Array("BSDClass", "BSDDOMUtils", "BSDTimeoutManager", "BSDArrayUtils");
BSDAnimatedElement.prototype = {

	className: "BSDAnimatedElement",
	initialize: function(displayElement, key, animationRoutines, frequencyMilliseconds, lengthSeconds, startDelayMillis) {	
		this.displayElement = displayElement;
		this.key = key;
		this.animationRoutines = animationRoutines;
		this.frequencyMilliseconds = frequencyMilliseconds;
		this.lengthSeconds = lengthSeconds;
		this.startDelayMillis = startDelayMillis;
		this.initDate = new Date();
		
		this.timeoutManager = new BSDTimeoutManager(this.key);
		this.cumulativeRequestCount = 0;
		if(!this.frequencyMilliseconds) {
			frequencyMilliseconds = 1000;
		}

	},

	start: function() {
		this.beginTime = new Date();
		this.enabled = true;
		this.executeAnimation();
	},
	
	stop: function() {
		this.enabled = false;
	},

	executeAnimation: function() {
		var doDelay = false;
		if(this.startDelayMillis && this.initDate.getTime() + this.startDelayMillis > new Date().getTime()) {
			BSDLogUtils.debug("executingAnimation: skipping due to delay time");

		}

		var doCleanup = false;
		if(!this.enabled) {
			doCleanup = true;
		} else {
			var currentTime = new Date();
			var elapsedTime = currentTime.getTime() - this.beginTime.getTime();
			if(this.lengthSeconds && elapsedTime > this.lengthSeconds*1000) {
				doCleanup = true;
			}
		}
		
		if(!doDelay || doCleanup) {
			this.executeAnimationRoutines(doCleanup);
		}
		
		var animElement = this;
		function timeoutFunc() {
			animElement.executeAnimation();
		}
		
		if(!doCleanup) {
			var count = this.cumulativeRequestCount++;
			var arguments = null;
			var timeoutRequest = new BSDTimeoutRequest(count, animElement, timeoutFunc, arguments);
			this.timeoutManager.setTimeout(timeoutRequest, this.frequencyMilliseconds);
		}	
	},
	
	executeAnimationRoutines: function(doCleanup) {

		for(var i = 0; i < this.animationRoutines.length; i++) {
			var currentRoutine = this.animationRoutines[i];
			if(!doCleanup) {
				currentRoutine.executeAnimation(this.displayElement, this.elapsedTime);
			} else {
				currentRoutine.executeCleanup(this.displayElement, this.elapsedTime);			
			}
		}		
	
	}


}


BSDAnimatedRoutine = BSDClass.create();
BSDAnimatedRoutine.prototype = {


	initialize: function(animationFunction, animationFunctionTarget, cleanupFunction, cleanupFunctionTarget) {	
		this.animationFunction = animationFunction;
		this.animationFunctionTarget = animationFunctionTarget;
		this.cleanupFunction = cleanupFunction;
		this.cleanupFunctionTarget = cleanupFunctionTarget;
	},
	

	executeAnimation: function(displayElement, elapsedTimeMillis) {	
		if(this.animationFunction && this.animationFunctionTarget) {
			var arguments = new Array();
			BSDArrayUtils.append(arguments, displayElement);
			BSDArrayUtils.append(arguments, elapsedTimeMillis);
			this.animationFunction.apply(this.animationFunctionTarget, arguments);
		}
	},
	
	executeCleanup: function(displayElement, elapsedTimeMillis) {
		if(this.cleanupFunction && this.cleanupFunctionTarget) {
			var arguments = new Array();
			BSDArrayUtils.append(arguments, displayElement);
			BSDArrayUtils.append(arguments, elapsedTimeMillis);
			this.cleanupFunction.apply(this.cleanupFunctionTarget, arguments);
		}
	}
	

}

BSDAnimatedCharacterRoutine = BSDClass.create();
BSDAnimatedCharacterRoutine.prototype = {


	initialize: function(animatedCharacter, maxLength, clearAfterMaxReached) {	
		this.animatedCharacter = animatedCharacter;
		this.maxLength = maxLength;
		this.clearAfterMaxReached = clearAfterMaxReached;
	},
	

	executeAnimation: function(displayElement, elapsedTimeMillis) {	
		var text = BSDDOMUtils.getText(displayElement);

		if(this.maxLength && text.length >= this.maxLength) {
			text = "";
		} else {
			text += this.animatedCharacter;
		}

		BSDDOMUtils.setText(displayElement, text);
	},
	
	executeCleanup: function(displayElement, elapsedTimeMillis) {

		if(displayElement && displayElement.childNodes && displayElement.childNodes.length > 0) {
			BSDDOMUtils.addText(displayElement, "");		
		}
	}
	
	
}


BSDAnimatedCountdownRoutine = BSDClass.create();
BSDAnimatedCountdownRoutine.prototype = {

	initialize: function(lengthSeconds, callback) {	
		this.lengthSeconds = lengthSeconds
		this.callback = callback;
		this.currentLength = this.lengthSeconds
	},

	executeAnimation: function(displayElement, elapsedTimeMillis) {	

		if(!this.currentLength) {
			return;
		}
		var text = "" + this.currentLength;

		BSDDOMUtils.setText(displayElement, text);
		this.currentLength--;
	},
	
	executeCleanup: function(displayElement, elapsedTimeMillis) {
		this.callback.apply();
	}
	
} 

BSDAnimatedOpacityRoutine = BSDClass.create();
BSDAnimatedOpacityRoutine.prototype = {


	initialize: function(opacityIncrement, maxOpacity) {	
		if(!opacityIncrement) {
			opacityIncrement = .1;
		}
		this.opacityIncrement = opacityIncrement;
		this.maxOpacity = maxOpacity;
	},
	

	executeAnimation: function(displayElement, elapsedTimeMillis) {	
		var currentOpacity = BSDDOMUtils.getElementStyle(displayElement, "opacity");
		if(!currentOpacity) {
			currentOpacity = 0;
		} else {
			currentOpacity = parseFloat(currentOpacity);
		}
		if(this.maxOpacity && this.maxOpacity <= currentOpacity + this.opacityIncrement) {
			return;
		}
		currentOpacity = currentOpacity + this.opacityIncrement;

		BSDDOMUtils.changeElementStyle(displayElement, "opacity", currentOpacity);
		
	},
	
	executeCleanup: function(displayElement, elapsedTimeMillis) {

	}
	
	
}

BSDContentRatingEditorMessages = BSDClass.create();
BSDContentRatingEditorMessages.DEPENDENCIES = new Array("BSDClass", "BSDDOMUtils", "BSDVisibilityUtils", "BSDLogUtils", "BSDHighlightUtils", "BSDArrayUtils", "animation/BSDAnimatedElement");
BSDContentRatingEditorMessages.prototype = {

	className: "BSDFiveStarContentRatingEditor",
	initialize: function(editorElement, type, isBinaryChoice, containerElementId) {
		this.editorElement = editorElement;
		this.type = type;

		
		if(!this.editorElement || !this.type) {
			return;
		}

		this.statusContainer = BSDDOMUtils.getObjectByIdFromParent(editorElement, "CONTENT_RATING_STATUS");
		if(!this.statusContainer) {
			BSDLogUtils.error("ERROR: Couldn't find status container");
			return;
		}
		
		this.message = 'You must <a href="/login">login</a> to give a rating';
		
		if(!isBinaryChoice) {
			this.initializeImages();
		} else {
			this.initializeYesButton();
			this.initializeNoButton();
		}
		this.initializeInappropriateButton();

		this.submitAnimationRoutines = new Array();
		BSDArrayUtils.append(this.submitAnimationRoutines, new BSDAnimatedCharacterRoutine(" .", 13));

		this.messageTimeoutRoutines = new Array();
		BSDArrayUtils.append(this.messageTimeoutRoutines, new BSDAnimatedRoutine(null, null, this.cleanupStatusAnimatedElement, this));

	},

  	initializeImages: function() {

		var images = BSDDOMUtils.getObjectsByClass("CONTENT_RATING_IMAGE", this.editorElement);
		if(images.length < 1) {
			BSDLogUtils.error("ERROR: didn't get any images for FiveStarContentRatingEditor");
			return;
		}
		for(var i = 0; i < images.length; i++) {
			this.initializeImage(images[i]);
		}
	},
	
	initializeImage: function(image) {
		var editor = this;
  		function imageClickHandler(e) {

			editor.doMessage(editor.message, "saveRatingStatusError");	 
			BSDEventUtils.stopPropagation(e);
			return false;			
		}
		BSDEventUtils.registerEvent(image, "click", imageClickHandler);

		this.initializeImageHover(image);
  	},
  	
  	
  	initializeImageHover: function(image) {
		function imageMouseoverHandler(e) {

			var imageSrc = image.src;
			if(!image.originalSrc) {
				image.originalSrc = imageSrc;
			}
			var newSrc;
			if(image.highlightSrc) {
				newSrc = image.highlightSrc;
			} else {
				newSrc = imageSrc.replace(/\.gif$/i, 'Active.gif');
				newSrc = newSrc.replace(/\.jpg$/i, 'Active.jpg');
				image.highlightSrc = newSrc;
			}

			BSDDOMUtils.setAttributeValue(image, "src", newSrc);

			return false;			
		}  		

		function imageMouseoutHandler(e) {

			if(image.originalSrc) {
				image.src = image.originalSrc;
			}
			return false;			
		}  		
		
		BSDEventUtils.registerEvent(image, "mouseover", imageMouseoverHandler);
		BSDEventUtils.registerEvent(image, "mouseout", imageMouseoutHandler);
  	
  	},  	

  	initializeInappropriateButton: function() {
		var buttons = BSDDOMUtils.getObjectsByClass("CONTENT_RATING_INAPPROPRIATE_BUTTON", this.editorElement);
		if(buttons.length < 1) {
			BSDLogUtils.error("ERROR: didn't get any inappropriate buttons for FiveStarContentRatingEditor");
			return;
		}

		this.inappropriateButton = buttons[0];
  	
  		if(!this.inappropriateButton) {
  			return;
  		}
  		
		var editor = this;
		function inappropriateButtonClickHandler(e) {
			BSDLogUtils.debug("Got inappropriate click");
			editor.doMessage(editor.message, "saveRatingStatusError");	 
			BSDEventUtils.stopPropagation(e);
			return false;			
		}  		


		BSDEventUtils.registerEvent(this.inappropriateButton, "click", inappropriateButtonClickHandler);
  	},
  	
  	initializeYesButton: function() {
		var buttons = BSDDOMUtils.getObjectsByClass("CONTENT_RATING_YES_BUTTON", this.editorElement);
		if(buttons.length < 1) {
			BSDLogUtils.error("ERROR: didn't get any yes buttons for BinaryChoiceContentRatingEditor");
			return;
		}

		this.yesButton = buttons[0];
  	
  		if(!this.yesButton) {
  			return;
  		}
  		
		var editor = this;
		function yesButtonClickHandler(e) {
			BSDLogUtils.debug("Got yes click");
			editor.doMessage(editor.message, "saveRatingStatusError");	 
			BSDEventUtils.stopPropagation(e);
			return false;			
		}  		


		BSDEventUtils.registerEvent(this.yesButton, "click", yesButtonClickHandler);
  	},  	

  	initializeNoButton: function() {
		var buttons = BSDDOMUtils.getObjectsByClass("CONTENT_RATING_NO_BUTTON", this.editorElement);
		if(buttons.length < 1) {
			BSDLogUtils.error("ERROR: didn't get any no buttons for BinaryChoiceContentRatingEditor");
			return;
		}

		this.noButton = buttons[0];
  	
  		if(!this.noButton) {
  			return;
  		}
  		
		var editor = this;
		function noButtonClickHandler(e) {
			editor.doMessage(editor.message, "saveRatingStatusError");	 
			BSDEventUtils.stopPropagation(e);
			return false;			
		}  		


		BSDEventUtils.registerEvent(this.noButton, "click", noButtonClickHandler);
  	},  	
  	 	

  	
  	doMessage: function(message, messageClass) {
		this.cleanupStatusAnimatedElement();
		
	  	this.statusElement = BSDDOMUtils.createElement("span", this.statusContainer);
  		this.statusElement.innerHTML = message;  
  		this.statusElement.className = messageClass;  		 			
	 	this.statusAnimatedElement = new BSDAnimatedElement(this.statusElement, this.pageURL, this.messageTimeoutRoutines, 3000, 3);
		this.statusAnimatedElement.start();  		

		  	
  	},
  	
   	cleanupStatusAnimatedElement: function() {

  		if(this.statusAnimatedElement) {
			this.statusAnimatedElement.stop();
			this.statusAnimatedElement = null;
		}
		if(this.statusElement && this.statusElement.parentNode) {
	  		this.statusElement.parentNode.removeChild(this.statusElement);
			this.statusElement = null;
		}
		if(this.statusProgressElement) {
			if(this.statusProgressElement.parentNode) {
				this.statusProgressElement.parentNode.removeChild(this.statusProgressElement);
			}
			this.statusProgressElement = null;
		}
		if(this.statusContainer) {
			BSDDOMUtils.clear(this.statusContainer);
		}
  	} 	
  	
  	
}


BSDContentRatingEditorMessages.initializeRatingEditorMessages = function(className, type, isBinaryChoice) {
	var elements = BSDDOMUtils.getObjectsByClass(className);

	for(var i = 0; i < elements.length; i++) {
		var currentElement = elements[i];
		var newEditor = new BSDContentRatingEditorMessages(currentElement, type, isBinaryChoice);			
	}
		
}
