// returns true if email address is valid
function isValidEmailAddr(strEmailAddr) {
	var re = /^([\w!#\$%&'\*\+\-\/=\?\^`{\|}~]+\.?)*[\w!#\$%&'\*\+\-\/=\?\^`{\|}~]@(([a-z\d]+\-+)*[a-z\d]+\.)+[a-z]{2,}$/i;
	return re.test(strEmailAddr);
}

// returns true if URL is valid
// supports http and https URLs
// URL can contain a valid domain name or a valid IP Address
// URL can contain an optional port
// path can contain no white space chars
function isValidURL(strURL) {
	if (strURL.search(/^([hH][tT][tT][pP][sS]?)\:\/\/(((?:[A-Za-z0-9]+(?:[-A-Za-z0-9]*[A-Za-z0-9]+)?\.)*([A-Za-z0-9]+(?:[-A-Za-z0-9]*[A-Za-z0-9]+)?\.[A-Za-z]{2,}))|((?:(?:(?:[01]?[0-9]?[0-9])|(?:2[0-4][0-9])|(?:25[0-5]))\.){3}(?:(?:[01]?[0-9]?[0-9])|(?:2[0-4][0-9])|(?:25[0-5]))))(:[0-9]{1,5})?((\/(?:[^\/\s]*\/)*)(\S*))?$/) != -1) return true;
	else return false;
}

// returns true if phone number is valid (North America only) any extentions must separated by an 'x'
// 2nd arg is optional and defaults to true
function isValidPhone(strPhone, blnAllowExtensions) {
	 if (blnAllowExtensions == null || blnAllowExtensions == true) {
		// allow extensions
		if (strPhone.search(/^\(?[0-9]{3}\)? *\-? *[0-9]{3} *\-? *[0-9]{4}(x *[0-9]+)?$/) != -1) return true;
		else return false;
	 } else {
		// do not allow extensions
		if (strPhone.search(/^\(?[0-9]{3}\)? *\-? *[0-9]{3} *\-? *[0-9]{4}$/) != -1) return true;
		else return false;
	 }
}

function formatPhone(strPhone) {
	// give up if this isn't a valid phone number
	if (!isValidPhone(strPhone)) return strPhone;
	
	var strDigits = stripNonDigits(strPhone);
	var strFormatedPhone = '(' + strDigits.substr(0, 3) + ') '
					 + strDigits.substr(3, 3) + '-'
					 + strDigits.substr(6, 4);
			 
	if (strDigits.length > 10) strFormatedPhone += ' ext. ' + strDigits.substr(10);
	return strFormatedPhone;
}

// returns true if valid US zip code eg. 00000-0000 (last 4 digits are optional)
function isValidZip(strZip) {
     if (strZip.search(/^[0-9]{5}( *\-? *[0-9]{4})?$/) != -1) return true;
     else return false;
}

// returns true if valid Canadian postal code
function isValidPostalCode(strPostalCode) {
     if (strPostalCode.search(/^[A-Z][0-9][A-Z] *[0-9][A-Z][0-9]$/i) != -1) return true;
     else return false;
}

// returns true if valid network address (i.e. 0.0.0.0 through 255.255.255.255)
function isValidIP(strIP) {
     if (strIP.search(/^([0-9]|([1-9][0-9])|(1[0-9][0-9])|(2[0-4][0-9])|(25[0-5]))(\.([0-9]|([1-9][0-9])|(1[0-9][0-9])|(2[0-4][0-9])|(25[0-5]))){3}$/) != -1) return true;
     else return false;
}

// returns true if valid Social Security Number
function isValidSSN(strSSN) {
     if (strSSN.search(/^[0-9]{3} *-? *[0-9]{2} *-? *[0-9]{4}$/) != -1) return true;
     else return false;
}

// strips non digits from a number.
function stripNonDigits(strText) {
	return strText.replace(/[^0-9]+/g, '');
}

// returns true if the string has only numbers. This is different from isNaN because it doesn't allow negative numbers and exponential expressions
function isDigits(strText) {
     if (strText.search(/^[0-9]+$/) != -1) return true;
     else return false;
}

// returns true if valid Merge Code
function isValidMergeCode(strText) {
     if (strText.search(/^#[0-9a-zA-Z]+#$/) != -1) return true;
     else return false;
}

// returns true if strCurrecy is correctly formatted as currency (optionally includes: commas, dollar sign prefix, decimal)
// some examples are:
// $1 $1.5 $1.50 $1000000.5 $1000000.50 $1,000,000 $1,000,000.5 $1,000,000.50 $.50 $.5
//  1  1.5  1.50  1000000.5  1000000.50  1,000,000  1,000,000.5  1,000,000.50  .50  .5
function isValidCurrency(strCurrency) {
     if (strCurrency.search(/^\$?((((\d+)|(\d{1,3}(,\d{3})*))(\.\d{0,2})?)|(\.\d{1,2}))$/) != -1) return true;
     else return false;
}

// formats a string as currency
function formatCurrency(vntNum) {
    var num = vntNum.toString().replace(/\$|\,/g,'');
    if(isNaN(num)) num = "0";
    var sign = (num == (num = Math.abs(num)));
    num = Math.floor(num*100+0.50000000001);
    var cents = num%100;
    num = Math.floor(num/100).toString();
    if(cents<10)
         cents = "0" + cents;
    for (var i = 0; i < Math.floor((num.length-(1+i))/3); i++)
         num = num.substring(0,num.length-(4*i+3))+','+num.substring(num.length-(4*i+3));
    return (((sign)?'':'-') + '$' + num + '.' + cents);
}                              

// returns the number of days in a month. objDate is a JavaScript Date object
// sample usage
// var daysInFeb2004 = getNumDaysInMonth(new Date(2004, 1, 1)); // JavaScript months start at 0! Jan=0, Feb=1 ...
// var daysInCurrentMonth = getNumDaysInMonth(new Date());
//
function getNumDaysInMonth(objDate) {
     var monthIndex = objDate.getMonth();
     if (monthIndex == 1) { // February
		if (objDate.getYear() % 4 == 0) return 29; // leap year
		else return 28; // non leap year
     } else if (monthIndex == 3 || monthIndex == 5 || monthIndex == 8 || monthIndex == 10) {
		return 30; // April, June, September, November
     } else {
		return 31; // January, March, May, July, August, October, December
     }
     return null;
}

// splits a string on the delimiter. returns an array of strings
function split(strDelimited, strDelimiter) {
	var splitString = new Array();
	var pos=0, pos2=strDelimited.indexOf(strDelimiter, pos);
	while (pos2 != -1) {
		splitString[splitString.length] = strDelimited.substring(pos, pos2);
		pos = pos2 + strDelimiter.length;
		pos2 = strDelimited.indexOf(strDelimiter, pos);
	}
	splitString[splitString.length] = strDelimited.substr(pos);
	return splitString;
}

function getRadio(objRadioCollection, strValue) {
	for (var i = 0; objRadioCollection[i] != null; i++) {
		if (objRadioCollection[i].value == strValue) return objRadioCollection[i];
	}
	return null;
}

function setRadioChecked(objRadioCollection, strValue, blnChecked) {
	var objRadioBtn = getRadio(objRadioCollection, strValue);
	if (objRadioBtn != null) objRadioBtn.checked = blnChecked;
}

function getRadioChecked(objRadioCollection, strValue) {
	var objRadioBtn = getRadio(objRadioCollection, strValue);
	if (objRadioBtn != null && objRadioBtn.checked) return true;
	return false;
}

function getRadioValue(objRadioCollection) {
	for (var i = 0; objRadioCollection[i] != null; i++) {
		if (objRadioCollection[i].checked) return objRadioCollection[i].value;
	}
	return null;
}

function setRadioDisabled(objRadioCollection, strValue, bDisabled) {
	var objRadioBtn = getRadio(objRadioCollection, strValue);
	if (objRadioBtn != null) objRadioBtn.disabled = bDisabled;
}

// returns an array containing pointers to the selected options in the selectbox
function getSelections(selectBox) {
     var selectedOptions = new Array(0);
     for (var i=0; i < selectBox.options.length; i++) {
          if (selectBox.options[i].selected) {
               selectedOptions[selectedOptions.length] = selectBox.options[i];
          }
     }
     return selectedOptions
}

// Selects all options in a selectBox with the specified value, or all options if value == null
// the last argument indicates whether to select or unselect the options
// the last 2 arguments are optional.
function selectOptions(selectBox, value, selected) {
	var selectStatus = (selected != null) ? selected : true;
	for (var i=0; i < selectBox.options.length; i++) {
		if (value == null || selectBox.options[i].value == value) {
			selectBox.options[i].selected = selectStatus;
		}
	}
}

// removes seleced options from a selectbox
function removeSelections(selectBox) {
     for (var i=selectBox.options.length-1; i >= 0; i--) {
          if (selectBox.options[i].selected) {
               selectBox.options[i] = null;
          }
     }
}

// copies selected options from source selectbox to destination selectbox
function copySelections(source, dest) {
     var selections = getSelections(source);
     for (var i=0; i < selections.length; i++) {
          if (!optionExists(selections[i], dest)) {
               dest.options[dest.options.length] = new Option(selections[i].text, selections[i].value);
          }
     }
}

// moves selected options from source selectbox to destination selectbox
function moveSelections(source, dest) {
     copySelections(source, dest);
     removeSelections(source);
}

// adds an option to a selectbox only if an option with that value does not already exist
function addOption(option, selectBox) {
    if (!optionExists(option, selectBox)) {
         selectBox.options[selectBox.options.length] = new Option(option.text, option.value);
    }
}

// returns true if the selectbox contains the option, and false if it does not.
function optionExists(option, selectBox) {
     for (var i=0; i < selectBox.options.length; i++) {
          if (selectBox.options[i].value == option.value) return true;
     }
     return false;
}

function trim(str) {
	str = '' + str;
	var startFound = false, endFound = false, strLength = str.length, badChars = ' 	';
	for (var i=0; i < strLength; i++) {
		if (!startFound && badChars.indexOf(str.charAt(0)) != -1) str = str.substring(1, str.length);
		else startFound = true;
		if (!endFound && badChars.indexOf(str.charAt(str.length-1)) != -1) str = str.substring(0, str.length-1);
		else endFound = true;
	}
	return str;
}

function replace(strText, strFind, strReplace) {
	var strNew = new String(strText);
	var i = 0;

	while ((i = strNew.indexOf(strFind, i)) != -1) {
		strNew = strNew.substr(0, i) + strReplace + strNew.substr(i + strFind.length);
		
		i += strReplace.length;
	}
	
	return strNew;
}


function findTop() {
	/***********************************************************************
	 ** Description -  Traverses up a frame structure to find a particular
	 **                frame which has been labeled as the "top" frame
	 ***********************************************************************/
	var objCurrentFrame = self;
	
	while (true) {
		if (objCurrentFrame.m_blnIsTopFrame) return objCurrentFrame;
		
		if (objCurrentFrame != objCurrentFrame.parent) objCurrentFrame = objCurrentFrame.parent;
		else if (objCurrentFrame.opener) objCurrentFrame = objCurrentFrame.opener;
		else return null;
	}
}

function findFrame(strFrameName, objFrame) {
	/***********************************************************************
	 ** Description -  Finds the frame with the name specified or returns
	 **                null if unfound.
	 ***********************************************************************/
	var objReturnVal = null;
	var aobjFrames, strCrntFrameName;
	
	//-- If no frame is currently defined, find the top most accessible frame
	if (objFrame == null) {
		//-- Find topmost frame that current window has access to
		var winTopMost = self;

		while (winTopMost != winTopMost.parent) {
			try {
				//-- Try to access a property that will throw an error if denied
				aobjFrames = winTopMost.parent.frames;
				strCrntFrameName = winTopMost.parent.name;
				winTopMost = winTopMost.parent;
			}
			catch (e) {
				break;
			}
		}
	
		return findFrame(strFrameName, winTopMost);
	}
	
	//-- Get a reference to subframes of the current frame
	try {
		aobjFrames = objFrame.frames;
	}
	catch (e) {
		return null;
	}
	
	//-- Traverse frame structure looking for a match
	for (var i = 0; i < aobjFrames.length; i++) {
		//-- First try to access a property to see if page has access
		try {
			strCrntFrameName = aobjFrames[i].name;
		}
		catch (e) {
			continue;
		}
		
		//-- See if this is the frame being searched for
		if (strCrntFrameName == strFrameName) {
			return aobjFrames[i];
		}
		else {
			objReturnVal = findFrame(strFrameName, aobjFrames[i]);
			if (objReturnVal != null) return objReturnVal;
		}
	}
	
	return null;
}


function urlEncode(strText) {
	var strValidChars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
	var strEncodedText = '';
	strText = new String(strText); //-- Just in case it's a number
	
	//-- Create an array of exceptions to the escape() function.
	var astrExceptions = new Array();
	astrExceptions['*'] = '%2A';
	astrExceptions['+'] = '%2B';
	astrExceptions['-'] = '%2D';
	astrExceptions['.'] = '%2E';
	astrExceptions['/'] = '%2F';
	astrExceptions['@'] = '%40';
	astrExceptions['_'] = '%5F';
	astrExceptions[' '] = '+';
	
	for (var i = 0; i < strText.length; i++) {
		//-- See if character at i is valid
		if (strValidChars.indexOf(strText.charAt(i)) == -1) {
			//-- If not valid, see if it's an exception to the escape() functionality
			if (astrExceptions[strText.charAt(i)] != null) {
				strEncodedText += astrExceptions[strText.charAt(i)];
			}
			else {
				strEncodedText += escape(strText.charAt(i));
			}
		}
		else strEncodedText += strText.charAt(i)
	}
	
	return strEncodedText;
}

function urlDecode(strText) {
	strText = strText.replace(/\+/g, ' ');
	return unescape(strText);
}


function parseQueryString() {
	var astrQueryString = new Array();
	var strQueryString = location.search;
	var astrPairs, strKey, strValue, intIndex;
	
	if (strQueryString.charAt(0) == '?') strQueryString = strQueryString.substr(1);
	if (strQueryString.length == 0) return astrQueryString;
	
	astrPairs = strQueryString.split('&');
	
	for (var i = 0; i < astrPairs.length; i++) {
		if (astrPairs[i].length > 0) {
			if ((intIndex = astrPairs[i].indexOf('=')) != -1) {
				strKey = urlDecode(astrPairs[i].substr(0, intIndex));
				strValue = urlDecode(astrPairs[i].substr(intIndex + 1));
			}
			else {
				strKey = urlDecode(astrPairs[i]);
				strValue = '';
			}
			
			if (astrQueryString[strKey] == null) astrQueryString[strKey] = '';
			else astrQueryString[strKey] += ', ';
			astrQueryString[strKey] += strValue;
		}
	}
	
	return astrQueryString;
}


function textToHtml(strText) {
	var strHtml = new String(strText);
	
	strHtml = strHtml.replace(/&/g, '&amp;');
	strHtml = strHtml.replace(/</g, '&lt;');
	strHtml = strHtml.replace(/>/g, '&gt;');
	strHtml = strHtml.replace(/"/g, '&quot;');
	strHtml = strHtml.replace(/\r\n/g, '<BR>');
	
	return strHtml;
}

function htmlToText(strHtml) {
	var strText = new String(strHtml);
	
	strText = strText.replace('&amp;', /&/g);
	strText = strText.replace('&lt;', /</g);
	strText = strText.replace('&gt;', />/g);
	strText = strText.replace('&quot;', /"/g);
	strText = strText.replace('<BR>', /\r\n/g);
	
	return strText;
}


function xmlEncode(strText) {
	var strXML = new String(strText);
	
	strXML = strXML.replace(/&/g, '&amp;');
	strXML = strXML.replace(/</g, '&lt;');
	strXML = strXML.replace(/>/g, '&gt;');
	strXML = strXML.replace(/"/g, '&quot;');
	strXML = strXML.replace(/'/g, '&apos;');
	
	return strXML;
}


function ObjectPosition(obj) {
	this.top = 0;
	this.left = 0;

	do {
		this.top += (isNaN(parseInt(obj.offsetTop))) ? 0 : parseInt(obj.offsetTop);
		this.left += (isNaN(parseInt(obj.offsetLeft))) ? 0 : parseInt(obj.offsetLeft);
	} while (obj = obj.offsetParent)
}


function getDisplayHeight() {
	if (window.innerHeight)
		return parseInt(window.innerHeight);
	
	if (document.documentElement && document.documentElement.clientHeight && document.documentElement.clientHeight > 0)
		return parseInt(document.documentElement.clientHeight);
	
	if (document.body && document.body.clientHeight)
		return parseInt(document.body.clientHeight);
	
	return -1;
}


function getDisplayWidth() {
	if (window.innerWidth)
		return parseInt(window.innerWidth);
	
	if (document.documentElement && document.documentElement.clientWidth && document.documentElement.clientWidth > 0)
		return parseInt(document.documentElement.clientWidth);
	
	if (document.body.clientWidth)
		return parseInt(document.body.clientWidth);
	
	return -1;
}


function getScrollTop() {
	if (document.body.scrollTop) return parseInt(document.body.scrollTop);
	if (window.pageYOffset) return parseInt(window.pageYOffset);
	return -1;
}


//strips chars from a string which do not match the pattern parameter passed to the function
function regExReplace(strText, strPattern) {
	
	return strText.replace(strPattern, '');
	
}


// Cookie functions
function setCookie(name, value, expires, path, domain, secure) {
  var curCookie = name + "=" + escape(value) +
      ((expires) ? "; expires=" + expires.toGMTString() : "") +
      ((path) ? "; path=" + path : "") +
      ((domain) ? "; domain=" + domain : "") +
      ((secure) ? "; secure" : "");
  document.cookie = curCookie;
}

function getCookie(name) {
  var dc = document.cookie;
  var prefix = name + "=";
  var begin = dc.indexOf("; " + prefix);
  if (begin == -1) {
    begin = dc.indexOf(prefix);
    if (begin != 0) return null;
  } else
    begin += 2;
  var end = document.cookie.indexOf(";", begin);
  if (end == -1)
    end = dc.length;
  return unescape(dc.substring(begin + prefix.length, end));
}


function deleteCookie(name, path, domain) {
  if (getCookie(name)) {
    document.cookie = name + "=" + 
    ((path) ? "; path=" + path : "") +
    ((domain) ? "; domain=" + domain : "") +
    "; expires=Thu, 01-Jan-70 00:00:01 GMT";
  }
}


/**
 * Modifies a property of a CSS rule defined in a style sheet
 *
 * @param  win       The window object in which the rule is defined (e.g. self, window.frames['frame1'])
 * @param  selector  The selector for the rule (e.g. '.myClass', '#titleDiv')
 * @param  property  The style property to modify. Use javascript style property names, not CSS
 *                   style (e.g. 'borderWidth', not 'border-width').
 * @param  value     The new value for the property
 */
function modifyCSSRule(win, selector, property, value)
{
	var rules = findCSSRule(win, selector);
	
	for (var i = 0; i < rules.length; i++)
		rules[i].style[property] = value;
}

/**
 * Searches all style sheets in a window for a CSS rule
 *
 * @param  win       The window object in which the rule is defined (e.g. self, window.frames['frame1'])
 * @param  selector  The selector for the rule (e.g. '.myClass', '#titleDiv')
 *
 * @return  An array of all CSS rules found with the given selector
 */
function findCSSRule(win, selector)
{
	var matchingRules = new Array();
	
	if (win.document && win.document.styleSheets)
	{
		for (var i = 0; i < win.document.styleSheets.length; i++)
		{
			try //-- Sometimes an unknown access error occurs
			{
				var rules = null;
				if (win.document.styleSheets[i].cssRules)
					rules = win.document.styleSheets[i].cssRules;
				else if (win.document.styleSheets[i].rules)
					rules = win.document.styleSheets[i].rules;
				
				if (rules)
				{
					for (var j = 0; j < rules.length; j++)
					{
						if (rules[j].selectorText && rules[j].selectorText == selector)
						{
							matchingRules.push(rules[j]);
						}
					}
				}
			}
			catch (err) { }
		}
	}
	
	return matchingRules;
}

