var doDebug = true;

/**
 * For building URLS. Set the base URL in the constructor, then call
 * addParameter for each parameter. If you call a param that already exists,
 * that parameter will be overwritten. Finally, call getUrl to get the encoded URL.
 *
 * @param baseUrl
 */
function UrlBuilder(baseUrl)
{
	var KEY = 0;
	var VALUE = 1;

	this.base = baseUrl;
	this.parameters = new Array();

	this.addParameter = function(key, value)
	{
		for (var i = 0; i <= this.parameters.length; i++)
		{
			if (this.parameters[i] == undefined)
			{
				break;
			}
			if (this.parameters[i][KEY] == key)
			{
				this.parameters[i][VALUE] = value;
				return;
			}
		}

		this.parameters[i] = new Array(2);
		this.parameters[i][KEY] = key;
		this.parameters[i][VALUE] = value;

		return this;
	}

	this.getUrl = function()
	{
		var url = '';

		url += this.base;

		for (var i = 0; i < this.parameters.length; i++)
		{
			url += '@1@2=@3'
					.replace('@1', i == 0 && url.indexOf('?') < 0 ? '?' : '&')// && url.indexOf('?') < 0 allows for the url to have ?pararm
					.replace('@2', this.parameters[i][KEY])
					.replace('@3', this.parameters[i][VALUE]);
		}

		url = encodeURI(url);

		return url;
	}
}

/**
 * Opens pop-ups
 */
var Window = {

	centerWindow: function (url, width, height, extras, resizable)
	{
		return this.centerWindow2(url, width, height, extras, extras, extras, extras, resizable, resizable);
	},

	centerWindow2: function (url, width, height, toolbar, location, status, menubar, scrollbars, resizable)
	{
		var winid = new Date().getTime();

		return this.centerWindowWithID(url, winid, width, height, toolbar, location, status, menubar, scrollbars, resizable);
	},

	centerWindowWithID: function (url, id, width, height, toolbar, location, status, menubar, scrollbars, resizable)
	{
		var xMax, yMax;

		if (document.all)
		{
			xMax = screen.width
			yMax = screen.height;
		}
		else if (document.layers)
		{
			xMax = window.outerWidth
			yMax = window.outerHeight;
		}
		else
		{
			xMax = window.screen.availWidth
			yMax = window.screen.availHeight;
		}

		xMax = xMax - 10;
		yMax = yMax - 50;

		if (width == 0 || width > xMax)
		{
			width = xMax;
		}

		if (height == 0 || height > yMax)
		{
			height = yMax;
		}

		var xOffset = (xMax - width) / 2, yOffset = (yMax - height) / 2;

		return window.open(url, id,
				'width=' + width +
				',height=' + height +
				',screenX=' + xOffset +
				',screenY=' + yOffset +
				',top=' + yOffset +
				',left=' + xOffset +
				',toolbar=' + toolbar +
				',location=' + location +
				',status=' + status +
				',menubar=' + menubar +
				',scrollbars=' + scrollbars +
				',resizable=' + resizable);
	},

	centerWindowResizable:function (url, width, height)
	{
		return Window.centerWindow(url, width, height, "no", "no", "no", "no", "yes", "yes");
	},

	popup: function (url, width, height, name)
	{
		if (name)
		{
			id = name
		}
		else
		{
			day = new Date();
			id = day.getTime();
		}

		id = 'page' + id;

		var xMax, yMax;

		if (document.all)
		{
			xMax = screen.width;
			yMax = screen.height;
		}
		else
		{
			if (document.layers)
			{
				xMax = window.outerWidth;
				yMax = window.outerHeight;
			}
			else
			{
				xMax = 640;
				yMax = 480;
			}
		}

		width = (width == null) ? 400 : width;
		height = (height == null) ? 400 : height;

		var xOffset = (xMax - width) / 2, yOffset = (yMax - height) / 2;

		return Window.centerWindowWithID(url, id, width, height, 'no', 'no', 'no', 'no', 'no', 'yes');
	}
}

var Util = {

	isFunction: function()
	{
		return (typeof(arguments[0]) == 'function');
	},

	isNotUndefined: function()
	{
		return (arguments[0] !== undefined);
	},

	isMicrosoft: function()
	{
		return navigator.appName.indexOf("Microsoft") != -1;
	},

	isObject: function()
	{
		return typeof arguments[0] == 'object';
	},
	isArray: function()
	{
		if (Util.isObject(arguments[0]))
		{
			var criterion = arguments[0].constructor.toString().match(/array/i);
			return (criterion != null);
		}

		return false;
	},

	isString: function ()
	{
		if (typeof arguments[0] == 'string')
			return true;

		if (Util.isObject(arguments[0]))
		{
			var criterion = arguments[0].constructor.toString().match(/string/i);
			return (criterion != null);
		}

		return false;
	},

	isElement: function()
	{
		return arguments[0] && arguments[0].nodeType == 1;
	},

	trim: function()
	{
		var input = arguments[0];

		if (Object.isString(input))
		{
			return input
					.replace(/^\s*/, "")
					.replace(/\s*$/, "");
		}
		else
		{
			return input;
		}
	},

	isMicrosoft: function()
	{
		return navigator.appName.indexOf("Microsoft") != -1;
	},


	getWindowDimensions: function()
	{
		var theWidth = 0, theHeight = 0;
		if (typeof( window.innerWidth ) == 'number')
		{
			//Non-IE
			theWidth = window.innerWidth;
			theHeight = window.innerHeight;
		}
		else if (document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ))
		{
			//IE 6+ in 'standards compliant mode'
			theWidth = document.documentElement.clientWidth;
			theHeight = document.documentElement.clientHeight;
		}
		else if (document.body
					&& ( document.body.clientWidth || document.body.clientHeight ))
			{
				//IE 4 compatible
				theWidth = document.body.clientWidth;
				theHeight = document.body.clientHeight;
			}

		var dimensions = {width: theWidth, height: theHeight};

		return dimensions;
	}

}

var Loader = {

	/**
	 * Preload an image or an array of images.
	 * @param images
	 */
	preload: function(images)
	{
		Event.observe(window, "load", function()
		{
			if (Util.isArray(images))
			{
				var total = images.length;
				for (var i = 0; i < total; i++)
				{
					new Image().src = images[i];
				}
			}
			else if (Util.isString)
			{
				new Image().src = images;
			}

			Log.debug('preloaded images ', images)
		});
	}
}

var Cookie = {

	create: function (name, value, days)
	{
		var expires;

		if (days)
		{
			var date = new Date();
			date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
			expires = "; expires=" + date.toGMTString();
		}
		else
		{
			expires = "";
		}

		Log.debug('write cookie ...', name + ': ' + value);

		document.cookie = name + "=" + value + expires + "; path=/";
	},

	read: function (name)
	{
		Log.debug('read cookie ...', name);

		var nameEQ = name + "=";
		var ca = document.cookie.split(';');

		for (var i = 0; i < ca.length; i++)
		{
			var c = ca[i];
			while (c.charAt(0) == ' ') c = c.substring(1, c.length);
			if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
		}

		return null;
	}

}

var Effects = {

	/**
	 * Adds events to change the image source to the on and off versions. Also
	 * preloads the graphics. On and Off images are based on the original image src.
	 *
	 * @param element image element to preload for.
	 */
	buttonOnOff: function(element)
	{
		/* convert string to array of one element*/
		if (Object.isString(element) || Util.isElement(element))
		{
			element = [element];
		}

		var total = element.length;
		var e;

		for (var i = 0; i < total; i++)
		{
			try
			{
				e = $(element[i]);

				if (e !== null && e !== undefined)
				{
					var imageOff = e.getAttribute('src');
					var imageOn = imageOff.replace('_off.', '_on.');

					/*Log.debug('Observering ' + e.id + ' for ' + imageOff, imageOn);*/

					Element.observe(e, 'mouseover', Effects.setImageSource.bindAsEventListener(e, imageOn));
					Element.observe(e, 'mouseout', Effects.setImageSource.bindAsEventListener(e, imageOff));

					e.setStyle({cursor: 'pointer'});

					Loader.preload([imageOff, imageOn]);
				}
			}
			catch(ex)
			{
				Log.warn('failed to buttonOnOff ' + element[i], ex);
			}
		}
	},

	setImageSource: function(event, path)
	{
		/*Log.debug('toggled to ' + path, this)*/
		this.src = path;
	}
}

/**
 * Support for submitting forms, and setting page actions.
 */
var Forms = {

	/**
	 * Set page_action value
	 *
	 * @param action to set
	 */
	setPageAction: function(action, form_name)
	{
		var form;

		if (form_name)
		{
			form = document.forms[form_name];
		}
		else
		{
			form = document.forms[0];
		}

		var pageAction = form['page_action'];
		return Forms.setProperty(pageAction, action);
	},

	/**
	 * Submit the given form
	 *
	 * @param form_name name of the form
	 */
	submitForm: function (form_name, reloadParent)
	{
		var form;

		if (form_name)
		{
			form = document.forms[form_name];
		}
		else
		{
			form = document.forms[0];
		}

		form.submit();
	},

	/**
	 * Submits the given form form 'delete' as the page_action
	 *
	 * @param form_name name of the form
	 */
	submitDelete: function (form_name)
	{
		this.setPageAction('delete');
		this.submitForm(form_name);
	},

	/**
	 * Submits the given form form 'refresh' as the page_action
	 *
	 * @param form_name name of the form
	 */
	submitRefresh: function (form_name)
	{
		this.setPageAction('refresh');
		this.submitForm(form_name);
	},

	/**
	 * Submits the given form form 'update' as the page_action
	 *
	 * @param form_name name of the form
	 */
	submitUpdate: function (form_name)
	{
		this.setPageAction('update');
		this.submitForm(form_name);
	},

	/**
	 * Submits the given form form 'close' as the page_action
	 *
	 * @param form_name name of the form
	 */
	submitClose: function (form_name)
	{
		this.setPageAction('close');
		this.submitForm(form_name);
	},

	/**
	 * Submits the given form form 'search' as the page_action
	 *
	 * @param form_name name of the form
	 */
	submitSearch: function (form_name)
	{
		this.setPageAction('search');
		this.submitForm(form_name);
	},

	/**
	 * Submits the given form form 'save' as the page_action
	 *
	 * @param form_name name of the form
	 */
	submitSave: function (form_name)
	{
		this.setPageAction('save', form_name);
		this.submitForm(form_name);
	},

	/**
	 * Submits the given form form 'search' as the page_action
	 *
	 * @param form_name name of the form
	 */
	submitAdd: function (form_name)
	{
		this.setPageAction('add');
		this.submitForm(form_name);
	},

	setProperty: function(element, value)
	{
		if (typeof(element) == 'string')
		{
			var elementById = $(element)

			if (elementById !== null)
			{
				element = elementById;
			}
		}

		if (element == null
				|| element == undefined
				|| typeof(element) !== 'object')
		{
			element = document.forms[0][element];
		}

		element.value = value;

		return this;
	},

	getProperty: function(element, defaultValue)
	{
		if (defaultValue == undefined)
		{
			defaultValue = '';
		}

		if (typeof(element) == 'string')
		{
			var elementById = $(element)

			if (elementById !== null)
			{
				element = elementById;
			}
		}

		if (element == undefined
				|| element == null
				|| typeof(element) !== 'object')
		{
			var form = document.forms[0];

			if (form !== undefined)
			{
				element = form[element];
			}
		}

		if (element !== undefined && element !== null)
		{
			defaultValue = element.value;
		}

		return defaultValue;
	},

	checks: {

		/**
		 * Toggles all checkboxes in the form as either checked or checked, depending on the
		 * status of the 'all' checkbox element.
		 *
		 * @param checkAllElement HTML checkbox element
		 * @param form the form (optional - defaults to forms[0])
		 */
		toggleCheckAll: function (checkAllElement, form)
		{
			if (form == null)
			{
				form = document.forms[0];
			}

			form = Element.extend(form);

			var checkboxes = form.getInputs('checkbox')
			checkboxes = checkboxes.without(checkAllElement);

			var checkedValue = checkAllElement.checked;

			checkboxes.each(function(checkbox)
			{
				checkbox.checked = checkedValue;
			});
		},

		/**
		 * Called after a checkbox is toggled on or off. This updates the 'all'
		 * checkbox status.
		 *
		 * @param checkbox HTML checkbox element that was toggeled
		 * @param form the form (optional - defaults to forms[0])
		 */
		toggleCheckOne: function (checkbox, form)
		{
			Forms.checks.updateCheckAll(form);
		},

		/**
		 *  Updates the 'all' checkbox checked value. If all checkboxes on the form
		 * are checked, the the 'all' will be checked, otherwise, the 'all' is unchecked.
		 *
		 * @param form the form (optional - defaults to forms[0])
		 */
		updateCheckAll: function (form)
		{
			if (form == null)
			{
				form = document.forms[0];
			}

			form = Element.extend(form);

			var checkAllElement = form['all'];

			if (checkAllElement == null)
			{
				return;
			}

			var checkboxes = form.getInputs('checkbox')
			checkboxes = checkboxes.without(checkAllElement);

			var allChecked = true;

			checkboxes.each(function(checkbox)
			{
				if (!checkbox.checked)
				{
					allChecked = false;
				}
			});

			checkAllElement.checked = allChecked;
		}
	}
}

/**
 * This Log class logs to FireFox's FireBug console,
 * if the console exists, otherwise, the statement throws an exception, which is caught and
 * simply discarded. This probably slightly impairs performance on any browser other than FF.
 */
var Log = {

	enabled: location.href.indexOf('localhost') > 0 || location.href.indexOf('alpha.retrieve.com') > 0,

	trace: function()
	{
		if (!Log.enabled) return;

		try
		{
			Log.Firebug.trace();
		}
		catch(ex)
		{
		}
	},

	group: function(arg, arg2)
	{
		if (!Log.enabled) return;

		if (!arg2)
		{
			arg2 = '';
		}

		try
		{
			Log.Firebug.group(arg, arg2);
		}
		catch(ex)
		{
		}

	},

	groupEnd: function()
	{
		if (!Log.enabled) return;

		try
		{
			Log.Firebug.groupEnd();
		}
		catch(ex)
		{
		}
	},

	debug: function (arg, arg2)
	{
		if (!Log.enabled) return;

		if (!arg2)
		{
			arg2 = '';
		}

		try
		{
			Log.Firebug.debug(arg, arg2);
		}
		catch(ex)
		{
		}
	},

	info: function (arg, arg2)
	{
		if (!Log.enabled) return;

		if (!arg2)
		{
			arg2 = '';
		}

		if (Log.enabled)
		{
			try
			{
				Log.Firebug.info(arg, arg2);
			}
			catch(ex)
			{
			}
		}
	},

	warn: function (arg, arg2)
	{
		if (!Log.enabled) return;

		if (!arg2)
		{
			arg2 = '';
		}

		if (Log.enabled)
		{
			try
			{
				Log.Firebug.warn(arg, arg2);
			}
			catch(ex)
			{
			}
		}
	},

	error: function (arg, arg2)
	{
		if (!Log.enabled) return;

		if (!arg2)
		{
			arg2 = '';
		}


		if (Log.enabled)
		{
			try
			{
				/*if (Util.isMicrosoft)alert(Object.toJSON(arg));
				 else */
				Log.Firebug.error(arg, arg2);
			}
			catch(ex)
			{
			}
		}
	},

	Firebug:{

		window: undefined,
		collapsedGroups: true,

		getWindow: function()
		{
			if (Log.Firebug.window === undefined)
			{
				var parent = window.parent;

				while (parent.parent !== parent)
				{
					parent = parent.parent;
				}

				Log.Firebug.window = parent;
			}

			return Log.Firebug.window;
		},

		debug:function(arg1, arg2)
		{
			var window = Log.Firebug.getWindow();

			if (window.console)
			{
				window.console.debug(arg1, arg2);
			}
			else if (console)
			{
				console.debug(arg1, arg2);
			}
		},

		info:function(arg1, arg2)
		{
			var window = Log.Firebug.getWindow();

			if (window.console)
			{
				window.console.info(arg1, arg2);
			}
			else if (console)
			{
				console.info(arg1, arg2);
			}
		},

		warn:function(arg1, arg2)
		{
			var window = Log.Firebug.getWindow();

			if (window.console)
			{
				window.console.warn(arg1, arg2);
			}
			else if (console)
			{
				console.debug(arg1, arg2);
			}
		},

		error:function(arg1, arg2)
		{
			var window = Log.Firebug.getWindow();

			if (window.console)
			{
				window.console.error(arg1, arg2);
			}
			else if (console)
			{
				console.error(arg1, arg2);
			}

			if (window.console)
			{
				window.console.trace();
			}
			else if (console)
			{
				console.trace();
			}
		},

		trace: function()
		{
			var window = Log.Firebug.getWindow();

			if (window.console)
			{
				window.console.trace();
			}
			else if (console)
			{
				console.trace();
			}

		},

		group: function(arg1, arg2)
		{
			var window = Log.Firebug.getWindow();

			if (window.console)
			{
				if (Log.Firebug.collapsedGroups) window.console.groupCollapsed(arg1, arg2);
				else window.console.group(arg1, arg2);
			}
			else if (console)
			{
				if (Log.Firebug.collapsedGroups) console.groupCollapsed(arg1, arg2);
				else console.group(arg1, arg2);
			}
		},
		groupEnd: function()
		{
			var window = Log.Firebug.getWindow();

			if (window.console)
			{
				if (Log.Firebug.collapsedGroups) window.console.groupEnd();
				else window.console.groupEnd();
			}
			else if (console)
			{
				if (Log.Firebug.collapsedGroups) console.groupEnd();
				else console.groupEnd();
			}
		}
	},

	Alert:{

		debug:function(arg1, arg2)
		{
			alert('debug: ' + arg1);

			if (arg2)
			{
				alert('debug: ' + arg2);
			}
		},

		info:function(arg1, arg2)
		{
			alert('info: ' + arg1);

			if (arg2)
			{
				alert('info: ' + arg2);
			}
		},

		warn:function(arg1, arg2)
		{
			alert('warn: ' + arg1);

			if (arg2)
			{
				alert('warn: ' + arg2);
			}
		},

		error:function(arg1, arg2)
		{
			arg1 = Object.toJSON(arg1);

			alert('error: ' + arg1);

			if (arg2)
			{
				alert('error: ' + arg2);
			}
		}
	}
};


var Waiter = {

	close: function()
	{
		try
		{
			/* close the waiter window */
			myHandle = window.open('', 'waiter');
			myHandle.close();
		}
		catch(ex)
		{
		}
	}
}
