/* 
 * system.tools.js 
 * version 5.5.6
 * Copyright (C) Jason Mingl (Ratheous)
 *
 *	08/24/2007 : 5.5.6 - Added EventContext
 						 Removed some trash
 *	08/20/2007 : 5.5.5 - Changed Class.override. parent class functions should not be altered if class is overridden more than once
 						 Added iif function
 *	05/03/2007 : 5.5.4 - iframe_shim - changes to size / positioning
 *	05/01/2007 : 5.5.3 - Added Class.override
 *	04/30/2007 : 5.5.2 - Added Class foundation
 *	04/20/2007 : 5.5.1 - Provisional fix for get_elem_offset and relative containers
 *	04/15/2007 : 5.5.0 - Avoid reassignment of '$' - prototype.js support
 *	04/08/2007 : 5.4.9 - Added Object.extend
 *	04/02/2007 : 5.4.8 - Added system.tools.get_var_style / $S
 *	03/15/2007 : 5.4.7 - showConsole
 *	02/27/2007 : ?.?.? - Many initial releases
*/

Object.extend = function(destination, source) 
{
	for (var property in source) 
	{ destination[property] = source[property]; }
	return destination;
};

var Class = { create: function() { return function() { this.initialize.apply(this, arguments); } } };

Class.prepare = function(definition)
{
	var obj = Class.create();
	Object.extend(obj.prototype, definition);
	return obj;
};

Class.extend = function(parent, definition) 
{
	var child = Class.create();
	Object.extend(child.prototype, parent.prototype);
	Object.extend(child.prototype, definition);
	return child;
};

Class.supplement = function(child, parent, definition) 
{
	Object.extend(child.prototype, parent.prototype);
	Object.extend(child.prototype, definition);
};

Class.override = function(dest, overrides) 
{
	if(!dest.prototype.parent) dest.prototype.parent = {};
	
	for (var p in overrides)
	{
		if(dest.prototype[p] && !dest.prototype.parent[p])
			dest.prototype.parent[p] = dest.prototype[p];
		dest.prototype[p] = overrides[p];
	}
	return dest;
};

Class.subclass = function(parent, overrides) 
{
	var child = Class.create();
	for (var p in parent.prototype)
		child.prototype[p] = parent.prototype[p];
	child.prototype.parent = {};
	for (var p in overrides)
	{
		if(child.prototype[p])
			child.prototype.parent[p] = child.prototype[p];
		child.prototype[p] = overrides[p];
	}
	return child;
};

// EventContext --------------------------------------------------------------

EventContext = Class.prepare(
{
	initialize: function() { this.idx = 0; this.events = new Object; },
	attach: function(callback, context) { this.events[++this.idx] = {method:callback, context:context}; return this.idx; },
	detach: function(idx) { delete this.events[idx]; },
	invoke: function() { for(i in this.events) try { this.events[i].method.apply(this.events[i].context, arguments); } catch(e){} }
});

if(typeof system != "object")
	var system = new Object;
if(typeof system.tools != "object")
	system.tools = new Object;

String.prototype.trim = function()
{
    return this.replace(new RegExp("^\\s+|\\s+$", "gi"), "");
};

// Is the current browser a total piece of $#!7?
system.tools.is_ie = function()
{
	return (navigator.appName == "Microsoft Internet Explorer");
};
// -------------------------------------------------------

system.tools.get_var_object = function(obj, reqd)
{
	var name;
	if(typeof obj != "object")
	{
		name = obj;
		obj = document.getElementById(obj);
	}
	if(!obj)
	{
		if(reqd)
			throw new Error("get_var_object() - can't find: " + name);
		return undefined;
	}
	return obj;
}; if(!$) var $ = system.tools.get_var_object;

system.tools.get_var_style = function(v) { return($(v).style); }; var $S = system.tools.get_var_style;

// -------------------------------------------------------

system.tools.get_elem_offset = function(obj)
{
	var offset = new Object;
	offset.left = 0;
	offset.top = 0;
	obj = $(obj);
	if (obj.offsetParent)
	{
		var rel;
		while (obj.offsetParent)
		{
			// provisional solution
			rel = obj.style.position == 'relative';
			offset.left += rel ? 0 : obj.offsetLeft;
			offset.top += rel ? 0 : obj.offsetTop;
			obj = obj.offsetParent;
		}
	} 
	else
	{
		if(obj.x) offset.left += obj.x;
		if(obj.y) offset.top += obj.y;
	}
	
	return offset;
}

system.tools.set_elem_position = function(elem, x, y)
{
	elem.style.left = x + 'px';
	elem.style.top = y + 'px';
}

// ----------------------------------------------------------------------------------

system.tools.in_array = function(value, arr)
{
	for(i = 0; i < arr.length; i++)
	{
		debug("checking " + value + " against " + arr[i]);
		if(arr[i] === value);
			return true;
	}
	return false;
}

// ----------------------------------------------------------------------------------

system.tools.switch_image = function(obj, new_src)
{
	$img_obj = system.tools.get_var_object(obj);
	$img_obj.src = new_src;
};

// ----------------------------------------------------------------------------------

system.tools.iframe_shim = function(frame, iframe_id)
{
	try 
	{
		if(!system.tools.is_ie()) return;
		frame = $(frame);
		var iframe = $(iframe_id);
		if (!iframe)
		{
			iframe = document.createElement("iFrame");
			iframe.setAttribute("id", iframe_id);
			iframe.setAttribute("src", "javascript:false;");
			iframe.setAttribute("scrolling", "no");
			iframe.setAttribute("frameborder", "0");
			iframe.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)';
			iframe.style.position = "absolute";
			document.body.appendChild(iframe);
		}
		if(frame.style.zIndex < 1)
			frame.style.zIndex = 1;
		iframe.style.width = frame.offsetWidth ? frame.offsetWidth + "px" : frame.style.width;
		iframe.style.height = frame.offsetHeight ? frame.offsetHeight + "px" : frame.style.height;
		iframe.style.top = frame.style.top != '' ? frame.style.top : '0';
		iframe.style.left = frame.style.left != '' ? frame.style.left : '0';
		iframe.style.zIndex = frame.style.zIndex - 1;
		iframe.style.display = "";
		return iframe;
	} 
	catch(e) {}
};

// ----------------------------------------------------------------------------------

function showConsole(opts) 
{
	var width = opts.width ? opts.width : 350;
	var height = opts.height ? opts.height : 100;
	var _top = opts.top != null ? opts.top : screen.height/2-height/2;
	var _left = opts.left != null ? opts.left : screen.width/2-width/2;
	var content = opts.content;
	var url = opts.url != null ? opts.url : '';
	var title = opts.title ? opts.title : 'Console';
	var windowname = opts.windowname ? opts.windowname : 'console';
	var sb = opts.sb ? 1:0;
	var rs = opts.rs ? 1:0;
	top.consoleRef=window.open(url, windowname, 'width='+ width +',height='+ height +(_top ? 'top='+_top+',' : '')+(_left ? 'left='+_left+',' : '')+ ',menubar=0,toolbar=0,status=0,scrollbars='+sb+',resizable='+rs);
	//docRef = top.winRef.document.open("text/html","replace");
	if(top.consoleRef && content)
	{
		top.consoleRef.document.writeln('<html><head><title>Permissions Failure</title></head><body bgcolor=white onLoad="self.focus()">'+ content +'</body></html>');
		top.consoleRef.document.close();
	}
};

function iif(value, def) { return value != null ? value : (def != null ? def : ''); };

if(typeof system.debug != "object")
	system.debug = new Object;
	
system.debug.trace = function() { /* blank stub */ };
system.debug.status = function() { /* blank stub */ };
	/* 
 * system.events.js 
 * version 1.0.5
 * Copyright (C) 2006-2007 Jason Mingl (Ratheous)
 
 Dependencies:
 	system.tools.js

 *	05/20/2007 : 1.0.5 - Added check for evt variable validity in stop()
 *	04/15/2007 : 1.0.4 - Modified system.events.add, system.events.cache.add, system.events.invoke et. al.
 						 Added system.events.remove
 *	04/08/2007 : 1.0.3 - Added system.events.invoke
 *	03/04/2007 : 1.0.2 - Added add_by_type function
 *	03/03/2007 : 1.0.1 - Added event translate function
 *	??/??/2006 : 1.0.0 - Initial release
 */

if(typeof system != "object")
	var system = new Object;
if(typeof system.events != "object")
	system.events = new Object;

system.events.cache = new Object;
system.events.cache.event_list = [];

system.events.cache.add = function(element, type, handler)
{
	system.events.cache.event_list.push(arguments);
	return arguments;
};

system.events.cache.flush = function()
{
	var itm;

	for(var i = system.events.cache.event_list.length - 1; i >= 0; i--)
	{
		itm = system.events.cache.event_list[i];
		if(itm[0].removeEventListener) itm[0].removeEventListener(itm[1], itm[2], itm[3]);
		if(itm[1].substring(0, 2) != "on") itm[1] = "on" + itm[1];
		if(itm[0].detachEvent) itm[0].detachEvent(itm[1], itm[2]);
		itm[0][itm[1]] = null;
	}
};

system.events.add = function(element, type, handler)
{
	try
	{
		if(element.addEventListener)
		{
			element.addEventListener(type, handler, false);
			return system.events.cache.add(element, type, handler);
		}
		else if(element.attachEvent)
		{
			element["e" + type + handler] = handler;
			element[type + handler] = function() { element["e" + type + handler](window.event); };
			element.attachEvent("on" + type, element[type + handler]);
			return system.events.cache.add(element, type, handler);
		}
	}
	catch(e)
	{
		//alert(e + " " + typeof element);
	}
};

system.events.add_by_type = function(root, element, evttype, handler)
{
	var itms = root.getElementsByTagName(element);
	var e = [];
	for(var i = 0; i < itms.length; i++)
		e.push(system.events.add(itms[i], evttype, handler));
	return e;
};

system.events.remove = function(evt)
{
	if(evt[0].removeEventListener) evt[0].removeEventListener(evt[1], evt[2], evt[3]);
	if(evt[1].substring(0, 2) != "on") evt[1] = "on" + evt[1];
	if(evt[0].detachEvent) evt[0].detachEvent(evt[1], evt[2]);
};

system.events.prevent_default = function(evt)
{
	if(evt.preventDefault) evt.preventDefault()
	else event.returnValue = false;
};

system.events.halt = function(evt)
{
	if(!evt) return;
	if(evt.stopPropagation) evt.stopPropagation()
	else event.cancelBubble = true;
	if(evt.preventDefault) evt.preventDefault()
	else event.returnValue = false;
};

system.events.translate = function(e)
{
	var evt = new Object;
	try
	{
		var crap = system.tools.is_ie();
		evt.target = crap ? window.event.srcElement : e.target;
		evt.event = crap ? window.event : e;
		evt.type = crap ? window.event.type : e.type;
		evt.layer_x = crap ? window.event.offsetX : e.layerX;
		evt.layer_y = crap ? window.event.offsetY : e.layerY;
		evt.page_x = crap ? window.event.x : e.pageX;
		evt.page_y = crap ? window.event.y : e.pageY;
		evt.screen_x = crap ? window.event.screenX : e.screenX;
		evt.screen_y = crap ? window.event.screenY : e.screenY;
		evt.key = crap ? window.event.keyCode : e.which;
		evt.button = crap ? window.event.button : e.which;
		evt.shift_key = crap ? window.event.shiftKey : e.modifiers | Event.SHIFT_MASK;
		evt.ctrl_key = crap ? window.event.ctrlKey : e.modifiers | Event.ALT_MASK;
		evt.alt_key = crap ? window.event.altKey : e.modifiers | Event.ALT_MASK;
		evt.translated = true;
	}
	catch(e){}
	return evt;
};

system.events.invoke = function(obj, observer, args) { return function() {  observer.apply(obj, args); }; };

system.events.add(window, "unload", system.events.cache.flush);
/*
 * system.forms.js
 * version 2.1.7
 * Copyright (C) Jason Mingl (Ratheous)
 *
 * Requires: system.tools.js  5.5.6+
 *           system.events.js 1.0.4+
 *
 * Optional: system.debug.js
 *
 <CHANGELOG>
 *
 *	08/24/2007 : 2.1.8 - Added onsubmit EventContext to form and form_manager
 						 Hidden fields are now automatically registered, but limited events are registered. unsure is onchange works
 *	07/30/2007 : 2.1.7 - Fields now assign element IDs if not present based on form_manager::id_prefix & id_registry
 *	05/11/2007 : 2.1.6 - Fields should now interpret 0|'' as false on checkboxes in set
 *	05/09/2007 : 2.1.5 - Added field cfg option default_init
 						 Fixed bug in form.reset/unlink. reset will now reset all fields without unlinking, unlink now properly handles unlinking
						 Fixed a bug with field.normal/original_class
						 Renamed validation.anything to unspecified
 *	05/08/2007 : 2.1.4 - Data can now be bound to forms and fields before or after initialization, individually by field or collectively by form
 						 Changed field.set_initial_value to field.set
 						 Added field option opts.bind for bound object
 						 Added field.get, bind & update
						 Added form.bind & update
						 Changed field.element.field_object to field.element.field
 *	04/30/2007 : 2.1.3 - Added id property to field class, converted to prototype-style class definitions
 *	04/29/2007 : 2.1.2 - Moved validation, notifications and rules routines into system.forms.validation.js, .notification.js and .rules.js
 *	04/19/2007 : 2.1.1 - Forms now auto-register disabled fields only if include_disabled is specified
 						 Added field.set_initial_value with option to hilight
						 Added form.check_modified
						 Added form.display_message convenience function
						 Fixed an error with field.original_class
 *	04/15/2007 : 2.1.0 - Fixed minor error with email validator
 						 Revamped/optimized events, added field.reset/unlink, form.reset/unlink, form_manager.remove_form
						 Fixed register_all_fields - wasn't loading checkboxes
 *	04/13/2007 : 2.0.9 - Fields now support the 'classname' option for setting which class(es) will be used for error/warning/modified hilighting
 								(used to be 'class' - #$%@ing IE)
 						 Removed date validator 'Date is in the future' warning
						 Cleaned up and shortened a bunch of code and corrected errors ... all over the place
						 Moved field configuration to a function 'cfg'
						 Aliased the form field registry as 'F' and '$'
						 Changed 'auto_register' to 'register'
						 Added 'required' to the form options as the default setting for auto registered fields
 *	04/08/2007 : 2.0.8 - Added integer validation
 						 Modified system.forms.form.register_field to accept registration of a particular field multiple times
						 Added auto_register option to form constructor
 *	03/30/2007 : 2.0.7 - Improved date validation
 *	03/15/2007 : 2.0.6 - checkbox validation - check_required_field
 *	03/04/2007 : 2.0.5 - Statusbar notifications should REALLY appear this time...
 *	03/04/2007 : 2.0.4 - Statusbar notifications now should appear on any button that submits the form, or the submit_element if it has been defined
 *	03/03/2007 : 2.0.3 - Field conditions now add style classes rather than changing them
 *
 </CHANGELOG>
 */

// ----------------------------------------------

if(typeof system != "object")
	var system = new Object;
if(typeof system.forms != "object") 
	system.forms = new Object;

system.forms.form_manager =
{
	id_prefix: '_field',
	id_registry: 0,
	form_registry: {},
	onsubmit: new EventContext, /* args: form, event */
	
	register_form: function(form)
	{
		if(!form instanceof system.forms.form)
			throw new Error("form must be an instance of system.forms.form");
		this.form_registry[form.name] = form;
	},
	remove_form: function(form)
	{
		if(!form instanceof system.forms.form)
			throw new Error("form must be an instance of system.forms.form");
		this.form_registry[form.name] = null;
	},
	handle_submit: function(form, evt) 
	{ 
		if(!form.validate())
		{
			system.events.halt(evt);

			if(system.forms.form_manager.last_click_event)
				form.display_message(system.forms.form_manager.last_click_event.target, form.submit_error);
			else if(form.submit_element)
				form.display_message(form.submit_element, form.submit_error);
		}
		else try { form.onsubmit.invoke(evt); this.onsubmit.invoke(form, evt); } catch(e) { alert('error: '+e.message); }
	},
	last_click_event: false,
	// This crap shouldn't be necessary, but for some reason getElementsByTagName can't find <input type="image">!?
	register_submit: function(element) { system.events.add($(element), 'click', form_mgr.default_click_event); },
	default_click_event: function(evt) { system.forms.form_manager.last_click_event = system.events.translate(evt); }
	
}; var form_mgr = system.forms.form_manager;

// ----------------------------------------------

system.forms.form = Class.prepare(
{
	onsubmit: new EventContext, /* args: event */
	
	initialize: function(opts)
	{
		try
		{
			this.element = $(opts.element);
			if(typeof this.element != "object")
				throw new Error("form ID not found");
			this.name = this.element.id;
			
			this.events = [];
			this.invoke = function(obj, observer, args) { return function() {  observer.apply(obj, [system.events.translate(arguments[0])].concat(args)); }; };
			this.handle_submit = function(form) { return function() { form_mgr.handle_submit(form, arguments[0]); }; };
			localsubmit = this.handle_submit(this);	this.events.push(system.events.add(this.element, "submit", localsubmit));
			
			this.opts = opts;
			this.bound = false;
			this.enable_submit = true;			this.field_list = new Array;	this.$ = this.F = this.field_registry = new Object;
			this.errors = false;				this.group_list = new Array;
			this.statusbar = opts.statusbar;	this.error_list = new Array;
			this.form_rules = new Array;		this.element.managed = true;
			this.submit_element = opts.submit_element == null ? null : $(opts.submit_element);
			this.submit_error = opts.submit_error == null ? "Errors on this form prevent it from being submitted" : opts.submit_error;
			
			if(opts['bind']) this.bind(opts['bind']);
			
			form_mgr.register_form(this);
			if(opts.register) this.register_all_fields(opts);
			else this.events.concat(system.events.add_by_type(document, 'INPUT', 'click', form_mgr.default_click_event));
		}
		catch(e) { system.debug.trace("system.forms.form: " + e, "error"); }
	},
	
	register_field: function(field)
	{
		if(!field instanceof system.forms.field) throw new Error("field must be an instance of system.forms.field");
		if(this.field_registry[field.element.id] instanceof system.forms.field)
		{
			var old_field = this.field_registry[field.element.id];
			old_field.unlink();
			field.index = old_field.index;
			field.next_field = old_field.next_field;
			field.prev_field = old_field.prev_field;
			if(field.prev_field /*!= null*/) field.prev_field.next_field = field;
			if(field.next_field /*!= null*/) field.next_field.prev_field = field;
			this.field_registry[field.element.id] = field;
			this.field_list[field.index] = field;
		}
		else
		{
			this.field_registry[field.element.id] = field;
			field.index = this.field_list.length;
			this.field_list[this.field_list.length] = field;
			if(this.last_field_inserted) { this.last_field_inserted.next_field = field; field.prev_field = this.last_field_inserted; }
			this.last_field_inserted = field;
		}
		if(this.bound) field.bind(this.bound_object);
	},
	
	register_field_group: function(group)
	{
		if(!field instanceof system.forms.field_group) throw new Error("field must be an instance of system.forms.field_group");
		this.group_list.push(group);
	},
	
	register_form_rule: function(rule)
	{
		if(!rule instanceof system.forms.rules.rule) throw new Error("rule must be an instance of system.forms.rules.rule");
		this.form_rules.push(rule);
	},
	
	validate: function()
	{
		this.error_list = new Array;
		for(var i = 0; i < this.field_list.length; i++)
		{
			this.field_list[i].initialized = true;
			this.field_list[i].validate();
			this.field_list[i].hilight();
			if(this.field_list[i].error) this.error_list.push(this.field_list[i].message);
		}
		if(this.error_list.length) this.errors = true;
		else this.errors = false;
		return !this.errors;
	},
	
	display_message: function(target, message) { if(this.statusbar) this.statusbar.show(target, message); },
	hide_message: function() { if(this.statusbar) this.statusbar.hide(); },
	
	check_modified: function(hilight)
	{
		for(var i = 0; i < this.field_list.length; i++)
		{
			if(hilight) this.field_list[i].hilight();
			else this.field_list[i].check_modified();
			if(this.field_list[i].modified) return true;
		}
		return false;
	},
	
	bind: function(obj, get, initial, validate, hilight)
	{
		this.bound = true;
		this.bound_object = obj;
		for(var i = 0; i < this.field_list.length; i++)
			this.field_list[i].bind(obj, get, initial, validate, hilight);
	},
	
	update: function(get, initial, validate, hilight)
	{
		for(var i = 0; i < this.field_list.length; i++)
			this.field_list[i].update(get, initial, validate, hilight);
	},
	
	register_all_fields: function(opts)
	{
		var itms = [];
		var l = this.element.getElementsByTagName('*');
		for (var i = 0; i < l.length; i++)
		{
			if(!opts['include_disabled'] && (l[i].disabled || l[i].readonly)) continue;
			if((l[i].tagName == 'INPUT' && (l[i].type != 'submit' && l[i].type != 'button' && l[i].type != 'image')) ||
				l[i].tagName == 'SELECT' ||
				l[i].tagName == 'TEXTAREA'
			  ) itms.push(l[i]);
			if(l[i].tagName == 'INPUT' && l[i].type != 'hidden') this.events.concat(system.events.add(l[i], 'click', form_mgr.default_click_event));
		}
		for(var i = 0; i < itms.length; i++)
			new system.forms.field({form:this, element:itms[i], name:itms[i].title, 
									required:opts['required'], default_init:opts['default_init']});
	},
	
	reset: function()
	{
		this.hide_message();
		for (var i = 0; i < this.field_list.length; i++) 
			this.field_list[i].reset();
	},
	
	unlink: function()
	{
		this.hide_message();
		for (var i = 0; i < this.field_list.length; i++) 
			this.field_list[i].unlink();
		for (var i = 0; i < this.events.length; i++)
			system.events.remove(this.events[i]);
		form_mgr.remove_form(this);
	},
	
	first_field: function() { return this.field_list[0]; },
	prev_field: function(field) { return field.prev_field; },
	next_field: function(field) { return field.next_field; },
	last_field: function() { return this.field_list[this.field_list.length-1]; }

}); var form = system.forms.form;


// ----------------------------------------------

system.forms.field = Class.prepare(
{
	initialize: function(opts)
	{
		try
		{
			if(!opts.form instanceof system.forms.form) throw new Error("'form' must be a form object");
			this.form = opts.form;	
			
			this.element = $(opts.element);
			if(typeof(this.element) == 'object')
				if(this.element.id.length == 0)
					this.element.id = form_mgr.id_prefix + (form_mgr.id_registry++);
				
			this.id = this.element.id;
			this.bound = false;
			this.field_rules = new Array;
			if(typeof(this.element) != "object") throw new Error("'element' (" + typeof(this.element) + ") must be a form element");
				
			this.prev_field = null;
			this.next_field = null;
			
			
			var e = [], add = system.events.add, el = this.element, f = this.form;
			if(this.element.type != 'hidden')
			{
				e.push(add(el, "mouseover", f.invoke(this, this.mouseover)));
				e.push(add(el, "mouseout", f.invoke(this, this.mouseout)));
				e.push(add(el, "keydown", f.invoke(this, this.keydown)));
				e.push(add(el, "keyup", f.invoke(this, this.keyup)));
				e.push(add(el, "focus", f.invoke(this, this.focus)));
				e.push(add(el, "blur", f.invoke(this, this.blur)));
			}
			e.push(add(el, "change", f.invoke(this, this.change)));
			this.events = e;
			
			this.cfg(opts);
			this.form.register_field(this);
		}
		catch(e) { system.debug.trace("system.forms.field: " + e, "error"); }
	},
	
	mouseover: function(evt) { if(this.form.statusbar) this.form.statusbar.field_message(this); },
	mouseout: function(evt) { if(this.form.statusbar) this.form.statusbar.hide(); },
	keydown: function(evt) { if((evt ? evt.which : window.event.keyCode) == 13) { this.update_status(); this.hilight(); system.events.halt(evt); } },
	keyup: function(evt) { if(this.ilock) { this.ilock = false; return; } if(this.initialized) { this.validate(false); this.update_status(); this.hilight(); } },
	focus: function(evt)
	{
		if(this.initialized) { this.validate(false); this.update_status(); this.hilight(); }
		if(this.prev_field instanceof system.forms.field) 
		{
			var field = this.prev_field;
			do { if(!field.initialized) field.validate(false); field.hilight(); field.initialized = true; } while(field = field.prev_field); 
		}
	},
	blur: function(evt) { this.validate(true); this.hilight(); this.initialized = true; if(this.form.statusbar) this.form.statusbar.hide(); },
	change: function(evt) { this.validate(true);  this.hilight(); },
	
	check_modified: function()
	{
		if(this.element.type == "checkbox")
			if(this.element.checked != this.initial_checked_state) this.modified = true;
			else this.modified = false;
		else
			if(this.element.value != this.initial_value) this.modified = true;
			else this.modified = false;
		return this.modified;
	},
	validate: function(format)
	{
		if(this.element.disabled) return this.error = false;
		for(var i = 0; i < this.field_rules.length; i++)
			if(!this.field_rules[i].test())
				return this.error;
		this.validator.validate(this, format);
		this.update(true);
		return this.error;
	},
	hilight: function()
	{
		this.check_modified();
		if(this.modified) this.style_target.className = this.modified_class;
		if(this.warning) this.style_target.className = this.warning_class;
		if(this.error) this.style_target.className = this.error_class;
		if(!this.modified && !this.warning && !this.error) this.style_target.className = this.normal_class;
	},
	update_status: function() { if(this.form.statusbar) this.form.statusbar.field_message(this); else this.element.title = this.message; },
	
	register_field_rule: function(rule)
	{
		if(!rule instanceof system.forms.rules.rule)
			throw new Error("rule must be an instance of system.forms.rules.rule");
		this.field_rules.push(rule);
	},
	
	reset: function()
	{
		this.style_target.className = this.normal_class;
		this.modified = this.warning = this.error = false; this.message = '';
		this.initial_checked_state = this.element.checked;
		this.initial_value = this.element.value;
		this.initialized = this.opts['default_init'] ? true : false;
		if(this.form.statusbar) this.form.statusbar.hide();
	},
	set: function(value, initial, validate, hilight)
	{
		// Need to do some testing on radio buttons
		if(this.element.tagName == 'INPUT' && this.element.type == 'checkbox')
			{ value = !value||value==0||value=='' ? false : true; if(initial) this.initial_checked_state = value; this.element.checked = value; }
		else 
			{ value = value ? value : ''; if(initial) this.initial_value = value; this.element.value = value; }
		if(validate) this.validate(true);
		if(hilight) this.hilight();
	},
	get: function(initial)
	{ 
		if(this.element.tagName == 'INPUT' && this.element.type == 'checkbox')
			return initial ? this.initial_checked_state : this.element.checked;
		else
			return initial ? this.initial_value : (this.element.value != '' ? this.element.value : (this.nullable ? null : ''));
	},
	bind: function(obj, get, initial, validate, hilight) 
	{ 
		this.bound = true;
		this.bound_object = obj; 
		if(get != null) this.update(get, initial, validate, hilight);
	},
	update: function(get, initial, validate, hilight)
	{
		if(!this.bound_object) return;
		if(get) this.bound_object[this.element.name] = this.get();
		else this.set(this.bound_object[this.element.name], initial, validate, hilight);
	},
	
	unlink: function() 
	{ 
		this.style_target.className = this.normal_class;
		for (var i = 0; i < this.events.length; i++)
			system.events.remove(this.events[i]);
	},
	
	cfg: function(opts)
	{
		if(this.opts) { Object.extend(this.opts, opts); opts = this.opts; } else this.opts = opts;
		this.element = $(opts.element);
		if(typeof(this.element) != "object") 
			throw new Error("'element' (" + typeof(this.element) + ") must be a form element");
		
		this.nullable = !(/\bnot_null/.test(this.element.className));
		
		this.initialized = opts['default_init'] ? true : false;
		this.initial_value = this.element.value != '' ? this.element.value : null;
		this.name = opts.name != null ? opts.name : this.element.name;
		this.validator = opts.validate_as != null ? opts.validate_as : system.forms.validation.unspecified;
		this.element.field = this;
		if(opts['bind']) this.bind(opts['bind']);
		
		//if(this.element.type == 'hidden') return;
		
		this.initial_checked_state = this.element.checked;
		this.required = opts.required;
		this.error = this.warning = this.modified = false;
		
		this.style_target = opts.style_target == null ? this.element : $(opts.style_target);
		this.message_target = opts.message_target == null ? this.style_target : $(opts.message_target);
		this.original_class = this.style_target.className;
		this.normal_class = opts.classname ? this.original_class + ' ' + opts.classname : this.original_class;
		this.modified_class = this.original_class + ' ' + this.normal_class + '_modified';
		this.warning_class = this.original_class + ' ' + this.normal_class + '_warning';
		this.error_class = this.original_class + ' ' + this.normal_class + '_error';
	}

}); var field = system.forms.field;


// ----------------------------------------------

system.forms.field_group = Class.prepare(
{
	initialize: function(o)
	{
		try
		{
			if(!o.form instanceof system.forms.form)
				throw new Error("'form' must be a form object");
			this.form = o.form;
			if(!o.fields instanceof Array)
				throw new Error("'fields' must be an Array object");
			this.fields = o.fields;
			this.disabled = false; // Need to make these arguments
			this.locked = false;
			this.hidden = false;
			this.enable = function(enable) { for(field in this.fields) field.element.disabled = !enable; this.disabled = !enable; };
			this.lock = function(lock) { for(field in this.fields) field.element.readonly = lock; this.locked = lock; };
			this.hide = function(hide) { for(field in this.fields) field.element.style.visibility = hide ? "hidden" : "visible"; this.hidden = hide; };
			this.form.register_field_group(this);
		}
		catch(e) { system.debug.trace("system.forms.form_manager.field_group: " + e, "error"); }
	}
}); var field_group = system.forms.field_group;

// ----------------------------------------------------------------------
// form rules

system.forms.rules = new Object;
var form_rules = system.forms.rules;

system.forms.rules.rule = Class.prepare(
{
	initialize: function(o)
	{
		this.form = o.form;
		this.criteria = o.criteria;
		this.enabled = o.enabled == null || o.enabled ? true : false;
		this.enable = function(enable) { this.enabled = enable; };
		this.message = o.message;
		this.group = o.group;
		var fs = this.group.fields;
		for(var i = 0; i < fs.length; i++) fs[i].register_field_rule(this);
		this.test = function()
		{
			if(this.enabled) return this.criteria(this, o); 
			return true; 
		};
		this.form.register_form_rule(this);
	}
}); var form_rule = system.forms.rules.rule;

// ----------------------------------------------------------------------
// form validation

system.forms.validation = {};
var validators = system.forms.validation;

var empty_string = /^\s*$/;

// Check required field ----------------------------------------------------------------------
// Returns true if required and present OR if not required. false if required and not present
system.forms.validation.check_required_field = function(f)
{
	if(eval(f.required))
	{
		if(f.element.type == 'radio')
		{
			var itms = document.getElementsByName(f.element.name);
			for(var i = 0, checked = false; i < itms.length; i++) if(itms.item(i).checked == true) checked = true;
			if(!checked) { f.error = true; f.message = f.name + ": please select an option"; return false; }
		}
		else if(f.element.type == 'checkbox') { if(!f.element.checked) { f.error = true; f.message = f.name + " must be checked"; return false; } }
		else if(empty_string.test(f.element.value)) { f.error = true; f.message = f.name + " is required"; return false; }
	}
	f.error = false; f.message = ""; return true;
};

// Validate unspecified ----------------------------------------------------------------------

system.forms.validation.unspecified =
{
	name: 'unspecified',
	format: function(v) { return v; },
	validate: function(f) { f.error = false; system.forms.validation.check_required_field(f); }
};/* 
 * system.forms.notification.js
 * version 1.0.1
 * Copyright (C) Jason Mingl (Ratheous)
 *
 * Requires: system.forms.js  2.0.0+
 *
 *	05/03/2007 : 1.0.1 - changed iframe hiding to display:none
 *	04/29/2007 : 1.0.0 - Moved out of system.forms.js v2.1.1
 *
 */

system.forms.warning_notification = new Object;
system.forms.warning_notification.tooltip = function(opts)
{
	this.frame = $(opts.frame);
	this.container = $(opts.container);
	this.x = opts.x;
	this.y = opts.y;
	this.initialized = false;
	this.message = "";
	this.field_message = function(f)
	{
		if(!(f instanceof system.forms.field))
			{ this.hide(); return; }
		if(f.warning || f.error)
			this.show(f.message_target, f.message);
		else { this.hide(); }
	};
	this.show = function(target, message)
	{
		var offset = system.tools.get_elem_offset(target);
		system.tools.set_elem_position(this.frame, offset.left + this.x, offset.top + this.y);
		if(this.container.innerHTML != message)
			this.container.innerHTML = message;
		this.frame.style.visibility = "visible";
		this.iframe = system.tools.iframe_shim(this.frame, "iFrameShimElement");
	};
	this.hide = function() { this.frame.style.visibility = "hidden"; if(this.iframe){this.iframe.style.display = "none";} };
}; var form_tooltip = system.forms.warning_notification.tooltip;/* 
 * system.forms.rules.js
 * version 1.0.0
 * Copyright (C) Jason Mingl (Ratheous)
 *
 * Requires: system.forms.js  2.0.0+
 *
 *	04/29/2007 : 1.0.0 - Moved out of system.forms.js v2.1.1
 *
 */

system.forms.rules.one_or_more = function(r)
{
	var er = true;
	var fs = r.group.fields;
	for(var i = 0; i < fs.length; i++)
		if(!empty_string.test(fs[i].element.value)) er = false;
	for(var i = 0; i < fs.length; i++)
	{
		fs[i].error = er;
		fs[i].message = rule.message = rule.message;
		fs[i].initialized = true;
		fs[i].hilight();
	}
	return !er;
};/* 
 * system.forms.validation.js
 * version 1.0.3
 * Copyright (C) Jason Mingl (Ratheous)
 *
 * Requires: system.forms.js  2.0.0+
 *
 *	06/16/2007 : 1.0.3 - All validators now perform their own tests. This can be used to collect more data through dynamic patterns
 *	05/10/2007 : 1.0.2 - Added names and default expressions to all validators 
 *	04/30/2007 : 1.0.1 - Validators are no longer defined as functions. No more 'new validators.email' etc.
 *	04/29/2007 : 1.0.0 - Moved out of system.forms.js v2.1.1
 *
 */

// ----------------------------------------------

if(!system.forms.validation)
	system.forms.validation = {};
var validators = system.forms.validation;

// Validate integer ----------------------------------------------------------------------

system.forms.validation.integer =
{
	name: 'integer',
	expr: /integer/,
	test: function(f) { return this.expr.test(f.element.className); },
	format: function(v) { return parseInt(v); }, //return parseInt(field.element.value);
	validate: function(f)
	{
		f.error = false;
		if(empty_string.test(f.element.value)) { system.forms.validation.check_required_field(f); return; }
		f.warning = false; f.error = false; f.message = "";
		if(isNaN(parseInt(f.element.value, 10))) { f.error = true; f.message = "Error: Not a valid number"; return; }
	}
};

// Validate ccnumber ----------------------------------------------------------------------

system.forms.validation.ccnumber =
{
	name: 'ccnumber',
	expr: /ccnumber/,
	test: function(f) { return this.expr.test(f.element.className); },
	error_message: 'Error: Not a valid credit card number',
	warning_message: 'Warning: This card number format is not recognized',
	format: function(v) { return v.replace(/[^\d]+/ig, ""); },
	validate: function(f, fmt)
	{
		f.error = false;
		if(empty_string.test(f.element.value)) { system.forms.validation.check_required_field(f); return; }
		f.warning = false; f.error = false; f.message = "";
		if(fmt) f.element.value = this.format(f.element.value);
		
		if(isNaN(parseInt(f.element.value, 10))) { f.error = true; f.message = this.error_message; return; }
		
		var len = f.element.value.length;
		var first = f.element.value.substring(0,1);
		if(!(len == 15 && first == '3')/*amex*/ && !(len == 16 && first >= '4' && first <= '6')/*visa/mast/disc*/)
		{ f.warning = true; f.message = this.warning_message; return; }
	}
};

// Validate date fields -------------------------------------------------------------------

system.forms.validation.date =
{
	name: 'date',
	expr: /date/,
	test: function(f) { return this.expr.test(f.element.className); },
	format: function(v)
	{
		var mysql_date_fmt = /(\d{4})[./-](\d{2})[./-](\d{2})/;
		var std_date_fmt = /\d{2}[./-]\d{2}[./-]\d{4}/;
		var tryformat = true;
		var tv = v;
		
		if(mysql_date_fmt.test(tv))
		{ 
			tv = tv.replace(/[^\d]+/ig, "");
			if(tv.length == 8)  { tv = tv.slice(4,6) + "/" + tv.slice(6,8) + "/" + tv.slice(0,4); tryformat = false; }
		}
		else
		{
			tv = tv.replace(/[^\d]+/ig, "");
			if(tv.length == 8) { tv = tv.slice(0,2) + "/" + tv.slice(2,4) + "/" + tv.slice(4,8); tryformat = false; }
			else if(tv.length == 6) { tv = tv.slice(0,2) + "/" + tv.slice(2,4) + "/20" + tv.slice(4,6); tryformat = false; }
		}
		if(tryformat)
		{
			var date = new Date(Date.parse(tv));
			var month = date.getMonth() + 1; month = month < 10 ? '0'+month : month;
			var day = date.getDate(); if(day < 10) day = "0" + day;
			var year = date.getFullYear();
			tv = month + "/" + day + "/" + year;
		}

		if(tv == "00/00/0000" || tv == "NaN/NaN/NaN")
			return v;
		return tv;
	},
	validate: function(f, fmt)
	{
		if(empty_string.test(f.element.value)) { system.forms.validation.check_required_field(f); return; }
		if(fmt) f.element.value = this.format(f.element.value); // Format data (if possible)
		f.warning = false; f.error = false; f.message = "";
		var std_date_fmt = /\d{2}[/]\d{2}[/]\d{4}/;
		
		if(!std_date_fmt.test(f.element.value))
		{ f.error = true; f.message = "Error: Invalid Date"; return; }
		
		var today = new Date;
		var date = new Date(Date.parse(f.element.value));

		if(date.toString() == "Invalid Date") { f.error = true; f.message = "Error: Invalid Date"; }
		else if(date.getYear() > (today.getYear() + 100)) { f.warning = true; f.message = "Warning: Date more than 100 years in the future! Possibly an error..."; }
		else if(date.getYear() < (today.getYear() - 10)) { f.warning = true; f.message = "Warning: Date is more than 10 years in the past"; }
	}
};

// Validate phone numbers --------------------------------------------------------------------

system.forms.validation.phone_number =
{
	name: 'phone_number',
	expr: /phone/,
	test: function(f) { return this.expr.test(f.element.className); },
	telephone_number: /[0-9 ()-]+$/,
	format: function(value)
	{
		value = value.replace(/[^\d]+/ig, "");
		if(value.length == 7) value = value.slice(0,3) + "-" + value.slice(3,7); /*555-5555*/	
		else if(value.length == 10) value = "(" + value.slice(0,3) + ") " + value.slice(3,6) + "-" + value.slice(6,10);	/*(555) 555-5555*/
		else if(value.length == 11)	value = value.slice(0,1) + " (" + value.slice(1,4) + ") " + value.slice(4,7) + "-" + value.slice(7,11);	/*1 (555) 555-5555*/
		return value;
	},
	validate: function(f, fmt)
	{
		if(empty_string.test(f.element.value)) { system.forms.validation.check_required_field(f); return; }
		if(fmt) f.element.value = this.format(f.element.value); // Format data (if possible)
		f.warning = false; f.error = false; f.message = "";
		for (var j = 0, numdigits = 0; j < f.element.value.length; j++)
			if (f.element.value.charAt(j) >= '0' && f.element.value.charAt(j) <= '9') 
				numdigits++;
		if(!this.telephone_number.test(f.element.value)) { f.error = true; f.message = "Error: not a valid telephone number. Characters permitted are digits, space and ()-"; }
		else if(numdigits < 10) { f.error = true; f.message = "Error: " + numdigits + " digits - valid length is 10-11 digits"; }
		else if(numdigits > 11) { f.error = true; f.message = "Error: " + numdigits + " digits - valid length is 10-11 digits"; }
	}
};

// Validate currency -------------------------------------------------------------

system.forms.validation.currency =
{
	name: 'currency',
	expr: /currency/,
	test: function(f) { return this.expr.test(f.element.className); },
	error_message: "Error: Invalid currency value",
	currency_fmt: /^\-?\(?\$\d+\.\d+\)?$/,
	format: function(v)
	{
		if(v == "") return v;
		v = new String(v);
		// If value contains any character other than -, (), $, . or a digit, skip formatting
		if(v.search(/[^\-^\(^\)^\$^.^\d]/i) != -1) return v;
		var neg = v.search(/\(/) != -1 || v.search(/-/) != -1;
		v = v.replace(/[\(\)\-\$]/ig, "");
		v = String(Math.abs(v));
		var decimals; if((pos = v.search(/\./i)) != -1) decimals = (v.length - pos) - 1;
		
		if(decimals)
		{
			if(decimals == 1) v = "$" + v + "0";
			else if(decimals == 2) v = "$" + v;
			else
			{
				v = v.replace(/[.]+/ig, "");
				var decimal_val = v.substr(pos, decimals);
				var whole_number = v.substr(0, v.length - decimals);
				dec_temp = decimal_val.substr(0, 2) + "." + decimal_val.substr(2, decimals - 2);
				dec_temp = Math.round(dec_temp);
				v = "$" + whole_number + "." + (dec_temp < 10 ? "0" + dec_temp : dec_temp);
			}
		}
		else { v = v.replace(/[^\d]+/ig, ""); v = "$" + v + ".00"; }
		
		if(neg) return "(" + String(v) + ")";
		else return v;
	},
	validate: function(f, fmt)
	{
		if(empty_string.test(f.element.value)) { system.forms.validation.check_required_field(f); return; }
		if(fmt) f.element.value = this.format(f.element.value); // Format data (if possible)
		f.warning = false; f.error = false; f.message = "";
		if(!this.currency_fmt.test(f.element.value)) { f.error = true; f.message = this.error_message; }
	}
};

// Validate email address -------------------------------------------------------------

system.forms.validation.email =
{
	name: 'email',
	expr: /email/,
	test: function(f) { return this.expr.test(f.element.className); },
	error_message: "Error: Invalid email address",
	warning_message: "Warning: Unusual email address",
	email_standard: /^[-a-z0-9!#$%&\'*+\/=?^_`{|}~]+(\.[-a-z0-9!#$%&\'*+\/=?^_`{|}~]+)*@(([a-z]([-a-z0-9]*[a-z0-9]+)?){1,63}\.)+([a-z]([-a-z0-9]*[a-z0-9]+)?){2,63}$/,
	/*'*/
	email_common: /^[A-Za-z][\w.-]+@\w[\w.-]+\.[\w.-]*[A-Za-z][A-Za-z]$/,
	format: function(v) { return v; },
	validate: function(f)
	{
		if(empty_string.test(f.element.value)) { system.forms.validation.check_required_field(f); return; }
		f.element.value = f.element.value.trim(); // Remove outer whitespace from value
		f.warning = false; f.error = false; f.message = "";	
		if(!this.email_standard.test(f.element.value)) { f.error = true; f.message = this.error_message; }
		else if(!this.email_common.test(f.element.value)) { f.warning = true; f.message = this.warning_message; }
	}
};

// Validate zipcodes -------------------------------------------------------------

system.forms.validation.zipcode =
{
	name: 'zipcode',
	expr: /zipcode/,
	test: function(f) { return this.expr.test(f.element.className); },
	format: function(value)
	{
		value = value.replace(/[^\d]+/ig, "");
		if(value.length == 9) value = value.slice(0,5) + "-" + value.slice(5,9); /*55555-5555*/	
		return value;
	},
	validate: function(f, fmt)
	{
		if(empty_string.test(f.element.value)) { system.forms.validation.check_required_field(f); return; }
		if(fmt) f.element.value = this.format(f.element.value); // Format data (if possible)
		f.warning = false; f.error = false; f.message = '';
		for (var j = 0, numdigits = 0; j < f.element.value.length; j++)
			if (f.element.value.charAt(j) >= '0' && f.element.value.charAt(j) <= '9') 
				numdigits++;
		if(numdigits != 5 && numdigits != 9) { f.error = true; f.message = "Error: " + numdigits + " digits. Valid length is 5 or 9 digits"; }
	}
};

Class.override(system.forms.form,
{
	validators: new Array,
	register_validator: function(validator) { this.validators.push(validator); },
	register_field: function(field)
	{
		try
		{
			for(var i = 0; i < this.validators.length; i++)
			{ 
				if(this.validators[i].test(field)) 
					field.validator = this.validators[i]; 
			};
			if(/required/.test(field.element.className)) field.required = true;
			if(/checkbox/.test(field.element.className)) field.style_target = $('_'+field.element.id) || field.element.id;
			this.parent.register_field.apply(this, [field]);
		} catch(e) { alert('form::register_field : '+e.message); }
	}
});/* 
 * system.navigation.js 
 * version 1.0.2
 * Copyright (C) Jason Mingl, ratheous@ratheous.net
 *
 * Requires: system.tools.js
 *           system.events.js
 *
 * Optional: system.debug.js
 
 *	04/15/2007 : 1.0.2 - Added 'retract' option to system.interface.tabstyles.foldout to allow or prevent all tabs from being retracted
 *	04/09/2007 : 1.0.1 - Added onactivate to tab_pg
 *	02/09/2007 : 1.0.0 - Initial release
*/

var POS_BOTTOM = 0;
var POS_RIGHT = 1;
var POS_RELATIVE = 2;
var POS_ABSOLUTE = 3;

var DEFAULT_OFFSET_X = 1;
var DEFAULT_OFFSET_Y = 1;

var DEFAULT_STYLE_ON = "";
var DEFAULT_STYLE_OFF = "";

if(typeof system != "object")
	var system = new Object;
if(typeof system.interface != "object")
	system.interface = new Object;

system.interface.menu = new Object;
system.interface.menu.menu_path = new Array;
system.interface.menu.event_queue = new Array;

system.interface.menu.timer_id = null;
system.interface.menu.timer_on = false;
system.interface.menu.timer_delay = 250;

/*
 * system.interface.menu.item constructor arguments:
 * any argument that is not required and is left undefined will use default values
 *
 *  element   : REQUIRED - id or node object of menu item. this element will trigger menu events
 *
 *  one or both of the following two  arguments must be defined
 *  parent    : system.interface.menu.item object. leave undefined for root menu items
 *  child     : id or node object of the container element for sub items. this element should be hidden initially
 *
 *  target    : id or node object of the element to recieve activate/deactivate style changes. leave undefined to default to the main element
 *  style_on  : activated state class name
 *  style_off : deactivated state class name
 *  position  : active state positioning mode for the child frame element. valid values: POS_BOTTOM, POS_RIGHT, POS_RELATIVE, POS_ABSOLUTE
 *  x         : x or left offset. behaves differently based on the above position setting. positive or negative integer
 *  y         : y or top offset. behaves differently based on the above position setting. positive or negative integer
 *
 * Example:
 *
 *  DEFAULT_POSITION = POS_BOTTOM;
 *  DEFAULT_STYLE_ON = 'ItemOn';
 *  DEFAULT_STYLE_OFF = 'ItemOff';
 *  var item1 = new menu_item({element:"item_root", child:"submenu1", x:0, y:1});
 *  new menu_item({element:'sub_item', parent:item1, target:'sub_item_target', style_on:'altItemOn', style_off:'altItemOff'});
 */

system.interface.menu.item = function(obj) 
{
	try
	{
		if (obj == undefined) return 'undefined';
    	if (obj == null) return 'null';
		this.parent = (obj.parent == undefined ? null : (typeof(obj.parent) == "object" ? obj.parent : null));
		this.child_frame = system.tools.get_var_object(obj.child);
		this.position = obj.position != undefined ? obj.position : DEFAULT_POSITION;
		this.offset_x = obj.x != undefined ? obj.x : DEFAULT_OFFSET_X;
		this.offset_y = obj.y != undefined ? obj.y : DEFAULT_OFFSET_Y;
		this.style_on = obj.style_on != undefined ? obj.style_on : DEFAULT_STYLE_ON;
		this.style_off = obj.style_off != undefined ? obj.style_off : DEFAULT_STYLE_OFF;
		this.elem = system.tools.get_var_object(obj.element);
		this.style_target = obj.target != undefined ? system.tools.get_var_object(obj.target) : this.elem;
		this.name = this.elem.id;
		system.events.add(this.elem, "mouseover", system.interface.menu.activator(this));
		system.events.add(this.elem, "mouseout", system.interface.menu.deactivator(this));
	}
	catch(e) { system.debug.trace("Error initializing menu item for id: '" + obj.element + "'", "error", e); }
}; var menu_item = system.interface.menu.item;

// Internal utility functions - not intended to be called directly ------------------------------------------------------------------------------

system.interface.menu.activator = function(obj)
{
	return function()
	{
		if(system.interface.menu.timer_on)
		{
			clearTimeout(system.interface.menu.timer_id);
			system.interface.menu.timer_id = null;
			system.interface.menu.timer_on = false;
		}

		var pos = obj;
		do { system.interface.menu.menu_path.unshift(pos); pos = pos.parent; } while(pos != null);
		system.interface.menu.deactivate();
		
		var path = "";
		for(i = 0; i < system.interface.menu.menu_path.length; i++)
		{
			path += system.interface.menu.menu_path[i].name;
			if(i < system.interface.menu.menu_path.length-1)
				path += " &raquo; ";
		}
		system.debug.status(path);
		
		obj.style_target.className = obj.style_on;
		if(obj.child_frame != null)
		{
			var offset = system.tools.get_elem_offset(obj.elem);
			if (obj.position == POS_BOTTOM) 
			{
				obj.child_frame.style.top = (offset.top + obj.elem.offsetHeight + obj.offset_y) + "px";
				obj.child_frame.style.left = (offset.left + obj.offset_x) + "px";
			}
			else if (obj.position == POS_RIGHT) 
			{
				obj.child_frame.style.top = (offset.top + obj.offset_y) + "px";
				obj.child_frame.style.left = (offset.left + obj.elem.offsetWidth + obj.offset_x) + "px";
			}
			else if (obj.position == POS_RELATIVE) 
			{
				obj.child_frame.style.top = (offset.top + obj.offset_y) + "px";
				obj.child_frame.style.left = (offset.left + obj.offset_x) + "px";
			}
			else if (obj.position == POS_ABSOLUTE) 
			{
				obj.child_frame.style.top = obj.offset_y + "px";
				obj.child_frame.style.left = obj.offset_x + "px";
			}
			obj.child_frame.style.visibility = "visible";			
		}
	};
};

system.interface.menu.deactivator = function(obj)
{
	return function()
	{
		var operation = function()
		{
			obj.style_target.className = obj.style_off;
			if(obj.child_frame != null)
				obj.child_frame.style.visibility = "hidden";
		};
		
		var deactivate_event = new Object;
		deactivate_event.name = obj.name;
		deactivate_event.deactivate = operation;
		system.interface.menu.event_queue.push(deactivate_event);
		system.interface.menu.menu_path = new Array();
		
		if(system.interface.menu.timer_on == false)
		{
			system.interface.menu.timer_id = setTimeout(system.interface.menu.deactivate, system.interface.menu.timer_delay);
			system.interface.menu.timer_on = true;
		}
	};
};

system.interface.menu.deactivate = function()
{
	var new_queue = new Array;
	while(itm = system.interface.menu.event_queue.pop())
	{
		found = false;
		for(i = 0; i < system.interface.menu.menu_path.length; i++)
			if(system.interface.menu.menu_path[i].name == itm.name)
				found = true;
		if(found == false) itm.deactivate();
		else new_queue.push(itm);
	}
	system.interface.menu.event_queue = new_queue;
	system.debug.status("Menu closed");
};

// --- tabclick function ------------------------------------------------------------------------

system.interface.tabclick = function(obj, onclass, offclass)
{
	obj = system.tools.get_var_object(obj);
	obj.hideFocus = true;
	if(system.interface.tabclick.lasttab != false)
	{
		system.interface.tabclick.lasttab.className = offclass;
		document.getElementById(system.interface.tabclick.lasttab.id.replace("_tab","")).style.display = "none";
	}
	obj.className = onclass;
	document.getElementById(obj.id.replace("_tab","")).style.display = "";
	system.interface.tabclick.lasttab = obj;
}; system.interface.tabclick.lasttab = false;

// --- Tab Manager ------------------------------------------------------------------------

system.interface.tab_manager = function(opts)
{
	this.group_list = new Array;
	this.register_tab_group = function(tab_group)
	{
		if(!tab_group instanceof system.interface.tab_group)
			throw new Error("tab_group must be an instance of system.interface.tab_group");
		this.group_list.push(this);
		eval("this." + tab_group.name + " = tab_group;");
	};
}; var tab_mgr = new system.interface.tab_manager();

system.interface.tab_group = function(opts)
{
	this.name = opts.name;
	this.style = opts.style;
	this.tab_list = new Array;
	tab_mgr.register_tab_group(this);
	this.register_tab = function(itm)
	{
		if(!itm instanceof system.interface.tab_page)
			throw new Error("itm must be an instance of system.interface.tab_page");
		this.tab_list.push(itm);
	};
	
}; var tab_grp = system.interface.tab_group; var default_tabs_grp = new system.interface.tab_group({name:"default_tabs"});

system.interface.tab_page = function(opts)
{
	this.id = opts.id;
	this.tab = $(opts.id+"_tab"); this.page = $(opts.id);
	this.className = this.tab.className + " ";
	this.active = opts.active != null ? opts.active : false;
	this.opts = opts;
	this.group = (opts.group instanceof system.interface.tab_group) ? opts.group : default_tabs_grp;
	this.tabstyle = opts.style == null ? this.group.style : opts.style;
	this.group.register_tab(this);
	
	this.activate = system.events.invoke(this.tabstyle, this.tabstyle.update, [this, 'click']);
	this.onactivate = opts.onactivate ? opts.onactivate : function(){};
	this.onevent = function(action, evt) { this.tabstyle.update(this, action, evt); };
	this.handle_click = function(itm) { return function() { itm.onevent("click", arguments[0]); }; };
	this.handle_dblclick = function(itm) { return function() { itm.onevent("dblclick", arguments[0]); }; };
	this.handle_mouseover = function(itm) { return function() { itm.onevent("mouseover", arguments[0]); }; };
	this.handle_mouseout = function(itm) { return function() { itm.onevent("mouseout", arguments[0]); }; };
	
	system.events.add(this.tab, "click", this.handle_click(this));
	system.events.add(this.tab, "dblclick", this.handle_dblclick(this));
	system.events.add(this.tab, "mouseover", this.handle_mouseover(this));
	system.events.add(this.tab, "mouseout", this.handle_mouseout(this));

	this.tabstyle.init(this);
}; var tab_pg = system.interface.tab_page;

system.interface.tabstyles = new Object;

system.interface.tabstyles.foldout = function(opts)
{
	this.tabon = opts.tabon;
	this.taboff = opts.taboff;
	this.single = opts.single ? opts.single : false;
	this.retract = opts.retract ? opts.retract : false;
	this.init = function(itm) { this.activate(itm, itm.active); }
	this.activate = function(itm, active) 
	{
		itm.active = active;
		itm.onactivate(itm);
		itm.tab.className = active ? itm.className + this.tabon : itm.className + this.taboff; 
		itm.page.style.display = active ? "" : "none";
	};
	this.update = function(itm, action, evt)
	{
		if(action == "click" || action == "dblclick")
		{
			if(this.single && !itm.active)
			{
				for(var i = 0; i < itm.group.tab_list.length; i++)
				{
					if(itm.group.tab_list[i] === itm)
						this.activate(itm.group.tab_list[i], true);
					else this.activate(itm.group.tab_list[i], false);
				}
			}
			else if(this.retract)
				this.activate(itm, !itm.active);
		}
	};
}// JavaScript Document

function sabre_forms_init()
{
	tablist = ['travel_search','flight_type_search'];
	tabs_init = true;
	init_tabs();
	
	formlist = ['roundform','onewayform','hotelform','carform','caymanform'];
	forms_init = true;
	init_forms();
	
	form_mgr.onsubmit.attach(formsubmit, this);
}

system.events.add(window, 'load', sabre_forms_init);

function formsubmit(form, evt)
{
	//system.events.halt(evt);
	try { $(form.name+'progress').className = 'progresson'; } catch (e) { alert(e.message); }
}
Class.override(system.forms.form,
{
	initialize: function(opts) 
	{ 
		this.register_validator(validators.phone_number);
		this.register_validator(validators.email);
		this.register_validator(validators.date);
		this.register_validator(validators.zipcode);
		this.register_validator(validators.currency);
		
		this.parent.initialize.apply(this, [opts]);
	}
});

/* Convenience functions for event-based form init */

var forms_init = false;
var formlist = new Array;

function init_forms()
{
	tooltip = new form_tooltip({frame:"warning", container:"warning_container", x:-25, y:-40})
	for(var i = 0; i < formlist.length; i++)
	{
		if($(formlist[i]))
			new form({element:formlist[i], register:true, statusbar:tooltip});
	}
}

function form_config()
{
	for(var i = 0; i < arguments.length; i++)
		formlist.push(arguments[i]);
	if(!forms_init) { system.events.add(window, 'load', init_forms); forms_init = true; }
}

/* Convenience functions for event-based tab init */

var tabs_init = false;
var tablist = new Array;

function init_tabs()
{
	var foldout_style = new system.interface.tabstyles.foldout(
	{
		tabon:"form_tab_selected", 
		taboff:"form_tab_inactive", 
		single:true,
		retract:false
	});
	for(var i = 0; i < tablist.length; i++)
	{
		if(!$(tablist[i]))
			continue;
		var tab_group = new tab_grp({name:tablist[i], style:foldout_style});
		var l = $(tablist[i]).getElementsByTagName('*');
		var exp = new RegExp('\\b'+tablist[i]+'\\b');
		var active = false;

		for (var j = 0; j < l.length; j++)
		if(exp.test(l[j].className))
		{
			active = /\bactive\b/.test(l[j].className);
			new tab_pg({id:l[j].id, group:tab_group, active:active});
		}
	}
}

function tab_config()
{
	for(var i = 0; i < arguments.length; i++)
		tablist.push(arguments[i]);
	if(!tabs_init) { system.events.add(window, 'load', init_tabs); tabs_init = true; }
}

// ------------------------------------------------------------------------------------------


function findCity(updateField) 
{
	var CityWin = window.open('/find-city/',updateField,"toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=435,height=380,alwaysRaised=yes,dependent=yes,screenX=300,screenY=200");
	CityWin.focus();
}

