/*
	This file was created by Tim Schottler and is not to be used, distributed, or modified without his consent.
	I'll track you down and steal your soul.
	tim@siteengine2.com
*/
//////////////////// *LIBRARY ////////////////////
var Library = {
	ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)'
}

var Page = {
	keepingAlive: '',
	keepAlive: function(arg){
		this.keepingAlive = setTimeout('Page.keepAlive(true)',600000);
		if(arg == true) new Ajax('/keepalive.cfm?ts='+new Date(),{});
	},
	showDebugMsg: function(msg){
		var DebugDiv = Elem.create('div',{className: 'DebugDiv'});
		
		var DebugDivBG = Elem.create('div',{className: 'DebugDivBG'});
		Elem.append(DebugDiv,DebugDivBG);
		
		var DebugDivBox = Elem.create('div',{className: 'DebugDivBox',innerHTML: msg});
		Elem.append(DebugDiv,DebugDivBox);
		
		var DebugDivX = Elem.create('div',{className: 'DebugDivX'});
		DebugDivX.onmousedown = function(){
			Elem.remove(this.parentNode.parentNode);
		}
		Elem.prepend(DebugDivBox,DebugDivX);
		
		Elem.prepend(document.body,DebugDiv);
		new Drag(DebugDivBox);
	}
}

//////////////////// *JS_EXTENSION ////////////////////
String.prototype.stripScripts = function(){
	return this.replace(new RegExp(Library.ScriptFragment, 'img'), '');
}
String.prototype.evalScripts = function(){
	var matchAll = new RegExp(Library.ScriptFragment, 'img');
	var matchOne = new RegExp(Library.ScriptFragment, 'im');
	var matches = this.match(matchAll);
	var results = [];
	try {
		for(var i=0; i<matches.length; i++)
			eval(matches[i].match(matchOne)[1]);
	} catch(e){}
}
String.prototype.replaceAll = function(str1,str2){
	var str = this;
	while(str.indexOf(str1) != -1)
		str = str.replace(str1,str2);
	return str;
}
Array.prototype.indexOf = function(obj){
	for(var i=0; i<this.length; i++)
		if(this[i] == obj) return i;
	return -1;
}

//////////////////// *CLASS ////////////////////
var Class = {
	create: function(){
		return function(){
			this.init.apply(this, arguments);
		}
	},
	extend: function(parent,child){
		for(var i in parent){
			if(!child[i]) child[i] = parent[i];
			else child[i+'_base'] = parent[i];
		}
		return child;
	}
}


//////////////////// *TRY ////////////////////
var Try = {
	these: function(){
		var r = false;
		for(var i=0; i<arguments.length; i++){
			try {
				r = arguments[i]();
				break;
			}catch(e){}
		}
		return r;
	}
}


//////////////////// *EVENT ////////////////////
// Mozilla has an Event object, ie is gay and does not.
if(!Event){
	var Event = {};
}
Event = Class.extend(Event,{
	pageLoaded: false,
	observe: function(obj,e,func){
		obj = $(obj);
		if(obj.attachEvent){
			e = 'on'+e;
			obj.attachEvent(e,func);
		} else if(obj.addEventListener){
			obj.addEventListener(e,func,false);
		}
	},
	stop: function(e,dontPreventDefault){
		if(e.preventDefault){
			e.stopPropagation();
			if(!dontPreventDefault)
				e.preventDefault();
		} else {
			if(!dontPreventDefault)
				e.returnValue = false;
			e.cancelBubble = true;
		}
	},
	getModifiers: function(e){
		return {
			ALT: e.altKey,
			CTRL: e.ctrlKey,
			SHIFT: e.shiftKey
		}
	}
});


//////////////////// *SERIALIZER ////////////////////
var Serializer = {
	toJSString: function(obj,includeFuncs){
		if(includeFuncs == undefined) includeFuncs = false;
		if(typeof(obj) == 'array')
			return this.arrayToJSString(obj,includeFuncs);
		else if(typeof(obj) == 'object')
			return this.objectToJSString(obj,includeFuncs);
	},
	arrayToJSString: function(obj,includeFuncs){
		if(includeFuncs == undefined) includeFuncs = false;
		var str = '[';
		for(var i=0; i<obj.length; i++){
			if(i>0) str += ',';
			var ival = obj[i];
			var itype = typeof(obj[i]);
			if(itype == 'object' || itype == 'array'){
				str += this.toJSString(ival,includeFuncs);
			} else if(itype == 'function' && includeFuncs){
				str += ival;
			} else if(itype != 'function'){
				str += '\''+ival+'\'';
			}
		}
		str += ']';
		return str;
	},
	objectToJSString: function(obj,includeFuncs){
		if(includeFuncs == undefined) includeFuncs = false;
		var str = '{';
		var j=0;
		for(var i in obj){
			if(j>0) str += ',';
			var ival = obj[i];
			var itype = typeof(obj[i]);
			if(itype == 'object' || itype == 'array'){
				str += i+': ';
				str += this.toJSString(ival,includeFuncs);
			} else if(itype == 'function' && includeFuncs && i != 'toJSString'){
				str += i+': ';
				str += ival;
			} else if(itype != 'function'){
				str += i+': ';
				str += '\''+ival+'\'';
			}
			j++;
		}
		str += '}';
		return str;
	}
}


//////////////////// *ELEM ////////////////////
var Elem = {
	create: function(tag,init){
		var elem = document.createElement(tag);
		if(init){
			for(var i in init){
				if(i == 'attributes'){
					for(var j in init[i]) elem.setAttribute(j,init[i][j]);
				} else {
					elem[i] = init[i];
				}
			}
		}
		return elem;
	},
	remove: function(elem){
		elem = $(elem);
		elem.parentNode.removeChild(elem);
	},
	get: function(tag,parent,matchObj){
		if(!tag) tag = '*';
		if(!parent) parent = document;
		else parent = $(parent);
		var elems = parent.getElementsByTagName(tag);
		var r = [];
		if(!matchObj) r = elems;
		for(var i=0; i<elems.length; i++){
			var elem = elems[i];
			for(var j in matchObj){
				if(j == 'attributes'){
					for(var k in matchObj[j]){
						if(elem.getAttribute(k) == matchObj[j][k]){
							r.push(elem);
							break;
						}
					}
				} else {
					if(j == 'className'){
						if(Elem.hasClassName(elem,matchObj[j])){
							r.push(elem);
							break;
						}
					} else if(elem[j] == matchObj[j]){
						r.push(elem);
						break;
					}
				}
			}
		}
		return r;
	},
	addClassName: function(elem,c){
		elem = $(elem);
		if(elem.className == undefined) return;
		if(!Elem.hasClassName(elem,c)) elem.className = elem.className + ' ' + c;
	},
	removeClassName: function(elem,c){
		elem = $(elem);
		if(elem.className == undefined) return;
		var cArr = elem.className.split(' ');
		for(var i=0; i<cArr.length; i++){
			if(cArr[i] == c){
				cArr.splice(i,1);
				break;
			}
		}
		elem.className = cArr.join(' ');
	},
	hasClassName: function(elem,c){
		elem = $(elem);
		if(!elem.className) return;
		var cArr = elem.className.split(' ');
		var has = false;
		for(var i=0; i<cArr.length; i++){
			if(cArr[i] == c){
				has = true;
				break;
			}
		}
		return has;
	},
	toggleClassName: function(elem,c){
		if($(elem).className == undefined) return;
		Elem[Elem.hasClassName(elem,c) ? 'removeClassName' : 'addClassName'](elem,c);
	},
	update: function(elem,html,stripScripts){
		elem = $(elem);
		elem.innerHTML = html.stripScripts();
		if(!stripScripts){
			setTimeout(function(){html.evalScripts()}, 10);
		}
	},
	empty: function(elem){
		elem = $(elem);
		try {
			elem.innerHTML = '';
		} catch(e) {
			var elems = elem.getElementsByTagName('*');
			for(var i=0; i<elems.length; i++){
				elem.removeChild(elems[i]);
			}
		}
	},
	prepend: function(elem,node){
		elem = $(elem);
		elem.insertBefore(node,elem.firstChild);
	},
	append: function(elem,node){
		elem = $(elem);
		elem.appendChild(node);
	},
	setOpacity: function(elem,opacity){
		elem = $(elem);
		elem.style.opacity = opacity/100;
		elem.style.filter = 'alpha(opacity='+opacity+')';
	},
	visible: function(elem){
		return $(elem).style.display != 'none';
	},
	toggle: function(){
		for(var i=0; i<arguments.length; i++){
			var elem = $(arguments[i]);
			Elem[Elem.visible(elem) ? 'hide' : 'show'](elem);
		}
	},
	hide: function(){
		for(var i=0; i<arguments.length; i++)
			$(arguments[i]).style.display = 'none';
	},
	show: function(){
		for(var i=0; i<arguments.length; i++)
			$(arguments[i]).style.display = '';
	},
	getChildren: function(elem){
		elem = $(elem);
		if(elem.children) return elem.children;
		var elems = [];
		var c = elem.childNodes;
		for(var i=0; i<c.length; i++){
			var n = c[i];
			if(n.nodeName != '#text') elems.push(n);
		}
		return elems;
	},
	getLastChild: function(elem){
		elem = $(elem);
		var lastChild = elem.lastChild;
		while(lastChild.nodeName == '#text')
			lastChild = lastChild.previousSibling;
		return lastChild;
	}
}


//////////////////// *FORM ////////////////////
var Form = {
	getForm: function(frm){
		if(frm) frm = $(frm);
		else if(document.forms[0]) frm = document.forms[0];
		return frm;
	},
	addSubmitEvent: function(frm,func){
		Event.observe(frm,'submit',func);
	},
	focusFirstElement: function(){
		for(var i=0; i<document.forms.length; i++){
			var frm = document.forms[i];
			if(frm && frm.elements && frm.elements.length){
				for(var j=0; j<frm.elements.length; j++){
					var input = frm.elements[j];
					if(input.type != 'hidden' && input.getAttribute('disallowautofocus') == null && input.type != 'button' && input.type != 'submit' && Elem.visible(input)){
						try {
							input.focus();
							return;
						}catch(e){
						}
					}
				}
			}
		}
	},
	serialize: function(frm){
		frm = Form.getForm(frm);
		var str = '';
		if(frm && frm.length){
			for(var i=0; i<frm.length; i++){
				var input = frm[i];
				if(input.type == 'checkbox'
				   || (input.type == 'select' && input.multiple)){
					
					if(!this.serializedInputs[input.name]){
						str += input.name + '=' + encodeURIComponent(this.serializeInput(input));
						if(i<frm.length) str += '&';
					}
					
				} else {
					str += input.name + '=' + encodeURIComponent(this.serializeInput(input));
					if(i<frm.length) str += '&';
				}
				this.serializedInputs[input.name] = true;
			}
			this.serializedInputs = {};
			return str;
		}
	},
	serializedInputs: {},
	serializeInput: function(input){
		input = $(input);
		if(input.value == undefined) return;
		
		var str = '';
		
		if(input.type == 'checkbox'
		   || (input.type == 'select' && input.multiple)){
			var values = [];
			for(var i=0; i<input.form[input.name].length; i++){
				var subinput = input.form[input.name][i];
				if(subinput.type == 'checkbox' && subinput.checked)
					values.push(input.form[input.name][i].value);
				else if(subinput.type == 'select' && subinput.selected)
					values.push(input.form[input.name][i].value);
			}
			str = values.join(',');
		} else {
			str = input.value;
		}
		return str;
	},
	validate: function(frm){
		for(var i=0; i<frm.elements.length; i++){
			if(Form.validateInput(frm.elements[i],true) == false) return false;
		}
		return true;
	},
	validateInput: function(input,applyfocus){
		input = $(input);
		
		var required = input.getAttribute('required');
		required = required == 1 ? true : false;
		if(input.type == 'checkbox') required = false;
		
		var validation = input.getAttribute('validation');
		if(validation == '' || validation == ' ' || validation == null) validation = 'required';
		if(input.type != 'text' && input.type != 'textarea') validation = 'required';
		validation = validation.toLowerCase();
		
		var value = "";
		var valid = true;
		
		if(input.type == 'radio' || input.type == 'checkbox'){
			if(input.checked) value = input.value;
			for(var i=0; i<input.form.elements.length; i++){
				var cinput = input.form.elements[i];
				if(cinput.name == input.name && cinput.checked){
					valid = Valid[validation](cinput.value,required);
					break;
				}
			}
		} else {
			value = input.value;
			valid = Valid[validation](value,required);
		}
		
		if(!input.form.errormsgs) input.form.errormsgs = {};
		if(!valid){
			// slap up an error message
			if(!input.form.errormsgs[input.name]){
				var msg = Form.errorMessage(input.getAttribute('message'),validation);
				Elem.addClassName(input,'invalid');
				input.form.errormsgs[input.name] = Elem.create('span',{className:'inputerror',innerHTML:msg})
				Elem.append(input.parentNode,input.form.errormsgs[input.name]);
			}
			if(applyfocus && Elem.visible(input)){
				try {
					input.focus();
				}catch(e){
				}
			}
			return false;
		}
		
		if(input.form.errormsgs[input.name]){
			// remove error message if it exists - the user fixed the input
			Elem.removeClassName(input,'invalid');
			Elem.remove(input.form.errormsgs[input.name]);
			input.form.errormsgs[input.name] = false;
		}
		
		return true;
	},
	errorMessage: function(msg,validation,input){
		if(msg == '' || msg == null){
			switch(validation){
				case 'numeric':
					msg = 'Please enter a valid number.';
					break;
				case 'email':
					msg = 'Please enter a valid email address.';
					break;
				case 'phone':
					msg = 'Please enter a valid US phone number.';
					break;
				case 'zip':
					msg = 'Please enter a valid US Zip Code.';
					break;
				case 'ssn':
					msg = 'Please enter a valid social security number.';
					break;
				case 'guid':
					msg = 'Please enter a valid GUID.';
					break;
				case 'uuid':
					msg = 'Please enter a valid UUID.';
					break;
				default:
					msg = 'Please fill all required fields.';
					break;
			}
		}
		return msg;
	},
	hideSelects: function(){
		if(!document.getElementById || !document.all) return false;
		for(var i=0; i<document.forms.length; i++){
			var frm = document.forms[i];
			for(var j=0; j<frm.elements.length; j++){
				var input = frm.elements[j];
				if(input.type.indexOf('select') != -1) input.style.visibility = "hidden";
			}
		}
	},
	showSelects: function(){
		if(!document.getElementById || !document.all) return false;
		for(var i=0; i<document.forms.length; i++){
			var frm = document.forms[i];
			for(var j=0; j<frm.elements.length; j++){
				var input = frm.elements[j];
				if(input.type.indexOf('select') != -1) input.style.visibility = "visible";
			}
		}
	},
	checkAll: function(name){
		var frm = $(name).form;
		var field = frm[name];
		for(var i=0; i<field.length; i++)
			field[i].checked = true;
	},
	uncheckAll: function(name){
		var frm = $(name).form;
		var field = frm[name];
		for(var i=0; i<field.length; i++)
			field[i].checked = false;
	}
}


//////////////////// *INPUT ////////////////////
var Input = {
	removeOptions: function(input){
		input = $(input);
		input.length = 0;
		return true;
	},
	addOption: function(input,label,value){
		input = $(input);
		input.length++;
		input.options[input.length-1].text = label;
		input.options[input.length-1].value = value;
		return true;
	},
	validateLength: function(input,maxlength){
		input = $(input);
		if(input.value.length > maxlength) input.value = input.value.substr(0,maxlength);
		var valspan = $(input.name+'_indicator');
		if(valspan != undefined && valspan != null)
			Elem.update(valspan,(maxlength-input.value.length)+' characters remaining.');
	},
	// this function is not complete - need to add support for all input types
	// right now it's just button,text,password,submit
	create: function(type,name,value,init){
		var type = type.toLowerCase();
		var str = '';
		var optionalAttrs = '';
		if(init == undefined) init = {};
		var csstype = 'text';
		if(type == 'button'
		   || type == 'text'
		   || type == 'password'
		   || type == 'submit'
		   || type == 'textarea'
		   || type == 'reset'){
			if(type == 'button' || type == 'submit' || type == 'reset')
				csstype = 'button';
			if(!init.onmouseover) init.onmouseover = '';
			init.onmouseover += 'try{Elem.addClassName(this,\''+csstype+'over\');}catch(e){};';
			if(!init.onmouseout) init.onmouseout = '';
			init.onmouseout += 'try{Elem.removeClassName(this,\''+csstype+'over\');}catch(e){};';
			if(!init.onfocus) init.onfocus = '';
			init.onfocus += 'try{Elem.addClassName(this,\''+csstype+'focused\');}catch(e){};';
			if(!init.onblur) init.onblur = '';
			init.onblur += 'try{Elem.removeClassName(this,\''+csstype+'focused\');}catch(e){};';
		}
		for(var i in init){
			if(i != 'options' && i != 'checked'){
				optionalAttrs += ' '+i+'="'+init[i]+'"';
			} else if(i == 'checked'){
				if(init[i] == true)
					optionalAttrs += ' checked="checked"';
			}
		}
		switch(type){
			case 'button':
			case 'text':
			case 'password':
			case 'submit':
			case 'reset':
			case 'checkbox':
			case 'hidden':
				str = '<input type="'+type+'" name="'+name+'" id="'+name+'" value="'+value+'" class="'+csstype+'"';
				str += optionalAttrs;
				str += '/>';
				break;
			case 'textarea':
				str = '<textarea name="'+name+'" id="'+name+'" class="'+csstype+'"';
				str += optionalAttrs;
				str += '>'+value+'</textarea>';
				break;
			case 'select':
			case 'selectmultiple':
				str = '<select';
				if(type == 'selectmultiple')
					str += ' multiple="multiple"';
				str += ' name="'+name+'" id="'+name+'"';
				str += optionalAttrs;
				str += '>';
				if(!init.options) init.options = [];
				for(var i=0; i<init.options.length; i++){
					var opt = init.options[i];
					var val = opt;
					var lab = opt;
					if(typeof opt == 'object'){
						val = opt.value;
						lab = opt.label;
					}
					str += '<option value="'+val+'"';
					if(value == val)
						str += ' selected="selected"';
					str += '>'+lab+'</option>';
				}
				str += '</select>';
				break;
			case 'checkboxgroup':
			case 'radiogroup':
				for(var i=0; i<init.options.length; i++){
					var opt = init.options[i];
					var val = opt;
					var lab = opt;
					if(typeof opt == 'object'){
						val = opt.value;
						lab = opt.label;
					}
					str += '<input type="'+(type=='checkboxgroup' ? 'checkbox' : 'radio')+'" name="'+name+'" id="'+name+'" value="'+val+'"'
					if(value == val)
						str += ' checked="checked"';
					str += ' /> '+lab+'<br />';
				}
				break;
		}
		return str;
	}
}


//////////////////// *COOKIES ////////////////////
var Cookie = {
	create: function(name,value,days){
		if (days){
			var date = new Date();
			date.setTime(date.getTime()+(days*24*60*60*1000));
			var expires = "; expires="+date.toGMTString();
		} else {
			var expires = "";
		}
		document.cookie = name+"="+value+expires+"; path=/";
	},
	read: function(name){
		var nameEQ = name + "=";
		var ca = document.cookie.split(';');
		for(var i=0;i < ca.length;i++)
		{
			var c = ca[i];
			while (c.charAt(0)==' ') c = c.substring(1,c.length);
			if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
		}
		return null;
	}
}


//////////////////// *DRAG ////////////////////
var Drag = Class.create();
Drag.prototype = {
	cookieName: false,
	init: function(elem, cookieName) {
		this.elem = $(elem);
		var me = this;
		this.elem.onmousedown = function(e){me.mouseDown(e)};
		this.elem.onmouseup = function(e){me.mouseDown(e)};
		if(cookieName){
			this.cookieName = cookieName;
			var elemPos = Cookie.read(this.cookieName);
			if(elemPos != null && elemPos != ''){
				elemPos = elemPos.split(',');
				elemPos = {left:elemPos[0], top:elemPos[1]};
			} else {
				elemPos = {left:20, top:20};
			}
			this.elem.style.left = elemPos.left;
			this.elem.style.top = elemPos.top;
		}
	},
	mouseDown: function(e){
		var e = e || window.event;
		var startWinX = this.elem.offsetLeft;
		var startWinY = this.elem.offsetTop;
		var startMouseX = e.clientX;
		var startMouseY = e.clientY;
		
		var me = this;
		document.onmousemove = function(e){
			var e = e || window.event;
			me.elem.style.left = (startWinX - (startMouseX - e.clientX)) + 'px';
			me.elem.style.top = (startWinY - (startMouseY - e.clientY)) + 'px';
			Event.stop(e);
		}
		document.onmouseup = function(e){
			document.onmousemove = null;
			document.onmouseup = null;
			if (me.cookieName){
				Cookie.create(me.cookieName, me.elem.style.left + "," + me.elem.style.top, 100);
			}
		}
	}
}


//////////////////// *AJAX ////////////////////
var Ajax = Class.create();
Ajax.getTransport = function(){
	return Try.these(
		function(){return new ActiveXObject('Msxml2.XMLHTTP')},
		function(){return new ActiveXObject('Microsoft.XMLHTTP')},
		function(){return new XMLHttpRequest()}
	) || false;
}
Ajax.getCFC = function(cfc,method){
	return cfc+'?method='+method+'&ts='+new Date().getTime();
}
Ajax.prototype = {
	init: function(url,params){
		this.method = params.method || "get";
		this.method = this.method.toLowerCase();
		this.args = params.args || {};
		this.success = params.success || function(){};
		this.error = params.error || function(xhr){
			Page.showDebugMsg('<h2>AJAX Response - Error</h2>'+xhr.responseText);
		};
		this.stripScripts = params.stripScripts || false;
		if(typeof this.args == 'object'){
			var paramstring = "";
			for(var i in this.args){
				if(typeof this.args[i] != 'object' && typeof this.args[i] != 'function')
					paramstring += i+"="+encodeURIComponent(this.args[i])+"&";
			}
		}
		this.container = params.container || false;
		this.XHR = Ajax.getTransport();
		var me = this;
		this.XHR.onreadystatechange = function(){me.checkState()};
		if(this.method == 'get'){
			if(url.indexOf('?') != -1)
				url += '&';
			else
				url += '?';
			url += paramstring;
		}
		this.XHR.open(this.method, url, true);
		if(this.method == 'post') this.XHR.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		this.XHR.send(paramstring);
	},
	checkState: function(){
		if(this.XHR.readyState == 4){
			if(this.XHR.status == 200){
				if(this.container) Elem.update(this.container,this.XHR.responseText,this.stripScripts);
				this.success(this.XHR);
				return;
			}
			this.error(this.XHR);
		}
	}
}


//////////////////// *UI ////////////////////
var UI = {
	init: function(){
		var tabs = $G('div',document,{className:'UITab'});
		for(var i=0; i<tabs.length; i++)
			new UI.Tab(tabs[i]);
			
		var trees = $G('ul',document,{className:'UITree'});
		for(var i=0; i<trees.length; i++){
			if(trees[i].getAttribute('id') != 'filebrowser')
				new UI.Tree(trees[i]);
		}
	},
	getLoadingMsg: function(msg){
		if(!msg) msg = 'Loading..';
		return '<p class="message loading">'+msg+'</p>';
	}
}


//////////////////// *UI_MENU ////////////////////
UI.Menu = Class.create();
UI.Menu.instances = [];
UI.Menu.prototype = {
	params: {icons:true,hideselects:false},
	iconFolder: '/global/images/icons/',
	init: function(elem,params){
		UI.Menu.instances.push(this);
		
		this.current = [];
		if(params){
			for(i in params){
				this.params[i] = params[i];
			}
		}
		
		elem = $(elem);
		if(this.params.hideselects && document.getElementById && document.all){
			elem.onmouseover = Form.hideSelects;
			elem.onmouseout = Form.showSelects;
		}
		var lis = $G('li',elem);
		for(var i=0; i<lis.length; i++){
			var li = lis[i];
			var level = 0;
			while(li.parentNode.nodeName.toLowerCase() == 'li' || li.parentNode.nodeName.toLowerCase() == 'ul'){
				level++;
				li = li.parentNode.parentNode;
			}
			this.addChild(lis[i],level);
		}
	},
	addChild: function(elem,level){
		new UI.Menu.Child(this,elem,level);
	},
	setCurrentPage: function(li_id){
		var menu = $(li_id);
		while(menu.parentNode.nodeName.toLowerCase() == 'li' || menu.parentNode.nodeName.toLowerCase() == 'ul') {
			Elem.addClassName(menu,'on');
			Elem.addClassName(menu.firstChild,'on');
			menu = menu.parentNode.parentNode;
		}
	}
}
UI.Menu.Child = Class.create();
UI.Menu.Child.prototype = {
	init: function(parent,elem,level){
		var me = this;
		this.parent = parent;
		this.level = level;
		this.timeout = null;
		this.container = elem;
		this.a = $G('a',elem)[0];
		this.ul = $G('ul',elem);
		this.ul.length ? this.ul = this.ul[0] : this.ul = {};
		this.a.onmouseover = function(){me.show()};
		this.ul.onmouseover = function(){me.reset()};
		this.a.onmouseout = this.ul.onmouseout = function(){me.hide()};
		this.icon = this.container.getAttribute('icon');
		if(this.parent.params.icons){
			if(this.icon){
				var span = Elem.create('span');
				span.className = 'navicon';
				span.style.backgroundImage = 'url("/global/images/icons/'+this.icon+'")';
				Elem.prepend(this.a,span);
				this.a.style.textIndent = '0px';
			}
		}
		if(this.ul.style){
			Elem.addClassName(this.a,'expandable');
		}
	},
	show: function(e){
		try {
			this.reset();
			var parent = this.parent;
			var lvl = this.level;
			if(parent.current[lvl]) parent.current[lvl].kill();
			parent.current[lvl] = this;
			Elem.addClassName(this.container,'over');
			Elem.addClassName(this.a,'over');
			if(this.ul.style) Elem.addClassName(this.ul,'over');
		}catch(e){}
	},
	hide: function(e){
		try {
			var me = this;
			if(this.ul.style){
				this.timeout = setTimeout(function(){me.kill()},700);
			} else {
				this.kill();
			}
		}catch(e){}
	},
	kill: function(e){
		Elem.removeClassName(this.container,'over');
		Elem.removeClassName(this.a,'over');
		if(this.ul.style) Elem.removeClassName(this.ul,'over');
	},
	reset: function(e){
		if(this.timeout) clearTimeout(this.timeout);
	}
}


//////////////////// *SHORTCUTS ////////////////////
var $ = function(elem){
	if(typeof elem == 'string') elem = document.getElementById(elem);
	return elem;
}
var $G = Elem.get;
var $F = Form.serializeInput;
var $L = function(func){
	if(!Event.pageLoaded)
		Event.observe(window,'load',func);
	else
		setTimeout(func,10);
}
$L(function(){Event.pageLoaded=true;});


//////////////////// *VALIDATION ////////////////////
var Valid = {
	required: function(value,required){
		if((value == null || !value.length) && required) return false;
		return true;
	},
	numeric: function(value,required){
		var requiredvalid = Valid.required(value,required);
		if(requiredvalid && value.length) return !isNaN(value);
		else return requiredvalid;
	},
	email: function(value,required){
		return Valid.regex(value, /^[a-zA-Z_0-9-'\+~]+(\.[a-zA-Z_0-9-'\+~]+)*@([a-zA-Z_0-9-]+\.)+[a-zA-Z]{2,7}$/, required);
	},
	phone: function(value,required){
		return Valid.regex(value, /^(((1))?[ ,\-,\.]?([\\(]?([1-9][0-9]{2})[\\)]?))?[ ,\-,\.]?([^0-1]){1}([0-9]){2}[ ,\-,\.]?([0-9]){4}(( )((x){0,1}([0-9]){1,5}){0,1})?$/, required);
	},
	zip: function(value,required){
		return Valid.regex(value, /^([0-9]){5,5}$|(([0-9]){5,5}(-| ){1}([0-9]){4,4}$)/, required);
	},
	ssn: function(value,required){
		return Valid.regex(value, /^[0-9]{3}(-| )?[0-9]{2}(-| )?[0-9]{4}$/, required);
	},
	guid: function(value,required){
		return Valid.regex(value, /[A-Fa-f0-9]{8,8}-[A-Fa-f0-9]{4,4}-[A-Fa-f0-9]{4,4}-[A-Fa-f0-9]{4,4}-[A-Fa-f0-9]{12,12}/, required);
	},
	uuid: function(value,required){
		return Valid.regex(value, /[A-Fa-f0-9]{8,8}-[A-Fa-f0-9]{4,4}-[A-Fa-f0-9]{4,4}-[A-Fa-f0-9]{16,16}/, required);
	},
	url: function(value,required){
		return Valid.regex(value, /^((http|https|ftp|file)\:\/\/([a-zA-Z0-0]*:[a-zA-Z0-0]*(@))?[a-zA-Z0-9-\.]+(\.[a-zA-Z]{2,3})?(:[a-zA-Z0-9]*)?\/?([a-zA-Z0-9-\._\?\,\'\/\+&amp;%\$#\=~])*)|((mailto)\:[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*@([a-zA-Z0-9-]+\.)+[a-zA-Z0-9]{2,7})|((news)\:[a-zA-Z0-9\.]*)$/, required);
	}, // '
	regex: function(value, pattern, required){
		value = value.replace(/^\s+/,'').replace(/\s+$/,'');
		
		if(!value.length && !required) return true;
		return pattern.test(value);
	}
}


//////////////////// *UI_VIDEO ////////////////////
UI.Video = Class.create();
UI.Video.prototype = {
	init: function(source,data,container,width,height){
		switch(source.toLowerCase()){
			case 'google':
				if(width == undefined) width = '100%';
				if(height == undefined) height = 326;
				new UI.SWF('http://video.google.com/googleplayer.swf?hl=en&docId='+data,container+'_SWF',width,height,8,container);
				break;
			case 'youtube':
				if(width == undefined) width = 425;
				if(height == undefined) height = 350;
				new UI.SWF('http://www.youtube.com/v/'+this.getYouTubeIDFromURL(data),container+'_SWF',width,height,8,container);
				break;
			default:
				Elem.update(container,'<p class="message error">Only google videos are supported so far.</p>');
				break;
		}
	},
	getYouTubeIDFromURL: function(URL){
		var qryStringStart = URL.indexOf('?');
		if(qryStringStart < 0)
			return URL;
		var qryString = URL.substr(qryStringStart+1,URL.length-qryStringStart);
		var argPairs = qryString.split('&');
		var args = {};
		for(var i=0; i<argPairs.length; i++){
			var argPair = argPairs[i].split('=');
			var argName = argPair[0].toLowerCase();
			var argValue = argPair[1];
			args[argName] = argValue;
		}
		if(args.v != undefined)
			return args.v;
		else
			return URL;
	}
}


//////////////////// *UI_VIDEO ////////////////////
UI.SWF = Class.create();
UI.SWF.prototype = {
	so: false,
	init: function(swf,swfID,width,height,flashVersion,container,flashVars,params){
		this.so = new SWFObject(swf,swfID,width,height,flashVersion);
		if(flashVars){
			for(i in flashVars)
				this.so.addVariable(i,flashVars[i]);
		}
		if(params){
			for(i in params)
				this.so.addParam(i,params[i]);
		}
		this.so.write($(container));
		return this;
	}
}
UI.FullScreenSWF = Class.create();
UI.FullScreenSWF.prototype = {
	init: function(swf,swfID,flashVersion,container,flashVars,params){
		if(!flashVars) flashVars = {};
		if(!params) params = {};
		flashVars.salign = 'lt';
		flashVars.scale = 'noscale';
		new UI.SWF(swf,swfID,'100%','100%',flashVersion,container,flashVars,params);
	}
}


//////////////////// *UI_TAB ////////////////////
UI.Tab = Class.create();
UI.Tab.instances = [];
UI.Tab.prototype = {
	init: function(elem,selectedtab){
		UI.Tab.instances.push(this);
		
		this.elem = $(elem);
		var containers = Elem.getChildren(this.elem);
		this.labelcontainer = containers[0];
		this.tabcontainer = containers[1];
		
		this.labels = Elem.getChildren(this.labelcontainer);
		this.tabs = Elem.getChildren(this.tabcontainer);
		
		for(var i=0; i<this.labels.length; i++){
			this.labels[i].index = i;
			this.labels[i].ref = this;
			this.labels[i].onmousedown =  this.labelClick;
		}
		try {
			this.labels[selectedtab].onclick();
		}catch(e){
		}
	},
	labelClick: function(){
		for(var i=0; i<this.ref.labels.length; i++)
			i != this.index ? this.ref.closeTab(i,this) : this.ref.openTab(i,this);
		Cookie.create('tabs_opentab_'+this.ref.elem.id,this.id,1000);
	},
	closeTab: function(index,a){
		Elem.hide(this.tabs[index]);
		Elem.removeClassName(this.labels[index],'on');
		eval(a.getAttribute('ontabblur'));
	},
	openTab: function(index,a){
		Elem.show(this.tabs[index]);
		Elem.addClassName(this.labels[index],'on');
		eval(a.getAttribute('ontabfocus'));
	}
}


//////////////////// *UI_TREE ////////////////////
UI.Tree = Class.create();
UI.Tree.instances = [];
UI.Tree.prototype = {
	init: function(elem,singleClickExpand,listeners){
		UI.Tree.instances.push(this);
		elem = $(elem);
		this.rootNode = elem;
		this.singleClickExpand = singleClickExpand;
		this.listeners = listeners || {main:{},child:{}};
		this.current = {head:{}};
		this.branches = [];
		this.initChildren(elem);
	},
	initChildren: function(parentnode){
		parentnode.isBranch = true;
		var children = Elem.getChildren(parentnode);
		for(var i=0; i<children.length; i++){
			var node = children[i];
			if(node.nodeName.toLowerCase() == 'li'){
				var isLastChild = i == children.length-1 ? true : false;
				this.initChild(node,isLastChild);
				if(node.childNodes.length > 1){
					var ul = $G('ul',node,{parentNode:node});
					if(ul.length) this.initChildren(ul[0]);
				}
			}
		}
	},
	initChild: function(elem,isLastChild){
		new UI.Tree.Child(this,elem,isLastChild,this.listeners.child,this.singleClickExpand);
	},
	expandAll: function(){
		for(var i=0; i<this.branches.length; i++)
			this.branches[i].expand();
	},
	collapseAll: function(){
		for(var i=0; i<this.branches.length; i++)
			this.branches[i].collapse();
	},
	setCurrent: function(child){
		if(this.current) Elem.removeClassName(this.current.head,'current');
		this.current = child;
		Elem.addClassName(this.current.head,'current');
	},
	getCurrent: function(){
		return this.current;
	}
}
UI.Tree.Child = Class.create();
UI.Tree.Child.prototype = {
	callListener: function(method){
		var L = this.listeners[method];
		if(L) L(this);
	},
	init: function(tree,elem,isLastChild,listeners,singleClickExpand){
		var me = this;
		this.tree = tree;
		this.container = elem;
		
		if(this.container.initialized) return;
		this.container.initialized = true;
		
		this.listeners = listeners || {};
		
		this.singleClickExpand = singleClickExpand;
		
		this.head = $G('div',elem)[0];
		this.ul = $G('ul',elem);
		this.ul.length ? this.ul = this.ul[0] : this.ul = {};
		Elem.addClassName(this.head,'leaf');
		this.head.onmouseover = function(e){
			e = e || window.event;
			me.mouseover(e);
		}
		this.head.onmouseout = function(e){
			e = e || window.event;
			me.mouseout(e);
		}
		if(isLastChild)
			Elem.addClassName(this.container,'lastchild');
		if(this.ul.style){
			Elem.addClassName(this.head,'branch');
			this.tree.branches.push(this);
			this.collapse();
		}
		this.head.onclick = function(e){
			e = e || window.event;
			me.click(e);
		}
		this.head.ondblclick = function(e){
			e = e || window.event;
			me.dblclick(e);
		}
	},
	click: function(e){
		this.tree.setCurrent(this);
		
		if(this.ul.style && this.singleClickExpand){
			this.expandcollapse();
		}
		
		this.callListener('click');
		//Event.stop(e);
	},
	dblclick: function(e){
		if(this.ul.style && !this.singleClickExpand){
			this.expandcollapse();
		}
		this.callListener('dblclick');
		Event.stop(e);
	},
	expandcollapse: function(){
		if(this.expanded){
			this.collapse();
		} else {
			this.expand();
		}
	},
	collapse: function(){
		this.expanded = false;
		Elem.hide(this.ul);
		Elem.removeClassName(this.head,'expanded');
	},
	expand: function(){
		this.expanded = true;
		Elem.show(this.ul);
		Elem.addClassName(this.head,'expanded');
	},
	mouseover: function(e){
		try {
			Elem.addClassName(this.head,'over');
			
			this.callListener('mouseover');
			Event.stop(e);
		}catch(er){}
	},
	mouseout: function(e){
		try {
			Elem.removeClassName(this.head,'over');
			
			this.callListener('mouseout');
			Event.stop(e);
		}catch(er){}
	}
}


//////////////////// *SHOWHIDEBOX ////////////////////
var ShowHideBox = {
	toggle: function(name,inputname,bool){
		Elem[bool ? 'show' : 'hide'](name);
		Elem[bool ? 'hide' : 'show'](name+'_showBtn');
		$(inputname).value = bool;
	}
}

//////////////////// *SHOWHIDEBOX ////////////////////
var Collection = {
	search: function(c,searchphrase,container){
		Elem.update(container,UI.getLoadingMsg('Searching for \''+searchphrase+'\''));
		new Ajax(Ajax.getCFC('/cfcs/Controls/Collection_Ajax.cfc','search'),{
			method: 'get',
			container: container,
			args: {
				c: c,
				searchphrase: searchphrase
			}
		});
	}
}