// Regular expressions for normalizing white space.
var whtSpEnds = new RegExp("^\\s*|\\s*$", "g");
var whtSpMult = new RegExp("\\s\\s+", "g");

// This code is necessary for browsers that don't reflect the DOM constants.
if (document.ELEMENT_NODE == null)
{
	document.ELEMENT_NODE = 1;
	document.TEXT_NODE    = 3;
}

//----------------------------------------------------------------------------------------------------
// General purpose functions.
//-----------------------------------------------------------------------------------------------------


	function iif (expr, trueStr, falseStr)
	{
		return (eval(expr)) ? trueStr : falseStr;
	}
		
	function display (el)
	{
		document.getElementById(el).style.display = (document.getElementById(el).style.display == 'block') ? 'none' : 'block';
	}	

	function visible (el)
	{
		document.getElementById(el).style.visibility = (document.getElementById(el).style.visibility == 'visible') ? 'hidden' : 'visible';
	}	

	function offsetTop ( el )
	{
		y = el.offsetTop;
		
		for ( e = el.offsetParent; e; e = e.offsetParent )
			y += e.offsetTop;
		
		return y;
	} 

	function offsetLeft( el )
	{
		x = el.offsetLeft;

		for ( e = el.offsetParent; e; e = e.offsetParent )
			x += e.offsetLeft;

		return x;
	}      

     function windowWidth ()
     {
        	if ( window.innerWidth != window.undefined )
          	return window.innerWidth;
 
         	if ( document.documentElement )
          	return document.documentElement.clientWidth;
               
          if ( document.body )
          	return document.body.clientWidth;
               
          return window.undefined;
     }
     
     function windowHeight ()
     {
        	if ( window.innerHeight != window.undefined )
          	return window.innerHeight;
 
         	if ( document.documentElement )
          	return document.documentElement.clientHeight;
               
          if ( document.body )
          	return document.body.clientHeight;
               
          return window.undefined;
     }
     
     
//----------------------------------------------------------------------------------------------------
// Functions to format data.
//-----------------------------------------------------------------------------------------------------

	// This function takes in a string and returns the string without leading or trailing spaces and with 
	// multiple white spaces collapsed to one space.
	// INPUT  : a string
	// OUTPUT : a formatted string
	function normalizeString(s)
	{
     s = s.replace(whtSpMult, " ");  // Collapse any multiple whites space.
     s = s.replace(whtSpEnds, "" );  // Remove leading or trailing white space.
     
     return s;
	}
  
     function strltrim() 
     {
          return this.replace(/^\s+/,'');
     }
     
     function strrtrim() 
     {
	     return this.replace(/\s+$/,'');
     }
     
     function strtrim() 
     {
     	return this.replace(/^\s+/,'').replace(/\s+$/,'');
     }
     
     function trim( str ) 
     {
	     return str.replace(/^\s+/,'').replace(/\s+$/,'');
     }
     
     String.prototype.ltrim = strltrim;
     String.prototype.rtrim = strrtrim;
     String.prototype.trim  = strtrim;

     if ( !Number.toFixed )
     {
	     Number.prototype.toFixed = function ( x )
     	{
               return Math.round( this * Math.pow( 10, x ) ) / Math.pow( 10, x );
          }
     }
  

//----------------------------------------------------------------------------------------------------
// Functions to evaluate and alter the classes that elements belong to.
//-----------------------------------------------------------------------------------------------------

	// This function will check to see if the specified element belongs to a specific class.
	// INPUT  : a page element, a class name to search for
	// OUTPUT : true if the element belongs to the class specified and false otherwise
	function hasClassName(el, name) 
	{
		var i, list;
	
		list = el.className.split(" ");
		for (i = 0; i < list.length; i++)
			if (list[i] == name)
		    	return true;
	
		return false;
	}
	
	// This function removes the specified element from a specified class.  If the element does not 
	// belong to the class specified, no changes will be made.
	// INPUT  : the element, the class to remove
	// OUTPUT : none, but the class membership of the element will be altered
	function removeClassName(el, name) 
	{
		var i, curList, newList;
	
		if (el.className == null)
	    	return;
	
		newList = new Array();
		curList = el.className.split(" ");
		for (i = 0; i < curList.length; i++)
			if (curList[i] != name)
				newList[newList.length] = curList[i];
	
		el.className = newList.join(" ");
	}
	
	// This function will replace one class with another for a given element.  If the element does not
	// belong to the class specified as the old class, the new class will just be added.
	// INPUT  : the element, the old class name, and the new class name
	// OUTPUT : none, but the classes of the element will be altered
	function replaceClassName(el, oldClass, newClass)
	{
		removeClassName(el, oldClass);
		el.className += " " + newClass;
	}


//-----------------------------------------------------------------------------
// Functions to get and compare values during a sort.
//-----------------------------------------------------------------------------

	// This function gets the complete value (text and HTML code) of any specified document 
	// node (e.g.: table cells).
	// INPUT  : the exact document element to retrieve the value of
	// OUTPUT : the value of the specified element as a string
	function getTextValue(el)
	{
		var s = "";
		
		// Find and concatenate the values of all text nodes contained within the element.
		for (var i = 0; i < el.childNodes.length; i++)
			if (el.childNodes[i].nodeType == document.TEXT_NODE)
				s += el.childNodes[i].nodeValue;
			// If the text node is another element node or a <br /> tag insert a space to represent the 
			// element.
			else if (el.childNodes[i].nodeType == document.ELEMENT_NODE && el.childNodes[i].tagName == "BR")
				s += " ";
			else
				// Use recursion to get text within sub-elements.
				s += getTextValue(el.childNodes[i]);
	
		return normalizeString(s);
	}
	
	// This function compares two values and returns a value that can be used to determine if
	// the first value is greater than the second.  Both values are converted to numbers for 
	// this comparison if possible.
	// INPUT  : two values to compare
	// OUTPUT : a 1 if the first value is greater than the second, a 0 if both values are 
	//          equal, and a -1 if the first value is less than the second
	function compareValues(v1, v2)
	{
		// If the values are numeric, convert them to floats.
		var f1 = parseFloat(v1);
		var f2 = parseFloat(v2);

		// If both values can be converted to numbers without error, use the numeric equivalents 
		// for comparison purposes.
		if (!isNaN(f1) && !isNaN(f2))
		{
			v1 = f1;
			v2 = f2;
		}
		
		// Compare the two values.  0 = v1 equals v2; 1 = v1 is greater than v2; -1 = v1 is less than v2
		if (v1 == v2)
			return 0;
		if (v1 > v2)
			return 1
			
		return -1;
	}

//----------------------------------------------------------------------------------------------------
// Functions to sort tables.
//-----------------------------------------------------------------------------------------------------

	// This function sorts the rows in any table body specified by the column specified.  A second
	// column can be specified for a secondary sort.  A -1 can be passed instead of a second column if 
	// there is only a primary sort.  Columns are represented by their position in the 
	// table (0 ... n - 1).
	// INPUT  : the table body element containing the rows to sort, the primary sort column, the 
	//          secondary sort column
	// OUTPUT : none, but the order of the rows in the table will be changed as will the table header
	function sortTable(obj, col1, col2)
	{
		// Get the table section to sort.
		var tblEl = document.getElementById(obj);
	
		// Set up an array of reverse sort flags, if not done already.
		if (tblEl.reverseSort == null)
		{
			tblEl.reverseSort = new Array();
	  			tblEl.lastColumn  = 0;
			
			for (var i = 0; i < tblEl.rows[0].cells.length; i++)
				tblEl.reverseSort[i] = false;
		}
		
		// If this column was the last one sorted, reverse its sort direction.
		if (col1 == tblEl.lastColumn)
			tblEl.reverseSort[col1] = !tblEl.reverseSort[col1];
		else
			tblEl.reverseSort[col1] = false;
		
		// Remember this column as the last one sorted.
		tblEl.lastColumn = col1;
		
		// Set the table display style to "none" - necessary for Netscape 6 browsers.
		var oldDsply = tblEl.style.display;
		tblEl.style.display = "none";
		
		// Sort the rows based on the content of the specified column using a selection sort.
	
		var tmpEl;
		var j;
		var minVal, minIdx;
		var testVal;
		var cmp;
		
		for (var i = 0; i < tblEl.rows.length - 1; i++)
		{
			// Assume the current row has the minimum value.
			minIdx = i;
			minVal = getTextValue(tblEl.rows[i].cells[col1]);
			
			// Search the rows that follow the current one for a smaller value.
			for (j = i + 1; j < tblEl.rows.length; j++)
			{
				testVal = getTextValue(tblEl.rows[j].cells[col1]);
				cmp     = compareValues(minVal, testVal);
	
				if (cmp == 0)
					if (col2 != -1)
				        compareValues(getTextValue(tblEl.rows[minIdx].cells[col2]), getTextValue(tblEl.rows[j].cells[col2]));
									
				// Reverse order?
				if (tblEl.reverseSort[col1])
					cmp = -cmp;
				
				// If this row has a smaller value than the current minimum, remember its
				// position and update the current minimum value.
				if (cmp > 0)
				{
					minIdx = j;
					minVal = testVal;
				}
			}
		
			// By now, we have the row with the smallest value. Remove it from the
			// table and insert it before the current row.
			if (minIdx > i)
			{
				tmpEl = tblEl.removeChild(tblEl.rows[minIdx]);
				tblEl.insertBefore(tmpEl, tblEl.rows[i]);
			}
		}
		
		// Update the table head to show which column is being sorted and in which direction.
		indicateSort(obj + '_head', tblEl.lastColumn, tblEl.reverseSort[tblEl.lastColumn]);
	
		// Restore the table's display style.
		tblEl.style.display = oldDsply;
		
		// In case this function was called as part of a hyperlink, return a false to keep a new
		// page from being loaded.
		return false;
	}
	
	// This function updates the head section of a table to show which column the table is currently
	// sorted by and in which direction the data is sorted (ascending or descending).  This function
	// should only be called by the sortTable() function.  For this function to work correctly, two 
	// variables, 'ascendingIndicator' and 'descendingIndicator', should be defined in the calling 
	// document to specify the graphics that are to be used as sort indicators.  The head 
	// section of the table should have the id <obj>_head where <obj> is the id of the body section of the 
	// table containing the rows that have been sorted.
	// INPUT  : the object id representing the body section of the table containing the rows that have 
	//          been sorted, the position of the last column sorted, and the reverse sort status of
	//          last sorted column (this is used to determine the direction of the sort performed)
	// OUTPUT : none, but the table head is modified
	function indicateSort(obj, lastColumn, ascending)
	{
		var tblEl = document.getElementById(obj);
		
		// Traverse through all of the table head cells and remove any sort indicators that are present.
		for (var i = 0; i < document.getElementById(obj).rows[0].cells.length; i++)
			tblEl.rows[0].cells[i].innerHTML = normalizeString(tblEl.rows[0].cells[i].innerText);
		
		// Set the default sort direction as ascending (true)
		var direction = true;
		
		// If the last sort direction is undefined or ascending (true), then the current sort 
		// direction is descending (false).
		if (eval("typeof(ascending)") == 'undefined' || ascending)
			direction = false;
		
		// Set the column name of the primary sort column as the column text followed by the image
		// for the appropriate sort direction.
		if (direction)
			tblEl.rows[0].cells[lastColumn].innerHTML = getTextValue(tblEl.rows[0].cells[lastColumn]) + ' ' + ascendingIndicator;
		else	
			tblEl.rows[0].cells[lastColumn].innerHTML = getTextValue(tblEl.rows[0].cells[lastColumn]) + ' ' + descendingIndicator;
	}	

//----------------------------------------------------------------------------------------------------
// Functions to change the rows in a table that are being hovered over by the mouse.
//-----------------------------------------------------------------------------------------------------
	
	// This function changes the class of all table cell tags (td) on a form that belong to another class.  This is used to change
	// the members of table cells that compose a single row of data in a table to be of a different class so that they look high-lighted
	// when the user hovers the mouse over any of the table cells belonging to that row.
	// INPUT  : The specified class of tags to change
	// OUTPUT : none, but several tags on the page may be changed to a different class.
	function activateRow(rowNum)
	{
		var allTDs = document.getElementsByTagName("TD");
	
		for (var i = 0; i < allTDs.length; i++) 
			if (hasClassName(allTDs[i], rowNum))
				if (hasClassName(allTDs[i], "dataCell"))
				{
					removeClassName(allTDs[i], "dataCell")
					allTDs[i].className += " activeCell";
				}
	}
	
	// This function changes the class of all table cell tags (td) on a form that belong to another class.  The purpose is the 
	// same as the above function but it sets the table cells back to the default classes.
	// INPUT  : The specified class of tags to change
	// OUTPUT : none, but several tags on the page may be changed to a different class.
	function deactivateRow(rowNum)
	{
		var allTDs = document.getElementsByTagName("TD");
	
		for (var i = 0; i < allTDs.length; i++) 
			if (hasClassName(allTDs[i], rowNum))
				if (hasClassName(allTDs[i], "activeCell"))
				{
					removeClassName(allTDs[i], "activeCell")
					allTDs[i].className += " dataCell";
				}
	}	

//----------------------------------------------------------------------------------------------------
// Functions to change images.
//-----------------------------------------------------------------------------------------------------

	// This function sets the source of the image element specified with the path passed.
	// INPUT  : the element to change and the image to set the element to
	// OUTPUT : none, but the image specified by el is changed to the image specified by img
	function swapImage(el, img)
	{
		var newImage = new Image();

		newImage.src = img;
		document.getElementById(el).src = newImage.src;
	}
