﻿/* 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()) ? tab.className.replace(/tabOff/,'tabOn') : tab.className.replace(/tabOn/,'tabOff')); // Use RegEx to maintain other classNames
						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
				try { $('div_footer').className = 'div_footer'; } catch (e) {} // Refresh footer
			}
		}		
	}
	else {
		return void(0);	
	};
};

/* TABBED BOX FUNCTIONS */


// ====================================================================
//       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;
};

function setExternalLinks() {
	if (!document.getElementsByTagName) return;
	var anchors = document.getElementsByTagName("a");
	for (var i=0; i<anchors.length; i++) {
		var anchor = anchors[i];
		if (anchor.getAttribute("href") && anchor.getAttribute("rel") == "external") {
			anchor.target = "_blank";
		};
	};
};
