/* Prototype extensions */
String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g,"");
};
String.prototype.ltrim = function() {
	return this.replace(/^\s+/,"");
};
String.prototype.rtrim = function() {
	return this.replace(/\s+$/,"");
};
/* Prototype extensions */


/* DOM traversal wrapper functions */
/* Kudos to http://developer.mozilla.org/en/docs/Whitespace_in_the_DOM */

/**
 * Throughout, whitespace is defined as one of the characters
 *  "\t" TAB \u0009
 *  "\n" LF  \u000A
 *  "\r" CR  \u000D
 *  " "  SPC \u0020
 *
 * This does not use Javascript's "\s" because that includes non-breaking
 * spaces (and also some other characters).
 */

/**
 * Determine whether a node's text content is entirely whitespace.
 *
 * @param nod  A node implementing the |CharacterData| interface (i.e.,
 *             a |Text|, |Comment|, or |CDATASection| node
 * @return     True if all of the text content of |nod| is whitespace,
 *             otherwise false.
 */
function is_all_ws( nod )
{
  // Use ECMA-262 Edition 3 String and RegExp features
  return !(/[^\t\n\r ]/.test(nod.data));
}

/**
 * Determine if a node should be ignored by the iterator functions.
 *
 * @param nod  An object implementing the DOM1 |Node| interface.
 * @return     true if the node is:
 *                1) A |Text| node that is all whitespace
 *                2) A |Comment| node
 *             and otherwise false.
 */

function is_ignorable( nod )
{
  return ( nod.nodeType == 8) || // A comment node
         ( (nod.nodeType == 3) && is_all_ws(nod) ); // a text node, all ws
}

/**
 * Version of |previousSibling| that skips nodes that are entirely
 * whitespace or comments.  (Normally |previousSibling| is a property
 * of all DOM nodes that gives the sibling node, the node that is
 * a child of the same parent, that occurs immediately before the
 * reference node.)
 *
 * @param sib  The reference node.
 * @return     Either:
 *               1) The closest previous sibling to |sib| that is not
 *                  ignorable according to |is_ignorable|, or
 *               2) null if no such node exists.
 */
function node_before( sib )
{
  while ((sib = sib.previousSibling)) {
    if (!is_ignorable(sib)) return sib;
  }
  return null;
}

/**
 * Version of |nextSibling| that skips nodes that are entirely
 * whitespace or comments.
 *
 * @param sib  The reference node.
 * @return     Either:
 *               1) The closest next sibling to |sib| that is not
 *                  ignorable according to |is_ignorable|, or
 *               2) null if no such node exists.
 */
function node_after( sib )
{
  while ((sib = sib.nextSibling)) {
    if (!is_ignorable(sib)) return sib;
  }
  return null;
}

/**
 * Version of |lastChild| that skips nodes that are entirely
 * whitespace or comments.  (Normally |lastChild| is a property
 * of all DOM nodes that gives the last of the nodes contained
 * directly in the reference node.)
 *
 * @param sib  The reference node.
 * @return     Either:
 *               1) The last child of |sib| that is not
 *                  ignorable according to |is_ignorable|, or
 *               2) null if no such node exists.
 */
function last_child( par )
{
  var res=par.lastChild;
  while (res) {
    if (!is_ignorable(res)) return res;
    res = res.previousSibling;
  }
  return null;
}

/**
 * Version of |firstChild| that skips nodes that are entirely
 * whitespace and comments.
 *
 * @param sib  The reference node.
 * @return     Either:
 *               1) The first child of |sib| that is not
 *                  ignorable according to |is_ignorable|, or
 *               2) null if no such node exists.
 */
function first_child( par )
{
  var res=par.firstChild;
  while (res) {
    if (!is_ignorable(res)) return res;
    res = res.nextSibling;
  }
  return null;
}

/**
 * Version of |data| that doesn't include whitespace at the beginning
 * and end and normalizes all whitespace to a single space.  (Normally
 * |data| is a property of text nodes that gives the text of the node.)
 *
 * @param txt  The text node whose data should be returned
 * @return     A string giving the contents of the text node with
 *             whitespace collapsed.
 */
function data_of( txt )
{
  var data = txt.data;
  // Use ECMA-262 Edition 3 String and RegExp features
  data = data.replace(/[\t\n\r ]+/g, " ");
  if (data.charAt(0) == " ")
    data = data.substring(1, data.length);
  if (data.charAt(data.length - 1) == " ")
    data = data.substring(0, data.length - 1);
  return data;
}

/* DOM traversal wrapper functions */

function $() { // Prototype short function!
	var elements = new Array();
	for (var i = 0; i < arguments.length; i++) {
		var element = arguments[i];
		if (typeof element == 'string')
			element = document.getElementById(element);
		if (arguments.length == 1)
			return element;
		elements.push(element);
	}
	return elements;
};

function getElementsByClass(searchClass,node,tag) {
	var classElements = new Array();
	if ( node == null )
		node = document;
	if ( tag == null )
		tag = '*';
	var els = node.getElementsByTagName(tag);
	var elsLen = els.length;
	var pattern = new RegExp('(^|\\\\s)'+searchClass+'(\\\\s|$)');
	for (i = 0, j = 0; i < elsLen; i++) {
		if ( pattern.test(els[i].className) ) {
			classElements[j] = els[i];
			j++;
		}
	}
	return classElements;
};

// Function to retrieve QS value
function querystring_getValue(key) {
	var value = null;
	for (var i=0;i<querystring.keys.length;i++) {
		if (querystring.keys[i]==key) {
			value = querystring.values[i];
			break;
		}
	}
	
	return value;
}

// Required for QS manipulation
function querystring_parse() {
	var query = window.location.search.substring(1);
	var pairs = query.split("&");

	for (var i=0;i<pairs.length;i++) {
		var pos = pairs[i].indexOf('=');
		if (pos >= 0) {
			var argname = pairs[i].substring(0,pos);
			var value = pairs[i].substring(pos+1);
			querystring.keys[querystring.keys.length] = argname;
			querystring.values[querystring.values.length] = value;
		}
	}
}

// Smart function to add NVP to QS
// Use in <a href="javascript:addToQS('name','value');"> to ensure location replacement
function addToQS(name,value) {
	var addNVP = true;
	for (var i=0; i<querystring.keys.length; i++) {
		if (querystring.keys[i] == name) {
			// Matching key found - no NVP push
			addNVP = false;
			
			if (querystring.values[i] != value) {
				// Update old value with new
				querystring.values[i] = value;
			}
			else {
				return (void(0)); // No action required
			}
		}
	}

	if (addNVP == true) {
		// Push new NVP		
		querystring.keys.push(name);
		querystring.values.push(value);

		// Rebuild url
		var strURL = window.location.pathname + '?';
		for (var j=0; j<querystring.keys.length; j++) {
			if (j!=0) { strURL += '&'; }
			strURL += querystring.keys[j] + '=' + querystring.values[j];
		}
		if (window.location.hash) {
			strURL += window.location.hash;
		}
		
		// Activate
		window.location = strURL;
	}
	else {
		return void(0);	
	}	
}



/* TABBED BOX FUNCTIONS */

// Wrapper function for onload event
function tabbedBox_activateTabs() {
	tabbedBoxes = getElementsByClass("tabbedBox"); // Get all tabbed boxes
	tabbedBox_displayTab();
}

// Function to display specific tabbed content by title via var or hash
function tabbedBox_displayTab(tabTitle) {

	if (typeof(tabTitle) != 'undefined') { // Tab title was passed directly
		var thisTabTitle = tabTitle;
	}
	else { // Check that a tab title was passed in the hash
		var RE = new RegExp("^tab_(.+)$"); // Case-sensitive
		if ((typeof(thisHash) != 'undefined') && (matches = thisHash.match(RE)) && (matches[1])) {
			var thisTabTitle = matches[1]; // Grab title of tab to display
		}
	}
		
	if (tabbedBoxes) { // Page contains tabbed boxes
		for (a in tabbedBoxes) {				
			var blnTitleMatch = false; // Process flag
			if (tabContainer = first_child(tabbedBoxes[a])) { // Get container
				var tab = first_child(tabContainer);
				while (tab) { // Check each tab for matching title
					if ((typeof(thisTabTitle) != 'undefined') && (tab.title.toLowerCase() == thisTabTitle.toLowerCase())) { // Case-insensitive match
						blnTitleMatch = true; // Match found
					}			
					
					// Add click event for direct display - must evaluate expression to insert actual values and not pass scope
					eval("tab.onclick = function() { tabbedBox_displayTab('"+tab.title+"'); }");
					
					tab = node_after(tab);	
				}
				if (blnTitleMatch) { // Process tabs
					tab = first_child(tabContainer); // Cycle thru tabs
					while (tab) { // Compare titles to determine class
						tab.className = ((tab.title.toLowerCase() == thisTabTitle.toLowerCase()) ? 'tabOn' : 'tabOff');
						tab = node_after(tab);	
					}
				}
			}
			if (blnTitleMatch) { // Process tab contents
				if (tabContentContainer = node_after(tabContainer)) {
					tabContent = first_child(tabContentContainer); // Cycle thru tab contents
					while (tabContent) { // Compare titles to determine class
						tabContent.className = ((tabContent.title.toLowerCase() == thisTabTitle.toLowerCase()) ? 'tabContentOn tabContent' : 'tabContentOff tabContent');
						tabContent = node_after(tabContent);	
					}		
				}
				try { SI.ClearChildren.clear(); } catch(e) {} // Reset height	
			}
		}
	}
	else {
		return void(0);	
	}
}

/* TABBED BOX FUNCTIONS */

function setSearchTextDefault() {
	if (obj = $('search_key')) {
		obj.value = 'Search';
	}
}

function getCurrentTab() {
	for (var i=0; i<=tabCount; i++) {
		if (obj = $('mainNavTab'+i)) {
			// Check state
			if (obj.className.match(/\btabOn\b/)) {
				return(i);
			}
		}			
	}
}

function mainNavTabHilite(tabID) {
	if (tabID != thisSectionTab) {
		if (obj = $('mainNavTab'+tabID)) {
			obj.className = obj.className.replace(/tabOff/, 'tabOn');	
		}
	}
}

function mainNavTabUnHilite(tabID) {
	if (tabID != thisSectionTab) {
		if (obj = $('mainNavTab'+tabID)) {
			obj.className = obj.className.replace(/tabOn/, 'tabOff');	
		}
	}
}

function isNumeric(x) {
	var myRegExp = /^[-+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?$/; 
	var result = x.match(myRegExp);

	if (result==null) result=false;

	return result;
}

function imgSwitch(imageID,rollType) {
	// General function to change status of an image
	// rollType is required: on|off|over
	if ((document.images[imageID]) && (rollType + '' != 'undefined')) {
		var thisImg = document.images[imageID];
		var rePattern = /^(https?:\/\/[^\/]+)(.+?)(on|off|over)(\.(gif|png))$/i; // Take care with (/g)lobal!
		var matches = rePattern.exec(thisImg.src); // Require explicit RE object for Safari 2 / Mac
		if (matches) {
			thisImg.src = matches[2] + rollType + matches[4];
		}
	}
}

function imgHilite(imgName) {
	if (document.images[imgName]) {
		document.images[imgName].src = document.images[imgName].src.replace(/_off\.gif$/,'_on.gif');
	}
}

function imgUnHilite(imgName) {
	if (document.images[imgName]) {
		document.images[imgName].src = document.images[imgName].src.replace(/_on\.gif$/,'_off.gif');
	}
}

function customDateString(oneDate) {
	var theDay = dayNames[oneDate.getDay() + 1];
	var theMonth = monthNames[oneDate.getMonth() + 1];
	var theYear = oneDate.getFullYear();
	return theDay.substring(0,3).toUpperCase() + "  |  " + theMonth.toUpperCase() + " " + oneDate.getDate() + ", " + theYear;
}

function DropdownChooser(Product) {
	if (Product != "") {
		window.location = Product;
	}
}

function reselectDropdown(frm,drop,val) {
	if (val != '') {
		var root = document.forms[frm].elements[drop];

		for (var t=0; t<root.length; t++) {
			if (root[t].value == val) {
				root.selectedIndex = t;
			}
		}
	}
}

function openWindow(URL,Name,W,H,L,T,Scrolls,Resize) {
	// Used to control params of pop-ups
	var defProps = 'copyhistory=0,directories=0,fullscreen=0,location=1,menubar=0,status=1,titlebar=1,toolbar=0';
	var poppedProps = '';

	if (W != null) {
		if (Scrolls == true) { W += 16; } // Allow for chrome in IE
		poppedProps += ('width='+W+',');
	}
	if (H != null) { poppedProps += ('height='+H+','); }
	if (L != null) { poppedProps += ('left='+L+','); }
	if (T != null) { poppedProps += ('top='+T+','); }
	poppedProps += 'scrollbars=' + ((Scrolls == true) ? 1 : 0) + ',' ;
	poppedProps += 'resizable=' + ((Resize == true) ? 1 : 0) + ',' ;
	poppedProps += defProps;

//	alert(poppedProps);
	poppedUp = window.open(URL,Name,poppedProps);
	setTimeout("poppedUp.window.focus();",100);
	return poppedUp;
}

function getObject(myid) {
	if ((HM_IE) || (HM_DOM)) {
		// Explorer
		if (HM_IE){
			return (document.all[myid]);
		}
		// DOM Browsers
		else if (HM_DOM) {
			return (document.getElementById(myid));
		}
	}
	else {
		return (false);
	}
}

function makeArray(n) {
//*** BUG: If I put this line in, I get two error messages:
//(1) Window.length can't be set by assignment
//(2) daysInMonth has no property indexed by 4
//If I leave it out, the code works fine.
//   this.length = n;
   for (var i = 1; i <= n; i++) {
      this[i] = 0
   } 
   return this
}

function showItem(myid,mydisplay) {
	if (mydisplay == "none") {
		getObject(myid).style.display = 'none';
		getObject(myid).style.visibility = 'hidden';
		if (SI) { SI.ClearChildren.clear(); } // Reset height
	}
	else if (mydisplay == "block") {
		getObject(myid).style.display = 'block';
		getObject(myid).style.visibility = 'visible';
		if (SI) { SI.ClearChildren.clear(); } // Reset height
	}
}

function toggleItem(myid, blnFade) {
	if (getObject(myid)) {
		var itemState = getObject(myid).style.display;
		if (itemState != 'none') {
			if (blnFade == 1) {
				fadeObj(myid,-1);
			}
			else {
				showItem(myid,'none');		
			}
			return (0);
		}
		else {
			if (blnFade == 1) {
				fadeObj(myid,1);
			}
			else {
				showItem(myid,'block');
			}
			return (1);
		}
	}
}

function toggleTextBoxVal(obj,ev,defVal) {
	if (obj) {
		if (ev == 'focus') {
			if (obj.value == defVal) {
				obj.value = '';
			}
		}
		else if (ev == 'blur') {
			if (obj.value == '') {
				obj.value = defVal;
			}
		}
	}
}

function setOpacity(obj, opacity) {
	opacity = (opacity == 100)?99:opacity; // Fixes re-draw bug when opacity = 1
	// IE/Win
	obj.style.filter = "alpha(opacity:"+opacity+")";
	if (obj.filters) {obj.filters.alpha.opacity=opacity;}
	// Safari<1.2, Konqueror
	obj.style.KHTMLOpacity = opacity/100;
	// Older Mozilla and Firefox
	obj.style.MozOpacity = opacity/100;
	// Safari 1.2, newer Firefox and Mozilla, CSS3
	obj.style.opacity = opacity/100;
	return opacity;
}

function fadeObj(obj,dir,lim) {
	if (dir == 1) {
		// Fade In
		if (!lim) {
			 // Full fade in
			lim = 100;

			// Set to 0 opacity hidden
			fOp[obj] = setOpacity(getObject(obj),0);
		}
		else {
			fOp[obj] = setOpacity(getObject(obj),lim);
		}

		getObject(obj).style.visibility = 'visible';
		getObject(obj).style.display = 'block';

		// Fade it
		fClr[obj] = setInterval(function() { fadeLoop(obj,10,lim); },25); // always use anonymous fn for intervals
	}
	else if (dir == -1) {
		// Fade Out
		if (!lim) {
			// Full fade out
			lim = 0;
			
			// Set to 100% opacity visible
			fOp[obj] = setOpacity(getObject(obj),100);
		}
		else {
			fOp[obj] = setOpacity(getObject(obj),lim);
		}
			
		getObject(obj).style.visibility = 'visible';
		getObject(obj).style.display = 'block';
		
		// Fade it
		fClr[obj] = setInterval(function() { fadeLoop(obj,-10,lim); },25); // always use anonymous fn for intervals
	}
}

function fadeLoop(obj,inc,lim) {
	if (inc > 0) {
		// Fade In
		if (fOp[obj] >= lim) {
			// Clean up and stop cycle
			clearInterval(fClr[obj]);
			if (SI) { SI.ClearChildren.clear(); }
		}
		else {
			fOp[obj] = setOpacity(getObject(obj),(fOp[obj]+inc));	
		}
	}
	else if (inc < 0) {
		// Fade Out
		if (fOp[obj] <= lim) {
			// Clean up and stop cycle
			if (lim == 0) { showItem(obj,'none'); } // Used to remove object from flow
			clearInterval(fClr[obj]);
			if (SI) { SI.ClearChildren.clear(); }
		}
		else {
			fOp[obj] = setOpacity(getObject(obj),(fOp[obj]+inc));
		}
	}
	else {
		// Catch all
		clearInterval(fClr[obj]);	
		if (SI) { SI.ClearChildren.clear(); }
	}
}

function matchColHeights() {
	var mHeight = 250; // Minimum height
	
	// Set array of column IDs to check in order of loading
	var aCols = new Array();
	aCols[1] = 'div_col1';
	aCols[2] = 'div_col2';
	aCols[3] = 'div_col3';
	
	// Get tallest column
	for(var i=aCols.length; i>0; i--) {
		if (getObject(aCols[i])) {
			elem = getObject(aCols[i]);
			// Last column has loaded - proceed
			if (elem.offsetHeight > mHeight) { mHeight = elem.offsetHeight; }
			elem.style.height = 'auto';
		}
	}
	
	if (mHeight > 0) {
		// Set all columns to tallest height
		for(i=aCols.length; i>0; i--) {
			if (getObject(aCols[i])) {
				elem = getObject(aCols[i]);
				elem.style.height = mHeight+'px';
			}
		}
		
		// Need to refresh footer position in IE if present
		if (getObject('div_footerCell')) {
			getObject('div_footerCell').className = 'footerCell';
		}
	}
}

function setBgScroll() {
	if (getObject('div_master')) {
		var masterWidth = getObject('div_master').offsetWidth;
		var bodyWidth = document.body.offsetWidth;
		var bodyRef = document.body;
		if (bodyWidth < masterWidth) {
			// Horizontal scrollbars are present - overlay fixed image if missing
			if (bodyRef.className != 'bodyScroll') {
				bodyRef.className = 'bodyScroll';
			}
		}
		else {
			// No horizontal scrollbars present - remove fixed image if present
			if (bodyRef.className != 'bodyFree') {
				bodyRef.className = 'bodyFree';
			}
		}
	}
}

function navToFadeOut() {
	if (getObject('div_navToHide')) {
		setOpacity(getObject('div_navToHide'),50);
	}
}

function navToFadeIn() {
	if (getObject('div_navToHide')) {
		setOpacity(getObject('div_navToHide'),100);
	}
}

function createCookie(name,value,days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}

function readCookie(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;
}

function eraseCookie(name) {
	createCookie(name,"",-1);
}

function obfusc(box,subj,dom) {
	if ((!dom) || (dom=='')) { dom = "imapdata" + unescape("%2E") + "com"; }
	var obfusced = ("mail" + "to" + unescape("%3A") + box + unescape("%40") + dom);
	if ((subj) && (subj!='')) { obfusced += (unescape("%3F") + "subject" + unescape("%3D") + escape(subj)); }
	this.location.href=obfusced;
}

/* Validations */
// Based on original PHP code by Cal Henderson (http://iamcal.com/publish/articles/php/parsing_email)
// Converted to JS regex
function is_valid_email_address(email) {
	var qtext = '[^\\x0d\\x22\\x5c\\x80-\\xff]';
	var dtext = '[^\\x0d\\x5b-\\x5d\\x80-\\xff]';
	var atom = '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c'+'\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+';
	var quoted_pair = '\\x5c\\x00-\\x7f';
	var domain_literal = '\\x5b('+dtext+'|'+quoted_pair+')*\\x5d';
	var quoted_string = '\\x22('+qtext+'|'+quoted_pair+')*\\x22';
	var domain_ref = atom;
	var sub_domain = '('+domain_ref+'|'+domain_literal+')';
	var word = '('+atom+'|'+quoted_string+')';
	var domain = sub_domain+'(\\x2e'+sub_domain+')*';
	var local_part = word+'(\\x2e'+word+')*';
	var addr_spec = local_part+'\\x40'+domain;
	var filter = eval('/^' + addr_spec + '$/');
	
	return ((filter.test(email)) ? 1 : 0);
}

// ====================================================================
//       URLEncode and URLDecode functions
//
// Copyright Albion Research Ltd. 2002
// http://www.albionresearch.com/
//
// You may copy these functions providing that 
// (a) you leave this copyright notice intact, and 
// (b) if you use these functions on a publicly accessible
//     web site you include a credit somewhere on the web site 
//     with a link back to http://www.albionresarch.com/
//
// If you find or fix any bugs, please let us know at albionresearch.com
//
// SpecialThanks to Neelesh Thakur for being the first to
// report a bug in URLDecode() - now fixed 2003-02-19.
// ====================================================================
function URLEncode(plaintext)
{
	// The Javascript escape and unescape functions do not correspond
	// with what browsers actually do...
	var SAFECHARS = "0123456789" +					// Numeric
					"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +	// Alphabetic
					"abcdefghijklmnopqrstuvwxyz" +
					"-_.!~*'()";					// RFC2396 Mark characters
	var HEX = "0123456789ABCDEF";

	var encoded = "";
	for (var i = 0; i < plaintext.length; i++ ) {
		var ch = plaintext.charAt(i);
	    if (ch == " ") {
		    encoded += "+";				// x-www-urlencoded, rather than %20
		} else if (SAFECHARS.indexOf(ch) != -1) {
		    encoded += ch;
		} else {
		    var charCode = ch.charCodeAt(0);
			if (charCode > 255) {
			    alert( "Unicode Character '" 
                        + ch 
                        + "' cannot be encoded using standard URL encoding.\n" +
				          "(URL encoding only supports 8-bit characters.)\n" +
						  "A space (+) will be substituted." );
				encoded += "+";
			} else {
				encoded += "%";
				encoded += HEX.charAt((charCode >> 4) & 0xF);
				encoded += HEX.charAt(charCode & 0xF);
			}
		}
	} // for

	return (encoded == '') ? false : encoded;
};

function URLDecode(encoded)
{
   // Replace + with ' '
   // Replace %xx with equivalent character
   // Put [ERROR] in output if %xx is invalid.
   var HEXCHARS = "0123456789ABCDEFabcdef"; 
   var plaintext = "";
   var i = 0;
   while (i < encoded.length) {
       var ch = encoded.charAt(i);
	   if (ch == "+") {
	       plaintext += " ";
		   i++;
	   } else if (ch == "%") {
			if (i < (encoded.length-2) 
					&& HEXCHARS.indexOf(encoded.charAt(i+1)) != -1 
					&& HEXCHARS.indexOf(encoded.charAt(i+2)) != -1 ) {
				plaintext += unescape( encoded.substr(i,3) );
				i += 3;
			} else {
				alert( 'Bad escape combination near ...' + encoded.substr(i) );
				plaintext += "%[ERROR]";
				i++;
			}
		} else {
		   plaintext += ch;
		   i++;
		}
	} // while

	return (plaintext == '') ? false : plaintext;
};


