// ==========================================================================
// RTSB Utility Class
// ==========================================================================
/* overload core objects (careful here!) */
/* some functions taken from Douglas Crockford http://javascript.crockford.com/remedial.html */
String.prototype.trim = function () {
    return this.replace(/^\s+|\s+$/g, "");
};
String.prototype.entityify = function () {
    return this.replace(/&/g, "&amp;").replace(/</g,
        "&lt;").replace(/>/g, "&gt;");
};
String.prototype.quote = function () {
    var c, i, l = this.length, o = '"';
    for (i = 0; i < l; i += 1) {
        c = this.charAt(i);
        if (c >= ' ') {
            if (c === '\\' || c === '"') {
                o += '\\';
            }
            o += c;
        } else {
            switch (c) {
            case '\b':
                o += '\\b';
                break;
            case '\f':
                o += '\\f';
                break;
            case '\n':
                o += '\\n';
                break;
            case '\r':
                o += '\\r';
                break;
            case '\t':
                o += '\\t';
                break;
            default:
                c = c.charCodeAt();
                o += '\\u00' + Math.floor(c / 16).toString(16) +
                    (c % 16).toString(16);
            }
        }
    }
    return o + '"';
};
String.prototype.isIn = function(arr) {
	if (!arr) { return false; }
	for (var i = 0; i < arr.length; i++) {
		if (arr[i] == this) {
			return true;
		}
	}
	return false;
}
String.prototype.pad = function(number, text) {
	if (!number || isNaN(number)) { 
		return this; 
	}
	text = text ? text : ' ';
	var needed = number - this.length;
	var tmp = this;
	for (var i = 0; i < needed; i++) { tmp += text; }
	return tmp;
}
String.prototype.reverse = function() {
	var tmp = '';
	for (var i = this.length; i > -1; i--) {
		tmp += this.substring(i, i+1);
	}
	return tmp;
}
String.prototype.commatize = function() {
	var tmp = this.reverse();
	var result = '';
	for (var i = 0; i < tmp.length; i++) {
		if (i > 0 && (i % 3 == 0)) { result += ',' };
		result += tmp.substring(i, i+1);
	}
	return result.reverse();
}
String.prototype.trim = function() {
	a = this.replace(/^\s+/, '');
	return a.replace(/\s+$/, '');
};
/** Custom object methods **/
String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ''); }
/** Form Deserializer **/
Object.extend(Form, {
	deserialize: function(form, data) {
		form = $(form);
		form.reset();
		for(key in data) {
			Form.Element.deserialize(form, key, data[key]);
		};
	}
});
Object.extend(Form.Element, {
	deserialize: function(form, element, data) {
        var elements = Form.getElements(form);
        for (var index = 0, len = elements.length; index < len; ++index) {
            var item = elements[index];
            if(item.name == element) {
    	        var method = item.tagName.toLowerCase();
    	        Form.Element.Deserializers[method](item, data);
    	        break;
    	    }
        }
	}
});
Form.Element.Deserializers = {
    input: function(element, data) {
        switch (element.type.toLowerCase()) {
            case 'submit':
            case 'hidden':
            case 'password':
            case 'text':
                return Form.Element.Deserializers.textarea(element, data);
            case 'checkbox':
                return Form.Element.Deserializers.inputSelector(element, data);
            case 'radio':
                return Form.Element.Deserializers.radioSelector(element, data);
        }
        return false;
    },
    inputSelector: function(element, data) {
        element.checked = true;
    },
    radioSelector: function(element, data) {
        var name = element.name;
        var radiobuttons = Form.getInputs(element.form, 'radio', element.name);
        for(var i = 0, len = radiobuttons.length; i < len; i++) {
            var radiobutton = radiobuttons[i];
            if(radiobutton.value == data)
                radiobutton.checked = true;
        }
    },
    textarea: function(element, data) {
        element.value = data;
    },
    select: function(element, data) {
        return Form.Element.Deserializers[element.type == 'select-one' ?
            'selectOne' : 'selectMany'](element, data);
    },
    selectOne: function(element, data) {
        element.value = data;
    },
    selectMany: function(element, data) {
        for(var i = 0, len = element.options.length; i < len; i++) {
    		var op = element.options[i];
            if(op.value == decodeURIComponent(data)) {
                op.selected = true;
                break;
            }
        }
    }
}
/* mostly static utility methods */
RTSB.BAD_DATA = '???';
/* user settings */
RTSB.settings = {};
RTSB.settings.use_popup_alert = false;
RTSB.settings.window_theme = 'alphacube';
RTSB.settings.alert_color = '#ff6666';
RTSB.settings.handler_events = ['click','change','blur','focus','mouseover','mouseout'];
/* labels */
RTSB.labels = {};
RTSB.labels.cancel = 'Cancel';
RTSB.labels.close = 'Close';
/* user info */
RTSB.rtuser = {};
RTSB.rtuser.id = 0;
RTSB._timer = {};
/* registered scripts */
RTSB.scripts = {
	/* fckeditor		: RTSB.fckeditor_base + '/fckeditor.js', */
	/* fckeditor		: RTSB.js_path + '/lib/fckeditor/2.5/fckeditor.js', */
	calendar		: RTSB.js_path + '/lib/calendar/calendar.js',
	calendar_en		: RTSB.js_path + '/lib/calendar/lang/calendar-en.js',
	calendar_setup	: RTSB.js_path + '/lib/calendar/calendar-setup.js',
	tooltip			: RTSB.js_path + '/lib/scriptaculous/tooltip.js',
	template		: RTSB.js_path + '/lib/trimpath/1.0.23/template.js',
	dateutils		: RTSB.js_path + '/lib/rtsb/dateutils.js',
	validator		: RTSB.js_path + '/lib/rtsb/validator.js',	
	formhandler		: RTSB.js_path + '/lib/rtsb/formhandler.js',	
	imagepicker		: RTSB.js_path + '/lib/rtsb/imagepicker.js',	// page-based
	imgpick			: RTSB.js_path + '/lib/rtsb/imgpick.js',		// div-based
	rtajaxreq		: RTSB.js_path + '/lib/rtsb/rtajaxreq.js',
	xlinks			: RTSB.js_path + '/lib/rtsb/xlinks.js',
	xitems			: RTSB.js_path + '/lib/rtsb/xitems.js',
	rtcomments		: RTSB.js_path + '/lib/rtsb/rtcomments.js',
	rtquery			: RTSB.js_path + '/lib/rtsb/rtquery.js',
	date			: RTSB.js_path + '/lib/rtsb/date.js',
	rtmodule			: {
						url: 		RTSB.js_path + '/lib/rtsb/rtmodule.js',
						classname:  'RTModule'
	},
	rtpage			: {
						url: 		RTSB.js_path + '/lib/rtsb/rtpage.js',
						classname:  'RTPage'
	},
	articlesform	: {
						url: 		RTSB.js_path + '/lib/rtsb/modules/articles_form.js',
						classname: 'ArticlesFormHandler'
	},
	slideshowdisplay	: {
						url: 		RTSB.js_path + '/lib/rtsb/modules/slideshow_display.js',
						classname: 'SlideShowDisplay'
	},
	dashboard	: {
						url: 		RTSB.js_path + '/lib/rtsb/modules/dashboard.js',
						classname: 'Dashboard'
	}
}
RTSB.init = function() {
	RTSB.assignToolTips();
	RTSB.Init.loadTogglers();
	RTSB.Init.loadImagePickers();
	RTSB.Init.loadThumbnails();
	RTSB.Init.loadFormHandlers();
	RTSB.Init.loadAjaxReqDivs();
	RTSB.Init.loadSelectDefault();
	return;
}
RTSB.assignToolTips = function() {
	$A($$('.tooltip')).each(function(elem) {
		if ($(elem).readAttribute('tooltip').length > 0) {
			new Effect.Tooltip(elem, $(elem).readAttribute('tooltip'), {className : 'tip'});
		}
	});
}
RTSB.initScriptPool = {};
RTSB.initInstances = function(key) {
	var instantiator = RTSB.initScriptPool[key];
	eval(instantiator);
}
RTSB.loaded_scripts = [];
RTSB.callback_handler = null;
RTSB.isTrue = function(value) {
	if (value == '1' || value == 'true' || value == true) {
		return true;
	}
	return false;
}
RTSB.loader = function(url, callback) {
	try {
		// make sure we only load once
		if (RTSB.loaded_scripts.indexOf(url) == -1) {
			RTSB.loaded_scripts.push(url);
			var script = document.createElement("script");
			script.type = "text/javascript";
			$$("head")[0].appendChild(script);
			var ajax_req = new Ajax.Request(
				url, 
				{
					method: "GET", 
					onSuccess: function(req){
						script.text = req.responseText;
					},
					onFailure: RTSB.showReqError
				});
		}
	} catch (e) {
		alert('RTSB.loader: '+ url + ':' +e);
	}
}
RTSB.loadScripts = function(url_or_props, callback, force_reload) {
	// handle object or path
	var url = url_or_props;
	var classname = null;
	var properties = null;
	if (url_or_props.url) {
		properties = url;
		url = properties.url;
		classname = properties.classname;
	}
	try {
		// make sure we only load once
		if ($A(RTSB.loaded_scripts).indexOf(url) == -1 || force_reload) {
			// note that we loaded already
			RTSB.loaded_scripts.push(url);
			var script = document.createElement("script");
			script.src = RTSB.makeAbsUrl(url);
			script.type = "text/javascript";
			$$("head")[0].appendChild(script);
			if (callback) {
				if (Prototype.Browser.WebKit && !navigator.userAgent.match(/Version\/3/)) { 
					RTSB._timer[url] = setInterval(function() {
						try {
							eval(classname);
							clearInterval(RTSB._timer[url]);
							callback(url_or_props); // call the callback handler
						} catch (e) {}
					}, 10);
				} else if (Prototype.Browser.Opera) { 
					RTSB._timer[url] = setInterval(function() {
						if (/loaded|complete/.test(document.readyState)) {
							clearInterval(RTSB._timer[url]);
							callback(url_or_props); // call the callback handler
						}
					}, 10);
				} else {
					script.onload = function () {
						callback(url_or_props);
					}
					script.onreadystatechange = function () {
						if (script.readyState == 'loaded' || script.readyState == 'complete') {
							callback(url_or_props);
						}
					}
				}
			}
		} else {
			if (callback) { callback(url_or_props); }
		}
	} catch (e) {
		alert('RTSB.loadScripts: '+ url_or_props + ':' + e);
	}
}
RTSB.makeAbsUrl = function(url) {
	RTSB.setBasePath();
	if (url.indexOf('http')==-1) {
		return (RTSB.base_url + url);
	}
	return url;
}
RTSB.setBasePath = function() {
	if (RTSB.base_url) { return; }
	var this_path = RTSB.js_path + '/lib/rtsb.js';
	$A($$('script')).each(function(script_tag) {
		if (script_tag.src.indexOf('rtsb.js') > -1) {
			var rtsb_script = script_tag.src;
			RTSB.base_url = rtsb_script.replace(this_path, '');
		}
	});
}
RTSB.require = function(ref, callback, force_reload) {
	if (RTSB.scripts[ref]) {
		RTSB.loadScripts(RTSB.scripts[ref], callback, force_reload);
	} 
}
RTSB.requires = function(refs) {
	if (typeof(refs) == 'string') {
		refs = $A(RTSB.Utils.makeArray(refs));
	}
	refs.each(function(ref){
		RTSB.require(ref);
	})
}
RTSB.requireCalendar = function(callback) {
	// do calendar components individually to ensure execution
	// sounds crazy, but works on FF/IE/S
	RTSB.require('calendar', function(){
		RTSB.require('calendar_en', function(){
			RTSB.require('calendar_setup', function(){
				callback();
			});
		});
	});
}
RTSB.makeCtrlFcn = function(obj, fcn_type) {
	try {
		return obj.params.ctrl + '.' + obj.params[fcn_type];
	} catch (e) {
		alert('RTSB.makeCtrlFcn:' + e);
	}
}
RTSB.addParam = function(obj, paramlist) {
	var result = '';
	for (var i = 0; i < paramlist.length; i++) {
		if (paramlist[i].length > 0)  {
			if (obj.params[paramlist[i]]) {
				result += '&'+paramlist[i]+'=' + obj.params[paramlist[i]];
			}
		}
	}
	return result;
}
RTSB.addFormParams = function(formelem, classname, skipempty) {
	var result = '';
	$A(formelem.getElementsByClassName(classname)).each(function(elem){
		// RTSB.Debug.logValue(elem.name, elem.getValue());
		if (!skipempty || $(elem).getValue().length > 0) {
			// use prototype function for this
			result += '&'+elem.name+'=' + $(elem).getValue();
		}
	});
	return result;
}
RTSB.renderTemplate = function(req, obj, out_elem, tpl_elem) {
	if (out_elem && tpl_elem) {
		try {
			// convert from json
			eval(obj.id+'.data='+req.responseText);
			if (obj.data && obj.data.rt_status) {
				// some type of error code, update
				$(out_elem).hide();
				$(out_elem).update(obj.data.rt_status.msg);
				$(out_elem).show();
				new Effect.Highlight(out_elem, {startcolor: RTSB.settings.alert_color});
			} else {
				// clear request list
				if (obj.data && obj.data.result) {
					obj.recordcount = parseInt(obj.data.result.recordcount);
				}
				// add handler to data
				obj.data.handlerid = obj.id;
				obj.data.handler = obj;
				// indicate if no records were found
				var parsed = '';
				parsed = tpl_elem.value.process(obj.data);
				$(out_elem).hide();
				$(out_elem).update(parsed);
				$(out_elem).show();
			}
		}
		catch (e) {
			var msg = RTSB.Debug.exception('RTSB.renderTemplate', e, null, true);
			msg = msg + '<br/>(Probably because the AJAX request did not return JSON, or because the object handler was not defined properly)';
			$(out_elem).update(msg);
		}
	}
}
RTSB.findObjDataItemById = function(obj, id) {
	if (obj.data.rt_objects) {
		for (var i = 0; i < obj.data.rt_objects.length; i++) {
			var item = obj.data.rt_objects[i];
			if(parseInt(item._attributes.item_id) == parseInt(id)) {
				return item;
			}
		}
	}
	return null;
}
RTSB.parseLink = function(link, args) {
	for (var i = 0; i < args.length; i++) {
		link = link.replace('{'+i+'}', args[i]);
	}
	return link;
}
/** Launchers **/
RTSB.launchers = {};
RTSB.launchers.imgMgr = {
	params: { 
			'layout'		: 	'rtsb.ps',
			'top.function'	: 	'Image+Picker',
			'main.view'		: 	'fileroom.list',
			'main.fileroot_name' : 'images',
			'main.ctrl'		: 	'filemgr.list'			
		},
	height: 480,
	width: 640
}
RTSB.popUp = function(launcher) {
	var url = launcher.url?launcher.url:RTSB.base_path + '/null';
	if (launcher.params) {
		url += '?';
		$H(launcher.params).keys().each(function(key){
			url += '&' + key + '=' + launcher.params[key];
		});
	}
	var height = launcher.height?launcher.height:'640';
	var width = launcher.width?launcher.width:'640';
	var resizable = launcher.resizable?launcher.resizable:'yes';
	var toolbar = launcher.toolbar?launcher.toolbar:'no';
	var scrollbars = launcher.scrollbars?launcher.scrollbars:'yes';
	var status = launcher.status?launcher.status:'no';
	var target = launcher.target?launcher.target:'PopUpWin';
	var winparams = 'height='+height+',width='+width+',resizable='+resizable+',toolbar='+toolbar+',scrollbars='+scrollbars+',status='+status;
	// console.log(url);
	return window.open(url, target, winparams);
}
/** Spinner Functions **/
RTSB.spinner = {};
RTSB.spinner.show = function(elem, spinner_obj) {
	if (elem) {
		$(elem).update(spinner_obj);
	}
}
RTSB.spinner.large = '<div class="spinnerBlockWrapper"><div class="spinnerMozLg"><div>&nbsp;</div></div></div>';
RTSB.spinner.horiz = '<div class="spinnerBlockWrapper"><div class="spinnerBarberHoriz"><div>&nbsp;</div></div></div>';
RTSB.spinner.arrows = '<div class="spinnerBlockWrapper"><div class="spinnerArrows"><div>&nbsp;</div></div></div>';
RTSB.spinner.horizleft = '<div class="spinnerBlockWrapper"><div class="spinnerBarberHorizLeft"><div>&nbsp;</div></div></div>';
/** AJAX functions **/
RTSB.ajaxRequest = function(ctrl, qry_params, success_fcn, failure_fcn, req_method, html_req) {
	req_method = req_method?req_method:'POST';
	failure_fcn = failure_fcn?failure_fcn:success_fcn;
	if (typeof(qry_params) == 'object') {
		qry_params = RTSB.toQryString(qry_params);
	}
	try {
		var params = '';
		if (html_req) {
			params += 'layout=null&showmenu=0&ctrl=' + ctrl;
		} else {
			params += 'exclusive=' + ctrl + '&rtresponsetype=json';
		}
		params += '&' + qry_params;
		params = RTSB.escapeQryParams(params);
		var ajax_req = new Ajax.Request(
			RTSB.base_path + '/null', 
			{
				method: req_method, 
				parameters: params, 
				onSuccess: success_fcn,
				onFailure: failure_fcn
			});
		return ajax_req;
	} catch (e) {
		RTSB.Debug.exception('RTSB.ajaxRequest', e, this);
	}
}
RTSB.escapeQryParams = function(params) {
	return encodeURI(params);
}
RTSB.ajaxGetRequest = function(ctrl, qry_params, success_fcn, failure_fcn) {
	return RTSB.ajaxRequest(ctrl, qry_params, success_fcn, failure_fcn, 'GET');
}
RTSB.ajaxParamPostRequest = function(ctrl, form, success_fcn, failure_fcn) {
	var params = {};
	$A(form.elements).each(function(elem){
		if (elem.name) {
			if (!$(elem).hasClassName("param")) {
				params[elem.name] = elem.value;
			}
		}
	});
	return RTSB.ajaxRequest(ctrl, params, success_fcn, failure_fcn, 'POST');
}
RTSB.ajaxPostRequest = function(ctrl, params, success_fcn, failure_fcn) {
	return RTSB.ajaxRequest(ctrl, params, success_fcn, failure_fcn, 'POST');
}
RTSB.showResponse = function(req, alert_elem) {
	var response = req.responseText;
	if (response.indexOf('alertmsgdetail') > -1) {
		$(alert_elem).update(response);			
	} else {
		try {
			eval('var responseobj='+response);
			RTSB.nonModalAlert(alert_elem, responseobj.rt_status.msg, 500);
		} catch (e) {
			$(alert_elem).update(e);
		}
	}
}
/** DEPRECRATED, use RTSB.Alert for all alert functions **/
RTSB.nonModalAlert = function(alert_elem, text, width) {
	return RTSB.Alert.nonModal(alert_elem, text, width);
}
RTSB.updateAlert = function(alert_elem, text) {
	return RTSB.Alert.updateAlert(alert_elem, text);
}
RTSB.nonModalAlertFade = function(alert_elem) {
	return RTSB.Alert.nonModalFade(alert_elem);
}
RTSB.ajaxGetHtmlRequest = function(ctrl, qry_params, success_fcn, failure_fcn) {
	return RTSB.ajaxRequest(ctrl, qry_params, success_fcn, failure_fcn, 'GET', true);
}
RTSB.toQryString = function(obj) {
	var result = '';
	try {
		for (var key in obj) {
			if (obj[key]) {
				result += '&' + escape(key) + '=' + obj[key];
			}
		}		
		return result;
	} catch (e) {
		return obj;
	}
}
RTSB.showReqError = function(req) {
	RTSB.Debug.exception('RTSB.showReqError', req.status);
}
/* returns true is object is an array -- a hack, only tells if obj is object, 
but no reliable method in js, the constructor method does not work in safari */
RTSB.isArray = function(obj) {
	return((typeof obj) == 'object');
}
/** Module Functions **/
RTSB.setParameters = function(obj) {
	if (!obj.params) { obj.params = {}; }
	if (!obj.args) { obj.args = {}; }
	if (!obj.qryparams) { obj.qryparams = {}; }
	// init settings if needed
	if (!obj.settings) { obj.settings = {}; }
	if (!obj.settings.fieldValues) { obj.settings.fieldValues = {}; }
	// hidden field values
	if (obj.form) { 
		// init values in params based on form;
		for (var key in obj.params) {
			if (obj.form[key]) {
				obj.params[key] = obj.form[key].value;
				// store settings value
				obj.settings.fieldValues[key] = obj.form[key].value;
			}
		}
		// init values in qryparams based on form;
		$A(obj.qryparams).each(function(item){
			if (obj.form[item] && obj.params[item]) {
				obj.params[item] = obj.form[item].value;
			}
		}.bind(obj));
	}
	for (var key in obj.args) {
		// args take precedence over form
		// console.log("key="+key+"  value="+obj.args[key]);
		obj.params[key] = obj.args[key];
	}
},
RTSB.assignEventListeners = function(obj, events) {
	if (obj.form) {
		// assign functions to all form elements of class 'handleEvent' with a valid function name 
		try {
			$A(obj.form.getElementsByClassName('handleEvent')).each(function(elem) {
				var fcn_name = elem.name?elem.name:(elem.title?elem.title:null);
				if (fcn_name && obj[fcn_name]) {
					$A(events).each(function(evt_type){
						if (elem.hasClassName(evt_type)) {
							Event.observe(elem, evt_type, obj[fcn_name].bindAsEventListener(obj), true);
						}
					}.bind(obj));
				}
			}.bind(obj));
		} catch (e) {
			RTSB.Debug.exception('RTSB.assignEventListeners', e);
		}
	}
},
/*
	Requires elements with handleEvent class names and the following custom tags:
	event = "{1}"
	action = "{2}"
	where:
		{1} = event (click, change, etc);
		{2} = object function (no arguments);
*/
RTSB.assignEventListenersAdv = function(obj, elem) {
	if (elem) {
		// assign functions to all form elements of class 'handleEvent' with a valid function name 
		try {
			$A(elem.select('.handleEvent')).each(function(child_elem) {
				if (child_elem.readAttribute('event') && child_elem.readAttribute('action')) {
					var evt_types = child_elem.readAttribute('event')?child_elem.readAttribute('event').split(','):[];
					if (evt_types.length > 0) {
						var fcn_name = child_elem.readAttribute('action');
						if (fcn_name && obj[fcn_name]) {
							$A(evt_types).each(function(evt_type){
								Event.observe(child_elem, evt_type, obj[fcn_name].bindAsEventListener(obj), true);
							});
						}
					}
				}
			}.bind(obj));
		} catch (e) {
			RTSB.Debug.exception('RTSB.assignEventListenersAdv', e);
		}
	}
},
RTSB.setOnLoad = function(obj) {
	// execute onload functions
	if (obj && obj.params && obj.params.onload && obj.params.onload.length > 0) {
		var loadfcns = RTSB.Utils.makeArray(obj.params.onload);
		for (var i = 0; i < loadfcns.length; i++) {
			try {
				obj[loadfcns[i]]();
			} catch(e) {
				alert('initialize:'+e);
			}
		}
	}
}
RTSB.addElemPrefix = function(obj, text) {
	var modified_text = obj.params.elem_id_prefix + text;
	return modified_text;
}

/** ALERT FUNCTIONS **/
RTSB.Alert = {};
RTSB.Alert.modal = function(text, width, height, ok_label, class_name, win_fcn) {
	text = text?text:'No alert text provided';
	if (RTSB.settings.use_popup_alert) {
		alert(text.unescapeHTML());
	} else {
		width = width?width:400;
		height = height?height:200;
		// wrap text in div
		text = '<div class="alertMessage">' + text + '</div>';
		
		ok_label = ok_label?ok_label:RTSB.labels.close;
		class_name = class_name?class_name:RTSB.settings.window_theme;	
		win_fcn = win_fcn?win_fcn:'alert';
		return Dialog[win_fcn](text, {className: class_name, width:width, height:height, okLabel: ok_label, ok:function(win) {return true;}});
	}
}
RTSB.Alert.modalWait = function(width, height, class_name, win_fcn) {
	return RTSB.Alert.modal(RTSB.spinner.large, width, height, null, class_name, 'info');
}
RTSB.Alert.createDialogHTML = function(text) {
	var result = '\
	<div align="center" class="rtDialogBoxWrap"><table><tr><td><div>\
	  <b class="rtDialogBox"><b class="rtDialogBox1"><b></b></b><b class="rtDialogBox2"><b></b></b>\
	  <b class="rtDialogBox3"></b><b class="rtDialogBox4"></b><b class="rtDialogBox5"></b></b>\
	  <div class="rtDialogBoxfg">'+text+'</div>\
	  <b class="rtDialogBox"><b class="rtDialogBox5"></b><b class="rtDialogBox4"></b>\
	  <b class="rtDialogBox3"></b><b class="rtDialogBox2"><b></b></b><b class="rtDialogBox1"><b></b></b></b>\
	</div></td></tr></table></div>';
	return result;
}
RTSB.Alert.nonModal = function(alert_elem, text, width) {
	width = width?width:250;
	var msg = RTSB.Alert.createDialogHTML(text, width);
	RTSB.Alert.update(alert_elem, msg);
	new Effect.Highlight(alert_elem.firstDescendant(), {startcolor:RTSB.settings.alert_color});
	clearTimeout(RTSB.modal_alert_fader);
	var fade_fcn = 'RTSB.nonModalAlertFade("'+alert_elem.id+'")';
	RTSB.modal_alert_fader = setTimeout(fade_fcn, 8000);
}
RTSB.Alert.nonModalFade = function(alert_elem) {
	// get dialog alert fade
	if ($(alert_elem).firstDescendant()) {
		new Effect.Fade($(alert_elem).firstDescendant());
	}
}
RTSB.Alert.update = function(alert_elem, text) {
	$(alert_elem).update(text);
}
RTSB.Cookie = {};
RTSB.Cookie.get = function(name) {
	var result = "";
	var cookies = document.cookie.split('; ');
	$A(cookies).each(function(cookie){
		var parts = cookie.split('=');
		if (parts.length == 2 && parts[0] == name) {
			result = unescape(parts[1]);
		}
	});
	return result;
}
RTSB.Cookie.set = function(name, value, expires, path, domain, secure) {
	var today = new Date();
	today.setTime( today.getTime() );
	if (expires ) {
		expires = expires * 1000 * 60 * 60 * 24;
	}
	path = path?path:window.location.pathname;
	if (path.substring(path.length-1, path.length) != '/') {
		path = path + '/';
	}
	var expires_date = new Date( today.getTime() + (expires));
	document.cookie = name+'='+escape( value ) +
		((expires) ? ';expires='+expires_date.toGMTString() : '') + //expires.toGMTString()
		((path) ? ';path=' + path : '') +
		((domain) ? ';domain=' + domain : '') +
		((secure) ? ';secure' : '');
}
RTSB.Cookie.del = function(name, path, domain) {
	if (RTSB.Cookie.get(name)) document.cookie = name + '=' +
			((path)? ';path=' + path : '') +
			((domain)? ';domain=' + domain : '' ) +
			';expires=Thu, 01-Jan-1970 00:00:01 GMT';
}
RTSB.Cookie.setObj = function(name, value, expires, path, domain, secure) {
	var value = Object.toJSON(value);
	// RTSB.Debug.logValue('value', value);
	RTSB.Cookie.set(name, value, expires, path, domain, secure);
}
RTSB.Cookie.getObj = function(name) {
	var cookie_val = RTSB.Cookie.get(name);
	// RTSB.Debug.logValue('cookie_val', cookie_val);
	if (cookie_val){
		try {
			eval('var obj = '+cookie_val)
			return obj;
		} catch (e) {
			alert('RTSB.Cookie.get:'+e);
		}
	} else {
		// return empty object if we don't find 
		return {};
	}
}
RTSB.Cookie.serializeElements = function(name, form_elems, expires, path, domain, secure) {
	var serialized = Form.serializeElements(form_elems, true);
	RTSB.Cookie.setObj(name, serialized, expires, path, domain, secure);
}
RTSB.Cookie.deSerializeElements = function(name, form) {
	var value = RTSB.Cookie.get(name);
	if (value && value.isJSON()) {
		var obj = value.evalJSON();
		Form.deserialize(form, obj);
	}
}
/** debug utilities **/
RTSB.Debug = {};
RTSB.Debug.log = function(text) {
	if(window.console) {
		console.log(text);
	} else {
		window.status = text;
	}
}
RTSB.Debug.logValue = function(name, value) {
	RTSB.Debug.log(name + '=' + value);
}
RTSB.Debug._tracers = {};
RTSB.Debug.trace = function(key) {
	if (!RTSB.Debug._tracers[key]) {
		RTSB.Debug._tracers[key] = new RTSB.Debug.tracer(key);
	}
	RTSB.Debug._tracers[key].increment();
}
RTSB.Debug.tracer = function(name) {
	this.name = name;
	this.counter = -1;
	this.startime = new Date().getTime();
	this.output_on_increment = true;
	this.increment = function() {
		this.counter++;
		if (this.output_on_increment) {
			RTSB.Debug.log(this.name + ':' + this.counter + ':' + (new Date().getTime() - this.startime));
		}
	}
}
RTSB.Debug.exception = function(location, error, obj, msgonly) {
	var id = '';
	if (obj && obj.id) {
		id = ' (' + obj.id + ')';
	}
	var msg = 'RTSB Exception ['+location+']:' + error + id;
	if (msgonly) {
		return msg;
	} else {
		alert(msg);
	}
	if (window.console) {
		console.trace();
	}
}
/** SYSTEM LOAD FUNCTIONS **/
RTSB.Init = {};
RTSB.Init.loadTogglers = function() {
	$A($$('.toggler')).each(function(elem){
		if (RTSB.Utils.checkToggleDiv(elem)) {
			// we expect a child image element
			var img = elem.immediateDescendants()[0];
			if(img.src && elem.getAttribute('src_off')) {
				img.src = elem.getAttribute('src_off');
				Event.observe(elem, 'click', function(evt){Event.stop(evt); RTSB.Utils.toggle(elem.id)});
			}
		}
	});
	// handle legend collapsing
	$A($$('.legendToggle')).each(function(elem){
		Event.observe(elem, 'click', RTSB.Utils.toggleFieldSet);
		RTSB.Utils.setToggleState(elem);
	}.bind(this));
}
RTSB.Init.loadImagePickers = function() {
	$A($$('.imagePicker')).each(function(elem){
		Event.observe(elem, 'click', function(evt){RTSB.Utils.initImagePicker(evt, elem)});
	});
}
RTSB.Init.loadThumbnails = function() {
	$A($$('.imagePickerThumbnail')).each(function(elem){
		var src_id = elem.id.replace('_imageThumb','');
		if ($(src_id) && $(src_id).value && $(src_id).value.length > 0) {
			elem.style.backgroundRepeat = 'no-repeat';
			elem.style.backgroundImage = 'url('+$(src_id).value+')';
		} else {
			elem.style.backgroundImage = '';
		}
		// add preview listener
		Event.observe(elem, 'click', function(evt){RTSB.Utils.previewImage(evt, elem)});		
	});
}
RTSB.Init.loadFormHandlers = function() {
	// iterate through forms
	$A(document.forms).each(function(form) {
		form = $(form);
		if (form.hasClassName('formhandler')) {
			var form_handler = form.readAttribute('formhandler');
			if (form_handler && form_handler.length >  0) {
				document[form_handler] = {};
				RTSB.require('formhandler', function(){
					// can assign object instance later 
					document[form_handler] = new FormHandler(form_handler, {
							'form'							: form,
							'formsubmitting'				: form.formhandler_formsubmitting?form.formhandler_formsubmitting.value:null,
							'formsubmittingmsg'				: form.formhandler_formsubmittingmsg?form.formhandler_formsubmittingmsg.value:null,
							'formsubmitalertmsg'			: form.formhandler_formsubmitalertmsg?form.formhandler_formsubmitalertmsg.value:null,
							'formsubmitalertbtn'			: form.formhandler_formsubmitalertbtn?form.formhandler_formsubmitalertbtn.value:null,
							'rtresume'						: form.formhandler_rtresume?form.formhandler_rtresume.value:null,
							'validate'						: form.formhandler_validate?form.formhandler_validate.value:null,
							'cancel_confirm_msg'			: form.formhandler_cancel_confirm_msg?form.formhandler_cancel_confirm_msg.value:null,
							'show_modal_validation_alert'	: form.formhandler_show_modal_validation_alert?form.formhandler_show_modal_validation_alert.value:null,
							'cancel_call'					: form.formhandler_cancel_call?form.formhandler_cancel_call.value:null
					});
				}, true);
			}
		}
		if (form.hasClassName('hashandler')) {
			var custom_handler = form.readAttribute('handler');
			if (custom_handler && custom_handler.length >  0) {
				form.handler = function(){};
				RTSB.require(custom_handler, function(handler_props){
					if (handler_props.classname) {
						try {
							form.handler_obj = eval('new '+handler_props.classname+'(form)');
						} catch(e) {
							RTSB.Debug.exception('RTSB.Init.loadFormHandlers('+handler_props.classname+')', e);
						}
					} else {
						alert('RTSB.Init.loadFormHandlers -- missing classname ('+custom_handler+')');
					}
				}, true);
			}
		}
	});
}
RTSB.Init.loadAjaxReqDivs = function() {
	$A($$('.ajaxreq')).each(function(elem){
		if (ctrl = elem.readAttribute('ctrl')) {
			params = elem.readAttribute('params');
			$(elem).update(RTSB.spinner.large);
			RTSB.ajaxGetHtmlRequest(ctrl, params, function(req){RTSB.Init.updateAjaxReqDivs(req, elem)}, function(){$(elem).update(''); RTSB.showReqError.bind(this)});
		}
	});
}
RTSB.Init.updateAjaxReqDivs = function(req, elem) {
	$(elem).update(req.responseText);
}
RTSB.Init.loadSelectDefault = function() {
	$A($$('.selectDefault')).each(function(elem){
		// add preview listener
		Event.observe(elem, 'click', function(evt){RTSB.FormUtils.selectDefault(evt, elem)});		
	});
}
/** GENERAL UTILITIES **/
RTSB.Utils = {};
RTSB.Utils.makeArray = function(string_list) {
	if (!string_list || string_list.length == 0) {
		return [];
	}
	var result = string_list.split(',');
	return result;
}
RTSB.Utils.getCookieList = function(id) {
	if (!id) { return null; }
	var cookie = RTSB.Cookie.get(id);
	if (!cookie) {
		return [];
	}
	return RTSB.Utils.makeArray(cookie);
}
RTSB.Utils.setCookieList = function(id, arr) {
	if (!id) { return; }
	arr = arr?arr:[];
	var cookie = arr.join(',');
	// RTSB.Debug.logValue(id, cookie); //@remove
	RTSB.Cookie.set(id, cookie);
}
RTSB.Utils.toggle = function(id) {
	var elem = $(id);
	if (RTSB.Utils.checkToggleDiv(elem)) {
		// we expect a child image element
		var img = elem.immediateDescendants()[0];
		var target_elem = elem.id.replace('toggler_','');
		var src_off = elem.getAttribute('src_off');
		var src_on = elem.getAttribute('src_on');
		if(img.src.indexOf(src_off) > -1) {
			// hide element
			$(target_elem).show();
			img.src = src_on;
			// save state
		} else {
			new Effect.Fade(target_elem);	
			// show element		
			img.src = src_off;
			// save state
		}
		// restore cookie state
		
	}
}
RTSB.Utils.toggleFieldSet = function(evt) {
	var legendAnchor = Event.element(evt);
	var elem = legendAnchor.ancestors()[0];
	if (elem.hasClassName('collapsed')) {
		RTSB.Utils.toggleFieldSetFields(elem, true);
	} else {
		RTSB.Utils.toggleFieldSetFields(elem, false);
	}
	Event.stop(evt);
}
RTSB.Utils.toggleFieldSetFields = function(elem, state) {
	if (!elem || !$(elem).nextSiblings()[0] || $(elem).nextSiblings()[0].id.indexOf("_fields") == -1) { return; }
	var elem_sib = $(elem).nextSiblings()[0];
	if (state) {
		elem.removeClassName('collapsed');
		$(elem_sib).show();
		RTSB.Utils.saveToggleState(elem_sib.id, true);
	} else {
		elem.addClassName('collapsed');
		$(elem_sib).hide();
		RTSB.Utils.saveToggleState(elem_sib.id, false);
	}
}
RTSB.Utils.makeToggleTagFromId = function(text) {
	return text.replace('_fields', '');
}
RTSB.Utils.setToggleState = function(legendAnchor) {
	var elem = legendAnchor.ancestors()[0];
	if (!elem || !$(elem).nextSiblings()[0] || $(elem).nextSiblings()[0].id.indexOf("_fields") == -1) { return; }
	var elem_sib_id = $(elem).nextSiblings()[0].id;
	var elem_sib_id_tag = RTSB.Utils.makeToggleTagFromId(elem_sib_id);
	var state = RTSB.Utils.checkToggleState(elem_sib_id_tag);
	// RTSB.Debug.logValue(elem_sib_id_tag, state); //@remove	
	if (state != null) {
		RTSB.Utils.toggleFieldSetFields(elem, state);
	}
}
RTSB.Utils.checkToggleDiv = function(elem) {
	return elem.id && elem.immediateDescendants() && elem.getAttribute('src_on') && elem.getAttribute('src_off');
}
RTSB.Utils.saveToggleState = function(id, on) {
	if (!id) { return; }
	id = RTSB.Utils.makeToggleTagFromId(id); // _fields is redundant
	var on_list = $A(RTSB.Utils.getCookieList('toggle_on'));
	var off_list = $A(RTSB.Utils.getCookieList('toggle_off'));
	if (on) {
		if (on_list.indexOf(id) == -1) {
			on_list.push(id);
		}
		off_list = off_list.without(id);
	} else {
		if (off_list.indexOf(id) == -1) {
			off_list.push(id);
		}
		on_list = on_list.without(id);
	}
	RTSB.Utils.setCookieList('toggle_on', on_list);
	RTSB.Utils.setCookieList('toggle_off', off_list);
}
RTSB.Utils.checkToggleState = function(id) {
	var on_list = $A(RTSB.Utils.getCookieList('toggle_on'));
	var off_list = $A(RTSB.Utils.getCookieList('toggle_off'));
	id = RTSB.Utils.makeToggleTagFromId(id); // _fields is redundant
	if (on_list.indexOf(id) > -1) {
		return true;
	} 
	if (off_list.indexOf(id) > -1) {
		return false;
	}
	return null;
}
RTSB.Utils.imgPick = {} // can only have one active image picker at a time
RTSB.Utils.initImagePicker = function(evt, elem) {
	Event.stop(evt);
	var dialog_window = Dialog.alert('<div id="imgPickerDialog"></div>', {className: RTSB.settings.window_theme, width: 600, height: 480, okLabel: RTSB.labels.cancel});
	RTSB.require('imgpick', function(){
		RTSB.Utils.imgPick = new RTSB.ImgPick('RTSB.Utils.imgPick', 'imgPickerDialog', dialog_window, elem);
	}.bind(this));
}
RTSB.Utils.previewImage = function(evt, elem){
	var bg_img = elem.style.backgroundImage;
	if (bg_img && bg_img.length > 0) {
		var img_path = RTSB.Utils.convertBgImage(bg_img);
		var dialog_window = Dialog.alert('<div class="imagePreview"><div class="label">'+img_path+'</div><div class="image"><img src="'+img_path+'" border="0"/></div></div>', {className: RTSB.settings.window_theme, width: 600, height: 480, okLabel: RTSB.labels.close});
	}
}
RTSB.Utils.convertBgImage = function(css_background_image) {
	var result = css_background_image.replace('url(','');
	result = result.replace(')','');
	return result;
}

/** form utilties **/
RTSB.FormUtils = {};
RTSB.FormUtils.addHandlers = function(form_element, handler_obj) {
	$A(form_element.getElementsByClassName("hashandler")).each(function(elem){
		if (clickhandler = elem.readAttribute('clickhandler')) {
			if (handler_obj[clickhandler]) {
				Event.observe(elem, 'click', handler_obj[clickhandler].bind(handler_obj), false);
			}
		}
	});
}
RTSB.FormUtils.resetElement = function(form_element) {
	switch(form_element.type) {
		case 'text': 
			form_element.value = '';
		break;
		case 'select-one': 
			form_element.selectedIndex = -1;
		break;
		case 'select-many': 
			form_element.selectedIndex = -1;
		break;
	}
}
RTSB.FormUtils.toggleSelectOption = function(form_element, option_value) {
	$A(form_element).each(function(option){
		if(option.value == option_value) {
			option.toggle();
		}
	});
}
RTSB.FormUtils.makeParams = function(form_element){
	var params = {};
	if(form_element) {
		$A(form_element.elements).each(function(elem){
			if (elem.name) {
				var value = '';
				switch(elem.type) {
					case 'select-one':
					case 'select-many':
						value = [];
						for (var i = 0; i < elem.options.length; i++) {
							if (elem.options[i].selected) {
								value.push(elem.options[i].value);
							}
						}
					break;
					default:
						value = elem.value;
					break;
				}
				// special cases 
				if (elem.name == 'rtresponsetype') {
					value = 'json';
				}
				if (elem.name == 'rtrefresh') {
					value = '';
				}
				// console.log(elem.name + '=' + value);
				params[elem.name] = value;
			}
		});
	}
	return params;
}
RTSB.FormUtils.parseWorldPerms = function(elem) {
	if (elem && elem.form) {
		if (elem.type == 'select-one') {
			var code = elem[elem.selectedIndex].value;
			if (code.length == 3) {
				var w_read = code.substring(0,1);
				var w_edit = code.substring(1,2);
				var w_link = code.substring(2,3);
				var f = elem.form;
				if(f.w_read) { f.w_read.value = w_read; }
				if(f.w_edit) { f.w_edit.value = w_edit; }
				if(f.w_link) { f.w_link.value = w_link; }
			}
		}
	}
}
RTSB.FormUtils.getFilenameFromPath = function(file_path) {
	var token = '/';
	if (file_path.indexOf('\\') > -1) {
		token = '\\';
	}
	var parts = file_path.split(token);
	return parts[parts.length-1];
}
RTSB.FormUtils.selectDefault = function(evt, elem) {
	if (defval = elem.readAttribute('defaultValue')) {
		if (defval == elem.value) {
			elem.select();
		}
	}
}
/** DO NOT USE YET -- Does not work as expected **/
RTSB.FormUtils.assignEventListeners = function(handler, form) {
	// since IE does not assign form onchange to element onchange, do it manually
	var event_handler = '';
	$A(form.elements).each(function(elem) {
		$A(RTSB.settings.handler_events).each(function(evt_name) {
			evt_handler = 'on' + evt_name;
			if (handler[evt_handler]) {
				Event.observe(elem, evt_name, function(event){ Event.stop(event); handler[evt_handler](event); });
			}
		});
	});
}
/** string utilties **/
RTSB.StringUtils = {};
RTSB.StringUtils.appendUrl = function(url, string) {
	var token = url.indexOf('?') > -1 ? '&':'?';
	return url + token + string;
}
RTSB.StringUtils.paramReplacer = function(href, param_name, new_value) {
	var qs = '';
	if (href.indexOf('?') > -1) {
		qs = href.split('?')[1];
		href = href.split('?')[0];
	}
	var regex = new RegExp(param_name+'=[^&]+', 'g'); 
	if (qs.match(regex)) {
		qs = qs.replace(regex, param_name + '=' + new_value);
	} else {
		qs = qs + '&' + param_name + '=' + new_value;
	}
	return href + '?' + qs;
}
RTSB.StringUtils.replaceUrlParam = function(param_name, new_value) {
	window.location = RTSB.StringUtils.paramReplacer(window.location.href, param_name, new_value);
}
// parse array of name value pairs
RTSB.StringUtils.replaceUrlParams = function(name_values) {
	var href = window.location.href;
	$A(name_values).each(function(name_value){
		if (name_value.length == 2) {
			href = RTSB.StringUtils.paramReplacer(href, name_value[0], name_value[1]);
		}
	});
	window.location = href;
}
RTSB.StringUtils.pageUrl = function(param_name, maxrows, startrow, increment) {
	maxrows = maxrows ? parseInt(maxrows) : 0;
	startrow = startrow ? parseInt(startrow) : 0;
	startrow = increment ? startrow + maxrows : startrow - maxrows;
	startrow = startrow > 0 ? startrow : 0;
	return RTSB.StringUtils.replaceUrlParam(param_name, startrow);
}
RTSB.StringUtils.messageFormat = function(template, args) {
	$A(args).each(function(arg, index){
		template = template.replace(new RegExp('\\{'+index+'\\}','g'), arg);
	});
	return template;
}
