// Javascript file with miscellaneous static functions NOT specific to any web project.

// Dropdowns

var Dropdown = 
{
	replaceOptions: function(element, associativeArray, firstItemText)
	{
		var selectedValue = "";
		if (element.options.selectedIndex >= 0)
			selectedValue = element.options[element.options.selectedIndex].value;
		
		while (element.options.length > 0)
			element.options[0] = null;
	     
		if (associativeArray == null)
			return;
			
		if (firstItemText != null)
			this.addOption(element, "", firstItemText, selectedValue);	
			
		for (id in associativeArray)
			this.addOption(element, id, associativeArray[id], selectedValue);
	},

	addOption: function(element, value, text, valueToSelect)
	{
		var option = new Option;
		option.value = value;
		option.text = text;
		
		element.options[element.options.length] = option;
		if (valueToSelect == value)
			option.selected = true;
			
		return option;
	},

	removeOption: function(element, value)
	{
		for (var i = element.options.length - 1; i >= 0; i--)
		{
			if (value == element.options[i].value)
				element.options[i] = null;
		}
	},

	indexOf: function(element, value)
	{
		for (var i = 0; i < element.options.length; i++)
		{
			if (value == element.options[i].value)
				return i;
		}
		return -1;
	},

	removeFirstOptionIfBlank: function(element)
	{
		if (element.options.length > 0 && element.options[0].value == "" && !element.options[0].selected)
			element.options[0] = null;
	},
	
	swapOptions: function(element, fromIndex, toIndex)
	{
		if (fromIndex == toIndex ||
			fromIndex < 0 || toIndex < 0 ||
			fromIndex >= element.options.length || toIndex >= element.options.length)
			return;
			
		var value = element.options[fromIndex].value;
		var text = element.options[fromIndex].text;
		var selected = element.options[fromIndex].selected;
		
		element.options[fromIndex].value = element.options[toIndex].value;
		element.options[fromIndex].text = element.options[toIndex].text;
		element.options[fromIndex].selected = element.options[toIndex].selected;

		element.options[toIndex].value = value;
		element.options[toIndex].text = text;
		element.options[toIndex].selected = selected;
	},	
	
	// Sort the items on a dropdown
	// by = 0 - order by text (default)
	// by = 1 - order by value
	// by = 2 - order by color
	// by = 3 - order by background color
	// by = 4 - order by class name
	// by = 5 - order by id
	// numeric = if true sorts numbers e.g. 2 before 10
	// caseSensitive = casesensitive e.g. a before Z*/
	sortOptions: function(element, by, numeric, caseSensitive) 
	{ 	
		by = (parseInt("0" + by) > 5) ? 0 : parseInt("0" + by);
		if (element.tagName.toLowerCase() != "select" && element.length < 2)
			return false;

		var elements = new Array();
		for (var i = 0; i < element.length; i++)
			elements[elements.length] = new Array((document.body.innerHTML ? element[i].innerHTML : element[i].text), element[i].value, (element[i].currentStyle ? element[i].currentStyle.color : element[i].style.color), (element[i].currentStyle ? element[i].currentStyle.backgroundColor : element[i].style.backgroundColor), element[i].className, element[i].id, element[i].selected);
	
		if (numeric) 
		{
			for (var i = 0; i < elements.length - 1; i++) 
			{
				for (var j = i + 1; j < elements.length; j++) 
				{
					if (parseInt(elements[j][by], 10) < parseInt(elements[i][by], 10)) 
					{
						var dummy = elements[i];
						elements[i] = elements[j];
						elements[j] = dummy;
					}
				}
			}
		} 
		else 
		{
			for (var i = 0; i < elements.length - 1; i++) 
			{
				for (var j = i + 1; j < elements.length; j++) 
				{
					if (caseSensitive) 
					{
						if (elements[j][by].toLowerCase() < elements[i][by].toLowerCase()) 
						{
							var dummy = elements[i];
							elements[i] = elements[j];
							elements[j] = dummy;
						}
					} 
					else 
					{
						if (elements[j][by] < elements[i][by]) 
						{
							var dummy = elements[i];
							elements[i] = elements[j];
							elements[j] = dummy;
						}
					}
				}
			}
		}
	
		for (i = 0; i < element.length; i++) 
		{
			if (document.body.innerHTML) 
				element[i].innerHTML = elements[i][0];
			else 
				element[i].text = elements[i][0];
			element[i].value = elements[i][1];
			element[i].style.color = elements[i][2];
			element[i].style.backgroundColor = elements[i][3];
			element[i].className = elements[i][4];
			element[i].id = elements[i][5];
			element[i].selected = elements[i][6];
		}
	}	
}


// Validators

var Validate = 
{
	verifyRequiredField: function(element, fieldName, showError)
	{
		if (element.options)
		{
			if (element.options[element.selectedIndex].value == "")
			{			
				if (showError != true)
					throw new Error("Please choose the " + fieldName);
					
				alert("Please choose the " + fieldName);
				element.focus();
			}
		}
		
		if (element.value == "")
		{			
			if (showError != true)
				throw new Error("Please enter the " + fieldName);

			alert("Please enter the " + fieldName);
			element.focus();
		}
	},
	
	verifyNumericRangeField: function(element, fieldName, minValue, maxValue, showError)
	{
		var value = Number(element.value);
		if (isNaN(value) || value < minValue || value > maxValue)
		{
			if (showError != true)
				throw new Error("Please enter the " + fieldName + " as a number between " + minValue + " and " + maxValue);
						
			alert("Please enter the " + fieldName + " as a number between " + minValue + " and " + maxValue);
			element.focus();
		}
	}	
}		


// Cookies

var Cookie = 
{
	getValue: function(name) 
	{
		var nameEQ = name + "=";
		var ca = document.cookie.split(';');
		for (var i = 0; i < ca.length; i++)
		{
			var c = ca[i];
			while (c.charAt(0) == ' ') 
				c = c.substring(1, c.length);
			if (c.indexOf(nameEQ) == 0) 
				return c.substring(nameEQ.length, c.length);
		}
		return "";
	},

	setValue: 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();
		}
		document.cookie = name+"="+value+expires+"; path=/";
	}
}


// Generic control utilities

var Control = 
{
	// Retrieves the left and top offset with respect to the body inside an array.
	getOffset: function(element)
	{
		var result = [element.offsetLeft, element.offsetTop];
		
		while (element != document.body)
		{
			element = element.offsetParent;
			if (!element)
				break;
			result[0] += element.offsetLeft;
			result[1] += element.offsetTop;
		}
		
		return result;
	},
	
	// Finds a control by its id and returns its object.
	find: function(id, doc) 
	{ 
		var p, i, x;  
		if (!doc) 
			doc = document; 
		if ((p = id.indexOf("?")) > 0 && parent.frames.length) 
		{
			doc = parent.frames[id.substring(p + 1)].document; 
			id = id.substring(0, p);
		}
		if(!(x = doc[id]) && doc.all) 
			x = doc.all[id]; 
		for (i = 0; !x && i < doc.forms.length; i++) 
			x = doc.forms[i][id];
		for (i = 0; !x && doc.layers && i < doc.layers.length; i++) 
			x = findObj(id, doc.layers[i].document);
		if (!x && doc.getElementById) 
			x = doc.getElementById(id); 
		if (!x && doc.getElementsByName && doc.getElementsByName(id))
			x = doc.getElementsByName(id)[0]; 
		return x;
	},

	// Gets the control on the page with a certain attribute set to a given value; or null if none exists.
	findWithAttribute: function(attributeName, value, doc)
	{
		if (!doc) 
			doc = document; 			
		var container = doc.all ? doc.all : doc.forms[0];		
		
		for (var i = 0; i < container.length; i++)
		{
			if (container[i][attributeName] == value)
				return container[i];
		}	
		return null;
	},	
	
	// Handler for the onkeydown event used to associate a text control to a button so that when 
	// a key (such as Enter) is pressed on the textbox, the button is clicked.  This is useful for forms with multiple
	// submit buttons.
	onKeyDownClickButton: function(textControl, event, keyCode, buttonID)
	{
		// Only worry about the specific key
		if (!((event.keyCode && event.keyCode == keyCode) || (event.which && event.which == keyCode)))
			return true;
			
		var buttonToClick = Control.find(buttonID);
		if (buttonToClick)
		{			
			// Add two extra handlers in case the user presses the key while the AutoComplete dropdown is visible on the IE browser.
			textControl.onkeyup = function() { if (window.buttonToClick && window.buttonToClick.click) window.buttonToClick.click(); };
			textControl.onpropertychange = function() { if (window.buttonToClick) window.buttonToClick = null; };
			window.buttonToClick = buttonToClick;
		}		
		else
			textControl.title = "Error: Button control '" + buttonID + "' does not exist!";
		return false;
	},

	// Handler for the onkeydown event used to associate a text control to another text control so that when 
	// a key (such as Enter) is pressed on the first textbox, the second one gains focus.
	onKeyDownChangeFocus: function(textControl, event, keyCode, textID)
	{
		// Only worry about the specific key
		if (!((event.keyCode && event.keyCode == keyCode) || (event.which && event.which == keyCode)))
			return true;
			
		var textBoxToFocus = Control.find(textID);
		if (textBoxToFocus)
			textBoxToFocus.focus();
		else
			textControl.title = "Error: TextBox control '" + textID + "' does not exist!";
		return false;
	}
}

// Generic debugging utilities

var Debug = 
{
	showProperties: function(obj)
	{
		var properties = "";	
		for (prop in obj)
			properties += ("." + prop + " = " + obj[prop] + "\n");	
		return alert(obj + "\n" + properties);
	}	
}

