/*****************************
 * Author: Andy Hill (athill)
 * Last updated 7/31/2006
 * Functions for manipulating the document object model
 * Tested for cross-browser compatibility (modern browsers)
 * Several functions borrowed or adapted from quirksmode.com
 *****************************/


visibleVar = null;
var what;
/**
 * Checks for browser capabilities
 *
 * Sets global variable "what" to ns4,ie,moz or none
 * 
 */ 
function getBrowser() {
	if ($.browser.msie) what = "ie";
	else what = "moz";
	return what;
}

/**
 * Checks if an object is null
 * @return boolean
 */
function isNull(a) {
	if (typeof a == 'undefined') return false;
    return typeof a == 'object' && !a;
}
/**
 * Given a unique HTML id, returns the element object 
 *
 * @param id unique id attribute on HTML page
 * @return HTML element
 */
function getElement(id) {
	return $('#' + id);
}
/**
 * Given a unique HTML ID, returns the element's style object
 *
 * @param id  unique id attribute on HTML page
 * $return an HTML element's style object
 */
function getStyleObject(id) {
	var obj = getElement(id);
	if (document.getElementById || document.all) {
		return obj.style;
	} else {
		return obj;
	}
}

/**
 * Given an element's ID, returns the value of a style looking through inline styles and embedded and external style sheets
 * Removes 'px' from float values
 *
 * @param id unique id attribute on HTML page
 * @param style - name of style in javascript format (camelCase rather than hyphen-ate)
 * @return current value of specified element style
 */
function getStyleById(id, style) {
	return $("#" + id).css(style);
}

/**
 * Sets the value of a style property of a given element
 * Adds 'px' to float values
 *
 * @param id Unique id attribute on HTML page
 * @param style Name of style in javascript format (camelCase rather than hyphen-ated)
 * @param value Value to set style to											   
 */
function setStyleById(id, style, value) {
	$("#" + id).css(style, value);
}

/**
 * Toggles visibility of a block element 
 * Used in sesDivCollapse 
 * @param id Unique id attribute on HTML page
 */
function toggleVisible(id) {
	var vis = getStyleById(id, 'display');
	var newVal = (vis != "block") ? "block" : "none";
	setStyleById(id, 'display', newVal);
}


/**
 * Toggles visibility of an inline element 
 * @param id Unique id attribute on HTML page
 */
function toggleSpan(id) {
	var vis = getStyleById(id, 'display');
	var newVal = (vis != "inline") ? "inline" : "none";
	setStyleById(id, 'display', newVal);
}

/**
 * Toggles the icon from + to - and toggles the alt attribute text as well
 * Used in sesDivCollapse
 * Requires nodeopen.gif and nodeclosed.gif in /images/treeNav directory
 *
 * @param id Unique id attribute on HTML page
 */
function toggleIcon(id) {
	var vis = document.getElementById(id).src;
	var isOpen = vis.indexOf("/images/treeNav/nodeopen.gif") > -1;
	var newVal = (isOpen) ? "/images/treeNav/nodeclosed.gif" : "/images/treeNav/nodeopen.gif";
	var altVal = (isOpen) ? "Node is closed" : "Node is open";
	document.getElementById(id).src = newVal;
	document.getElementById(id).alt = altVal;
}

/**
 * Toggles the display of table-row elements
 * Requires a table row with id of {id} and a count of rows to toggle with ids of form {id}_{i}
 * For example:
 * <table>
 * <tr id="test" onclick="toggleRowDisplay(this, 2);"><td> ... </td></tr>
 * <tr id="test_1"><td> ... </td></tr>
 * <tr id="test_2"><td> ... </td></tr>
 * </table>
 * Would toggle "test_1" and "test_2" when "test" is clicked
 * @param row HTML table-row element
 * @param count Number of appropriately IDed table rows to toggle
 */
function toggleRowDisplay(row, count) {
	var show = (what == "ie") ? "block" : "table-row";
	for (i = 1; i <= count; i++) {
		var current = getStyleById(row.id + "_" + i, "display");
		var style = (current == show) ? "none" : show;
		setStyleById(row.id + "_" + i, "display", style);
	}
}

/**
 * Toggles table visibility
 * 
 * @param id ID of HTML table whose visibility is to be toggled.
 */
function toggleTableVisible(id) {
	var hidden = $("#" + id).css('display') == 'none';
	if (hidden) $("#" + id).show();
	else $("#" + id).hide();
}

/**
 * Sets the content inside HTML tags identified by the ID
 *
 * @param id Unique id attribute of HTML element
 * @param content The text with which to fill the inner HTML
 */
function setInnerHtml(id, content) {
	document.getElementById(id).innerHTML = content;
}

/**
 * Retrieves the content inside HTML tags identified by the id
 * @param id Unique id attribute on HTML page
 * @return Content of requested HTML element
 */
function getInnerHtml(id) {
	return document.getElementById(id).innerHTML;
}

/*********************
start add/remove event handlers
************************/
/**
 * Add an event to an HTML element programtically
 * @param object HTML element to add/remove event to/from
 * @param evType Type of event w/o the "on"; ie, "mousedown"
 * @param fn Event handler
 * @param useCapture - Whether events should bubble -- usually set to false, irrelevant in IE
*/
function addEvent(obj, evType, fn, useCapture){
  if (obj.addEventListener){
    obj.addEventListener(evType, fn, useCapture);
    return true;
  } else if (obj.attachEvent){
    var r = obj.attachEvent("on"+evType, fn);
    return r;
  } else {
    alert("Handler could not be attached");
  }
}

/**
 * Remove an event to an HTML element programtically
 * @param object HTML element to add/remove event to/from
 * @param evType Type of event w/o the "on"; ie, "mousedown"
 * @param fn Event handler
 * @param useCapture - Whether events should bubble -- usually set to false, irrelevant in IE
*/
function removeEvent(obj, evType, fn, useCapture){
  if (obj.removeEventListener){
    obj.removeEventListener(evType, fn, useCapture);
    return true;
  } else if (obj.detachEvent){
    var r = obj.detachEvent("on"+evType, fn);
    return r;
  } else {
    alert("Handler could not be removed");
  }
}


/**
 * Finds current position of element
 * @param oLink - a DOM element
 * @return Array of form [x, y] containing element's position 
 */
function findPosition( elem ) {
  if( elem.offsetParent ) {
    for( var posX = 0, posY = 0; elem.offsetParent; elem = elem.offsetParent ) {
      posX += elem.offsetLeft;
      posY += elem.offsetTop;
    }
    return [ posX, posY ];
  } else {
    return [ elem.x, elem.y ];
  }
}

/**
 * Retrieve's the current window's size
 *
 * @return Returns an (x, y) array of current window's size
 */
function getWindowSize() {
	var frameWidth;
	var frameHeight;
	if (self.innerWidth) {
		frameWidth = self.innerWidth;
		frameHeight = self.innerHeight;
	} else if (document.documentElement && document.documentElement.clientWidth) {
		frameWidth = document.documentElement.clientWidth;
		frameHeight = document.documentElement.clientHeight;
	} else if (document.body) {
		frameWidth = document.body.clientWidth;
		frameHeight = document.body.clientHeight;
	}
	return [frameWidth, frameHeight];
}

/**
 * Populates an HTML dropdown from an array
 *
 * @param field An HTML select object
 * @param arr An array of values. Either a 1-dimensional array will place the same value for value and test, 
 * 		or a 2-dimenstion array of the form arr[i]["text"] and arr[i]["value"] 
 */
function populateDropdownFromArray(htmlField, arr) {
	htmlField.options.length = 0;
	if (isArray(arr[0])) {		
		for ( var i = 0; i < arr.length; i++) {
			htmlField.options[i] = new Option(arr[i].text, arr[i].value);
		}
	} else {
		for ( var i = 0; i < arr.length; i++) {			
			htmlField.options[i] = new Option(arr[i], arr[i]);
		}
	}
}

/**
 * Returns the current value based on the type of htmlElem
 * Currently supports dropdown, text, hidden, and textarea form fields
 *
 * @param htmlElem An HTML form field
 * @return The current value of the element
 */
function getValue(htmlElem) {
	if (htmlElem.type == "select-one") {
		var val = htmlElem.selectedIndex;
		return htmlElem[val].value;	
	} else if (htmlElem.type == "text" || htmlElem.type == "hidden" || htmlElem.type == "textarea") {
		return htmlElem.value;
	} else if (htmlElem.type == "radio") {
		return htmlElem.value;
	} else if (htmlElem.length) {
		//alert(htmlElem[0].type);
		if (htmlElem[0].type == "radio") {
			for (var i = 0; i < htmlElem.length; i++) {
				if (htmlElem[i].checked) return htmlElem[i].value;
			}
			return "";			
		}
	}
}

/**
 * Given an HTML select element and a value in that dropdown, 
 * Selects the index whose value is {value}
 * @param dropdown HTML select element
 * @param value value of HTML select element to select
 */
function selectValue(dropdown, value) {	 
	for (var i = 0; i < dropdown.options.length; i++) {
		if (dropdown.options[i].value == value) {
			dropdown.selectedIndex = i;
			break;
		}
	}
}


/**
 * Given an HTML select element and a value in that dropdown, 
 * Selects the index whose text is {value}
 * @param dropdown HTML select element
 * @param text Text of HTML select element to select
 */
function selectText(dropdown, text) {	 
	for (var i = 0; i < dropdown.options.length; i++) {
		if (dropdown.options[i].text == text) {
			dropdown.selectedIndex = i;
			break;
		}
	}
}

/**
 * Given an HTML select element, retrieves the currently selected text
 *
 * @param dropdown HTML select element
 * @return currently selected text in dropdown
 */
function getSelectedText(dropdown) {
	var val = dropdown.selectedIndex;
	return dropdown[val].text;		
}



/*************************
* Type checking functions
**************************/

/**
 * Checks if variable is an array (uses isObject())
 *
 * @param a JavaScript variable
 */
function isArray(a) {
    return isObject(a) && a.constructor == Array;
}

/**
 * Checks if variable is an object (uses isFunction())
 *
 * @param a JavaScript variable
 */
function isObject(a) {
    return (a && typeof a == 'object') || isFunction(a);
}

/**
 * Checks if variable is a function
 *
 * @param a JavaScript variable
 */
function isFunction(a) {
    return typeof a == 'function';
}

/************************************
 * Used to alter font size on page  *
 ************************************/
//Set initial parameters
var currentSize = 8;
var cookies = document.cookie.split(";");
for (var i = 1; i < cookies.length; i++) {
	cook = cookies[i].split("=");
	if (cook[0] == "fontSize") {
		currentSize = cook[1];
		break;
	}
}

/**
 * Constructor for fontControl object
 * Initializes fontControl property currentSize to global currentSize variable
 */
function fontControl() {
	this.currentSize = currentSize;
}	

/**
 * Handles changing the font size of the page
 * This is rough and not nearly as  good as built-in browser, but it works alright
 *
 * @param change Must be either +, - , or r to increase, decrease, or revert to original font-size 
 * 	respectively
 */
fontControl.prototype.changeFont = function(change) {
	if (change == "+") this.currentSize++;
	if (change == "-") this.currentSize--;
	if (change == "r") this.currentSize = 8;
	document.cookie = "fontSize=" + this.currentSize;
	var tags = "td,p,a,div,span,li,body,form".split(",");
	for (var i = 0; i < tags.length; i++) {
		var els = document.getElementsByTagName(tags[i]);
		for (var j = 0; j < els.length; j++) {
			els[j].style.fontSize = this.currentSize + 'pt';
		}
	}
	for (i = 1; i < 7; i++) {
		var els = document.getElementsByTagName("h" + i);
		for (var j = 0; j < els.length; j++) {
			var newSize = (parseInt(this.currentSize - (-7)) - i);
			els[j].style.fontSize = newSize + 'pt';
		}
	}
}

fc = new fontControl();


/**
 * Not currently used - breaks in safari, also assumes an integer return value for Mozilla
 * Returns the value of a style property of a given element
 *
 * @param element ID of HTML element
 * @param style CSS style to retrieve
 * @return The value of a style property of the element with the given ID
 */
function getCurrentStyle(element, style) {
	var elem2 = document.getElementById(element);	
	if (what =="none") {
		retVal =  "";
	} else if (what == "moz") {
		var sElem2 = getComputedStyle(elem2,'');
		var fSize = sElem2.getPropertyCSSValue(style).getFloatValue(CSSPrimitiveValue.CSS_PX);
		retVal = fSize;
	} else {
		retVal  = eval("elem2.currentStyle." + style);
	}
	return retVal;
}

/**
 * Used to auto tab to next form field
 * Example Usage:
 * <input type="text" name="ip1" size="3" maxlength="3" onkeyup="return autoTab(this, 3, event);" />
 *
 * @param input HTML text input element
 * @param len Length of string in HTML text element at which to auto-tab to next field
 * @param e DOM event object
 */
function autoTab(input,len, e) {
	var keyCode = (what == "ns4") ? e.which : e.keyCode; 
	var filter = (what == "ns4") ? [0,8,9] : [0,8,9,16,17,18,37,38,39,40,46];
	if (input.value.length >= len && !containsElement(filter,keyCode)) {
		input.value = input.value.slice(0, len);
		input.form[(getIndex(input)+1) % input.form.length].focus();
		input.form[(getIndex(input)+1) % input.form.length].select();
	}
	function containsElement(arr, ele) {
		var found = false, index = 0;
		while(!found && index < arr.length)
			if(arr[index] == ele)
				found = true;
			else
				index++;
		return found;
	}
	function getIndex(input) {
		var index = -1, i = 0, found = false;
		while (i < input.form.length && index == -1)
			if (input.form[i] == input)index = i;
			else i++;
		return index;
	}
	return true;
}

/** 
 * Shortcut to open a window without any extra parameters
 * @param url URL of window to open
 */
function openWindow(url) {
	window.open(url, 'mywin');
}

/**
 * When the following single function is called, it will allow us to assign any number of load event handlers, 
 * 	without any of them conflicting:
 * Once this function is in place, we can use it any number of times:
 * addLoadListener(firstFunction);
 * addLoadListener(secondFunction);
 * addLoadListener(twentyThirdFunction);
 * From: http://www.sitepoint.com/print/javascript-from-scratch
 * 
 * @param fn Function to add to list of function run immediately after page loads
*/
function addLoadListener(fn) {
	if (typeof window.addEventListener != 'undefined') {
		window.addEventListener('load', fn, false);
	} else if (typeof document.addEventListener != 'undefined') {
		document.addEventListener('load', fn, false);
	} else if (typeof window.attachEvent != 'undefined') {
		window.attachEvent('onload', fn);
	} else {
		var oldfn = window.onload;
		if (typeof window.onload != 'function') {
			window.onload = fn;
		} else {
			window.onload = function() {
				oldfn();
				fn();
			};
		}
	}
}

/*
 *Returns an array [x, y] representing the current 
 * mouse position
 * @param e DOM event
 * @return Array of type [x,y] indicating event's posision
 */
function getEventPosition(e) {
	var posx = 0;
	var posy = 0;
	if (!e) var e = window.event;
	if (e.pageX || e.pageY)
	{
		posx = e.pageX;
		posy = e.pageY;
	}
	else if (e.clientX || e.clientY)
	{
		posx = e.clientX + document.body.scrollLeft;
		posy = e.clientY + document.body.scrollTop;
	}
	return [posx, posy];
}

/**
 * Returns the {value} in {array} or -1 if value is not present
 * Necessary as IE has not implemented array.indexOf(value) and does not allow 
 *		extending native objects
 *
 * @value - value to search for (needle)
 * @array - array to perform search (haystack)
 */
function inArray(value, array) {
	for (var i = 0; i < array.length; i++) if (value == array[i]) return i;
	return -1;
}

/**
 * Sets a forms action
 * @param form		HTML	 Form object
 * @param action	string	 New action for form 	
 */
 function setFormAction(form, action) {
	if (document.all) form.attributes['action'].value = action;
	else form.action = action;
}

/*** 
 * Clears any form object passed to it
 */
function clearForm(form) {
	for (var i = 0; i < form.length; i++) {
		switch (form[i].type) {
			case "text":
			case "textarea":
			case "file":
				form[i].value = "";
				break;
			case "select-one":
				form[i].selectedIndex = 0;
				break;
			case "select-multiple":
				for (var j = 0; j < form[i].length; j++) form[i][j].selected = false;
				break;
			case "radio":
			case "checkbox":
				form[i].checked = false;
				break;
			default:
				break;		
		}
	}
}