/*
Class: baseUtility

Overview: baseUtility Overview
	Various resuable utility functions that are useful in a number of contexts but belong solely to none.

Bugs:
	None known.
	
To do:
	- Replace addEvent with adopted framework's approach (once one is adopted).
	- Remove init (it's need to satisfy possible <body onload="init();"> elements is illustrative of poor programming practice).

Change Log:
	2006.06.16	JEM	- Initial version.
*/

var domCompat = (document.getElementById) && (document.documentElement); // test for essential DOM compatability

// written by Dean Edwards, 2005
// with input from Tino Zijdel - crisp@xs4all.nl
// http://dean.edwards.name/weblog/2005/10/add-event/
// http://therealcrisp.xs4all.nl/upload/addEvent_dean.html
function addEvent(element, type, handler)
{
	if (element.addEventListener)
		element.addEventListener(type, handler, false);
	else
	{
		if (!handler.$$guid) handler.$$guid = addEvent.guid++;
		if (!element.events) element.events = {};
		var handlers = element.events[type];
		if (!handlers)
		{
			handlers = element.events[type] = {};
			if (element['on' + type]) handlers[0] = element['on' + type];
			element['on' + type] = handleEvent;
		}
	
		handlers[handler.$$guid] = handler;
	}
}
addEvent.guid = 1;

function removeEvent(element, type, handler)
{
	if (element.removeEventListener)
		element.removeEventListener(type, handler, false);
	else if (element.events && element.events[type] && handler.$$guid)
		delete element.events[type][handler.$$guid];
}

function handleEvent(event)
{
	event = event || fixEvent(window.event);
	var returnValue = true;
	var handlers = this.events[event.type];

	for (var i in handlers)
	{
		if (!Object.prototype[i])
		{
			this.$$handler = handlers[i];
			if (this.$$handler(event) === false) returnValue = false;
		}
	}

	if (this.$$handler) this.$$handler = null;

	return returnValue;
}

function fixEvent(event)
{
	event.preventDefault = fixEvent.preventDefault;
	event.stopPropagation = fixEvent.stopPropagation;
	return event;
}
fixEvent.preventDefault = function()
{
	this.returnValue = false;
}
fixEvent.stopPropagation = function()
{
	this.cancelBubble = true;
}

// This little snippet fixes the problem that the onload attribute on the body-element will overwrite
// previous attached events on the window object for the onload event
if (!window.addEventListener)
{
	document.onreadystatechange = function()
	{
		if (window.onload && window.onload != handleEvent)
		{
			addEvent(window, 'load', window.onload);
			window.onload = handleEvent;
		}
	}
}

/* 
Function: explore
	Turns off all elements with an id within a specified sequence, then turns on the desired element out of that sequence.

Parameters:
	prefix - the initial portion of the id's for a series of desired elements.
	myNum - of all of the elements within the series, the specific one to turn on.
	total - the total (upperBound) of the elements in the series.
	onClass - the class to assign to the element that should remain on.
	offClass - the class to assign to the elements to be turned off.

Dependencies:
	<changeClassById>; <anchorById>;
	
Example Usage:

(start code)

In the HTML: <div id="els1">...</div><div id="els2">...</div><div id="els3">...</div>

The JS call: explore('els',2,3,'fbon','fboff');     

assuming the second div is desired, and 'fbon' and 'fboff' were appropriately defined
in the CSS.

(end)

Bugs:
	None known.
	
To do:
	None.
	
Change Log:
	2004.??.??  JEM - Initial version.
	2004.05.04  JEM - Added functionality to not turn any element back on (reset) and any changes undocumented to date.
	2006.10.22	ALP	- Added optional parameter isAnchored to specify whether to anchor the page to the el that is being changed.
*/
function explore (prefix, myNum, total, onClass, offClass, isAnchored) {
	for (i = 1; i <= total; i++) {
		currEl = prefix + i;
		changeClassById (currEl, offClass);
	}
	if (myNum != '') {
		currEl = prefix + myNum;
		changeClassById (currEl, onClass);
		if (isAnchored) {
			anchorById(currEl);
		}
	}
} // end explore

/* 
Function: changeClassById
	Given the ID of the desired HTML element and the newClass to which the element should change, do just that and assign newClass to the class property of the the element ID. Rename of the change() function. 

Parameters:
	id - id of the element in question.
	newClass - the desired class to assign to the element. 

Depends On:
	None
	
Example Usage:

(start code)

In the HTML: <div id="els1">...</div> 
The JS call: changeClassById ('els1','fbon');
...asigns the class 'fbon' to the element with an id of 'els1'.

(end)

Bugs:
	None known.
	
To do:
	None.
	
Version History:
	2004.??.??	JEM	- Initial version.
	2004.05.04  JEM - Any changes undocumented to date. 
*/
function changeClassById(id, newClass) {
	//alert (id + " to class " + newClass); // good for debugging
	try {
		var identity=$(id); // this step required for some older Mozilla/NS browsers
		identity.className=newClass;
	} catch (e) {
		alert ("changeClassById error: Error attempting to change the class of '" + id + "' to '" + newClass + "'. \n Error: " + e);
	}
} // end changeClassById()

/* 
Function: arrayConcat
	Given two arrays, returns one array containing the elements of the first followed by the elements of the second. Suggested enhancements: allow n arrays to be passed in and loop through the arguments and concatenate them all together; test for m-dimensions and concatenate across each.

Parameters:
	array1, array2 - two single-dimensional arrays.

Dependencies:
	None.

Returns:
	An array with contents of array1 and array2 concatinated.
	
Bugs:
	None known.
	
To do:
	None.

Version History:
	2004.??.??	JEM	- Initial version.
	2004.05.04  JEM - Any changes undocumented to date. 
*/
function arrayConcat(array1, array2) {
	var returnArray = new Array();
	for (var i=0; i<array1.length; i++) {
		returnArray[returnArray.length] = array1[i];
	}
	for (var j=0; j<array2.length; j++) {
		returnArray[returnArray.length] = array2[j];
	}
	return returnArray;
}

/* 
Function: anchorById
	Ensures the selected element is within the view of the browser window.  

Parameters:
	elID - the ID of the element in question 

Depends On:
	None

Version History:
	2005.04.28  YB - Initial version.
	2005.08.10  JEM - Changed method to scrollIntoView to avoid URL manipulation, which interferes with the back button.
	2006.06.02	JEM	- Renamed to anchorById from jumpToDiv.
*/
function anchorById(elId){
	document.getElementById(elId).scrollIntoView();
}
var jumpToDiv = anchorById; // backwards compatibility

/* 
Function: changeClassOfParent
	Given an element and the desired class, change the class of the element's parent.

Parameters:
	el - usually a 'this' reference; reference to the element that called this function.
	newClass - the desired class to assign to the element's parent.

Dependencies:
	<changeClassById>;

Bugs:
	None known.
	
To do:
	None.

Change Log:
	2004.08.30  JEM	- Initial version.
	2006.07.10	JEM	- Added <$> to el.
*/
function changeClassOfParent(el, newClass) {
            changeClassById($(el).parentNode.id, newClass);
}

/* 
Function: Array.prototype.push
	Adds the push method to the Array object if such does not exist.

Parameters:
	item - item to be added to the array.

Dependencies:
	None.

Bugs:
	None known.
	
To do:
	None.

Change Log:
	200?.??.??	JEM	- Initial version.
	2006.06.02	JEM	- Uncommented changes to date.

*/
if(Array.prototype.push == null){
	Array.prototype.push = function(item){
		this[this.length] = item;
		return this.length;
	}
}

/* 
Function: window.prototype.print
	Displays an error message to the user who is trying to execute a script that uses window.print in a browser that does not support window.print.

Parameters:
	None.

Dependencies:
	None.

Bugs:
	None known.
	
To do:
	None.

Change Log:
	2006.06.02	JEM	- Initial version.
*/
if (window.print == null) {
	window.print = function() {
		alert("Sorry, this browser does not support this feature.  To print this page, please click on File at the top of your screen, and then choose Print.");
	}
}

/* 
Function: externalLinks
	Adds functionality to each a tag on the page with a rel="external" to open the link in a new window.  Avoids the need to use invalid XHTML of target="_blank".

Parameters:
	None.

Dependencies:
	None.

Bugs:
	None known.
	
To do:
	None.

Change Log:
	200?.??.??	JEM	- Initial version.
	2006.06.02	JEM	- Undocumented changes to date; changed to use onclick function instead of simply applying target="_blank" to pacify the validators.
	2006.06.13	JEM	- Minor code clean-up.
*/
function externalLinks() {
	if (document.getElementsByTagName) {
		var anchors = document.getElementsByTagName("a");
		for (var i=0, j=anchors.length; i<j; i++) {
			var anchor = anchors[i];
			if (anchor.getAttribute("href") &&
				anchor.getAttribute("rel") == "external") {
				anchor.onclick = function () {window.open(this.href); return false;};
			} 
		}
	}
}

/* 
Function: generateEl
	Create a DOM element of the optionally specified type (otherwise a div) and append it to the optionally specified el (otherwise the body).

Parameters:
	parentEl	- Optional reference to the element into which the generated element should be appended.
	type	- Optional string indicating the type of element to be created.

Dependencies:
	<$>;

Returns:
	Reference to generated element.

Bugs:
	None known.
	
To do:
	None.

Change Log:
	200?.??.??	JEM	- Initial version.
	2006.06.02	JEM	- Undocumented changes to date; code clean-up; added type parameter.
*/
function generateEl(parentEl, type) {
	var theParent = (parentEl) ? $(parentEl) : document.getElementsByTagName("body").item(0);
	var tagType = type || "div";
	var elToAdd = document.createElement(type);
	var theEl = theParent.appendChild(elToAdd);
	return theEl;
}

/* 
Function: init
	When init is called on every page, this null function prevents errors on those pages that don't offer a local version of init.

Parameters:
	None.
	
Dependencies:
	None.

Returns:
	N/A.
	
Bugs:
	None known.
	
To do:
	- Revise programming practices to no longer reference the init function (bad practice to use one).

Change Log:
	200?.??.??   ???	- Initial version.
*/
function init() {
}

