/* 
$Id: bjup-1.15.js 3047 2009-04-23 23:21:23Z nlwillia $
*/

function validateString(strToCheck, validChars)
{
	for(var i=0; i<strToCheck.length; i++) {
		if(validChars.indexOf(strToCheck.charAt(i)) == -1)
			return false;
	}
	return true;
}

function validateQty(qtyObj, showError, isCSR)
{
	var qtyValue = qtyObj.value;
	var nQtyValue = parseFloat(qtyValue, 10);
	
 	if (qtyValue == "" || isNaN ( qtyValue ) || !validateString(qtyValue, "1234567890")) {
	 	if (showError) {
			if(isCSR) {
				alert("Quantity must be a number.");
			}else {
				alert("Quantity must be between 1 and 250.");
			}
			qtyObj.focus();
			qtyObj.select();
		}
  		return false;
 	}

 	if ( nQtyValue <= 0 || nQtyValue % 1 > 0 )
 	{
		if (showError) {
			if(isCSR){
				alert("Quantity must be whole number greater than 0.");
			}else{
				alert("Quantity must be between 1 and 250.");
			}
			qtyObj.focus();
			qtyObj.select();
		}
  		return false;
 	}

 	if (isNaN(nQtyValue))
 	{
	 	if (showError) {
			if(isCSR) {
				alert( "Quantity must be a number.");
			} else {
				alert( "Quantity must be between 1 and 250.");
			}
			qtyObj.focus();
			qtyObj.select();
		}
  		return false;
 	}

 	if (nQtyValue > 250 && !isCSR)
 	{
		if (showError) {
			alert( "Quantity must be between 1 and 250." );
			qtyObj.focus();
			qtyObj.select();
			qtyObj.value = 250;
		}
  		return false;
 	}
 	return true;
}

/** @return true if the argument contains 6 digits and has a valid SKU checksum. */
function isValidItem(s) {

	var num = Number(s);
	if (isNaN(num)) {
		return false;
	}
	
	s = num.toString();
	
	if (s.length > 6) {
		return false;
	}

	// Pad to the left with zeros.  e.g.: "75" becomes "000075"
	while (s.length < 6) {
		s = "0" + s;
	}

	/* Because item numbers have a fixed width, we can conveniently use instance variables
	   to represent each digit instead of something dynamic.  This approach maps each
	   ASCII 0x30 - 0x39 to an ordinal 0-9.  The length test ensures that the string is not
	   indexed out of bounds.  The '& 0x000F' filters out the ASCII 0x30 bits leaving only
	   an ordinal result.  The mapping order is d6..d1 where d6 is the least significant.
	*/
	 var d6 = s.charAt(5) & 0x000F;
	 var d5 = s.charAt(4) & 0x000F;
	 var d4 = s.charAt(3) & 0x000F;
	 var d3 = s.charAt(2) & 0x000F;
	 var d2 = s.charAt(1) & 0x000F;
	 var d1 = s.charAt(0) & 0x000F;

	// The checksum algorithm requires that the odd indexed digits (left-to-right) be doubled.
	d1 <<= 1;
	d3 <<= 1;
	d5 <<= 1;

	/* Then, we add the digits of the doubled results:
	   i.e.:  1 * 2 = 0 2  -->  0 + 2 = 2
	          9 * 2 = 1 8  -->  1 + 8 = 9

	   - The '/10' operation gives us the tens position, but we have to floor it to get an
	     integer result.  Because the largest single digit is 9 and it only doubles to 18,
	     there will never be a 100's position to worry about.
	   - The '%10' operation gives us the ones position.  Mod returns an integer by default.
	*/
	d1 = Math.floor(d1 / 10) + (d1 % 10);
	d3 = Math.floor(d3 / 10) + (d3 % 10);
	d5 = Math.floor(d5 / 10) + (d5 % 10);

	var sum = d1 + d2 + d3 + d4 + d5;

	/* The checkdigit is the last digit of the sum subtracted from 10.  The checkdigit must
	   be a single digit 0-9.  If the last digit of the sum is '0' (say the sum is 10) then
	   the result (10) must be trimmed to '0'.  The first mod gets the last digit of the sum.
	   The second mod ensures that it's 0-9.
	*/
	var checkdigit = (10 - (sum % 10)) % 10;
	
	// An item number is valid if its last digit (least significant) equals the checkdigit.
	return d6 == checkdigit && num > 0;
}

/** @return true if the argument contains 10 or 13 digits and has a valid ISBN checksum. */
function isValidISBN(s) {
	if (s) {
		var normalized = "";
		for (var i = 0; i < s.length; i++) {
			if (!isNaN(s[i]) || s[i] == 'X') {
				normalized += s[i];
			}
		}

		var digits = [];
		for (var i = 0; i < normalized.length - 1; i++) {
			digits[i] = normalized[i] == 'X' ? 10 : normalized[i] & 0x000F;
		}

		var sum = 0;
		var checkdigit = null;

		if (normalized.length == 13) {
			for (var i = 0; i < 11; i += 2) {
				sum += digits[i];
			}
			for (var i = 1; i < 12; i += 2) {
				sum += digits[i] * 3;
			}
			checkdigit = (10 - sum % 10) % 10;
		} else if (normalized.length == 10) {
			for (var i = 0; i < 9; i++) {
				sum += digits[i] * (10 - i);
			}
			checkdigit = (11 - sum % 11) % 11;
			if (checkdigit == 10) {
				checkdigit = "X";
			}
		}
		return checkdigit == normalized[normalized.length-1];
	}
	return false;
}


function removeSpace( field ) {
	var txtIn = field.value;
	var txtOut = "";;

	for ( var i = 0 ; i < txtIn.length ; i ++ ) {
		if ( txtIn.charAt( i ) != ' ' )
			txtOut += txtIn.charAt( i );
	}
	field.value = txtOut;
}

// method to trim off (brackets, dash and/or spaces)
// Dv - august 28, 2003
function replace (repString , from , to , maxIter ) {
	var out = "";
	while ( repString.indexOf( from ) >= 0 ) {
		out += ( repString.substring ( 0 , repString.indexOf ( from ) ) + to );
		repString = repString.substring( repString.indexOf ( from ) + from.length, repString.length);
		if( --maxIter == 0 ) break;
	}
	out += repString;
	return out;
}
// end of replace functions

//////////////////////////////////////////////////////////////////
function ltrim2(fieldValue)
{
	if (""==fieldValue)
	{
		return "";
	}

	cnt = 0;
	len = fieldValue.length;
	while (cnt<len)
	{
		if (' '!=fieldValue.charAt(cnt) && '\t'!=fieldValue.charAt(cnt))
			break;
		cnt++;
	}
	return fieldValue.substring(cnt,len);
}

function rtrim2(fieldValue)
{
	if (""==fieldValue)
	{
		return "";
	}

	len = fieldValue.length;
	while (0!=len)
	{
		if (' '!=fieldValue.charAt(len-1) && '\t'!=fieldValue.charAt(cnt))
			break;
		len--;
	}
	return fieldValue.substring(0, len);
}

function trim(fieldValue)
{
	return rtrim2(ltrim2(fieldValue));
}


function trimAllTextInput(form)
{
	for(var i=0; i<form.length; i++)
	{
		if(form.elements[i].type == 'text' || form.elements[i].type == 'password')
		{
			form.elements[i].value = trim(form.elements[i].value);
		}
		else continue;
	}
}

function validatePhone(objPhone) {
	re = /^\(?(\d{3})\)? ?(\d{3})-?(\d{4})(x\d{0,6})?$/

	OK = re.exec(objPhone.value)
	if (!OK)
			return false;
	else
		return true;
}

// Validates address components: Address Line(s), City, State, Zip, and Country
// Sets cursor focus and/or select on invalid fields
function validAddress(form) {
	if (!validAddressLines(form))
		return false;
		
	if (form.city.value == "") {
		alert ("City is missing. Please enter the city and resubmit.");
		form.city.focus();
		return false;
	}

	var country = form.country.options[form.country.selectedIndex].value;

	if (form.state.options[form.state.selectedIndex].value == "" && (country == "USA" || country == "CAN")) {
		alert ("Please select a state and resubmit.");
		form.state.focus();
		return false;
	}
	
	if (!validZip(form.country, form.zipCode)) {
		form.zipCode.focus();
		form.zipCode.select();
		return false;
	}

	if (country == "") {
		alert ("Please select a country and resubmit.");
		form.country.focus();
		return false;
	}
	return true;
}

// Verifies there is only one address line for USA and CAN addresses
// Prevents preceding address lines from being blank
// Sets cursor focus and/or select on invalid fields
function validAddressLines(form) {
	if (form.address1.value == "") {
		alert ("Address is missing. Please enter the address and resubmit.");
		form.address1.focus();
		return false;
	}

	var country = form.country.options[form.country.selectedIndex].value;
	
	// enforce one address line for USA and Canadian addresses
	if ((country == "USA" || country == "CAN") && (form.address2.value != "" || form.address3.value != "" || form.addressField2.value != "")) {
		alert("Please use a single line for USA and Canadian addresses.");
		if (form.address2.value != "") {
			form.address2.focus();
			form.address2.select();
		}
		else if (form.address3.value != "") {
			form.address3.focus();
			form.address3.select();
		}
		else if (form.addressField2.value != "") {
			form.addressField2.focus();
			form.addressField2.select();
		}
		return false;
	}
	
	// enforce the preceding line must be non-blank before accepting input on next line when non-US, non-CDN addresses
	if (form.country.options[form.country.selectedIndex].value != "USA" && form.country.options[form.country.selectedIndex].value != "CAN") {
		// Line 4
		if (form.addressField2.value != "" ) {
			if (form.address3.value == "" || form.address2.value == "" ) {
				alert( "Line 2 or 3 of the entered address is empty.  Please correct this problem." );
				form.address2.focus();
				form.address2.select();
				return false;
			}
		}
	
		// Line 3
		if (form.address3.value != "" ) {
			if (form.address2.value == "" ) {
				alert( "Line 2 of the entered address is empty.  Please correct this problem." );
				form.address2.focus();
				form.address2.select();
				return false;
			}
		}
	}
	return true;
}

// determines if the form has changed since the form was loaded
function hasFormChanged(form) {
	// loop through all elements of the form
	for (var i=0; i<form.length; i++) {
		var element = form.elements[i];
		if (element.type != 'hidden')
			// Test non-hidden element types to see if they have changed
			if (hasElementChanged(element))
				return true;
	}
	return false;
}

// determines if passed element has changed since the form was loaded
function hasElementChanged(element) {
// supports element types of text, password, dropdown (select-one), checkbox, or radio
	if (element.type == 'text' || element.type == 'password') {
		//alert('Element ' + element.name + ' of type ' + element.type + ' and value of ' + element.value +
		//	' has defaultValue of ' + element.defaultValue);
		if(element.defaultValue != element.value) {
			return true;
		}
	}
	else if (element.type == 'select-one') {
		//alert('Element ' + element.name + ' of type ' + element.type + ' has defaultSelected of ' + 
		//	element.options[element.selectedIndex].defaultSelected);
		if (!element.options[element.selectedIndex].defaultSelected) {
			return true;
		}
	}
	else if (element.type == 'checkbox' || element.type == 'radio') {
		//alert('Element ' + element.name + ' of type ' + element.type + ' and value of ' + element.value +
		//	' has defaultChecked of ' + element.defaultChecked + ' Checked of ' + element.checked);
		if (element.defaultChecked != element.checked) {
			return true;
		}
	}
	return false;
}

// Sets the required fields accourding to the passed in value
function switchFieldRqdStatusForPreferredContact( preferredContactMethod )   {
	//preferred communication method
	 if(preferredContactMethod == "P1") {
		showRequired(document.images["imgP1"]);
		hideRequired(document.images["imgP2"]);
		hideRequired(document.images["imgFX"]);
	} 
	else if(preferredContactMethod == "P2") {
		hideRequired(document.images["imgP1"]);
		showRequired(document.images["imgP2"]);
		hideRequired(document.images["imgFX"]);
	} 
	else if(preferredContactMethod == "FX") {
		hideRequired(document.images["imgP1"]);
		hideRequired(document.images["imgP2"]);
		showRequired(document.images["imgFX"]);
	} 
	else {
		hideRequired(document.images["imgP1"]);
		hideRequired(document.images["imgP2"]);
		hideRequired(document.images["imgFX"]);
	}
}

// Sets the required fields according to the select country
function switchFieldRqdStatusForCountry(form) {
	var country = form.country.options[form.country.selectedIndex].value;

	if(country == 'USA' || country == 'CAN' || country=='   ') {
		showRequired(document.images["imgState"]);
		showRequired(document.images["imgZip"]);
	}
	else {
		hideRequired(document.images["imgState"]);
		hideRequired(document.images["imgZip"]);
	}
}

// Hides the required image indicator and removes the alt text
function hideRequired(img) {
	img.width = 0;
	img.heigth = 0;
	img.alt = "";
}

// Shows the required image indicator and adds the alt text
function showRequired(img) {
	img.width = 8;
	img.heigth = 9;
	img.alt = "Required Field";
}

//EVENT HANDLING METHODS

// returns true if browser type is Internet Explorer
function isIETypeBrowser() {
	if (navigator.appVersion.indexOf("MSIE")!=-1)
		return true;
	else
		return false;
}

//returns the keycode of the key that was pressed
function getKeyPressed(event) {
	var key;
	if (isIETypeBrowser())
		// IE does not pass in an object, but makes the event object availble through the window object
		key = window.event.keyCode;
	else
		// For Gecko based browser, an event object will be passed in
		key = event.which;
	return key;
}

// stops Event Handling
function stopEventHandling(event) {
	if (isIETypeBrowser()) {
		window.event.returnValue = false;
		window.event.cancelBubble = false;
	}
	else {
		// these are supposed to stop further event activity in Gecko browsers, but didn't work when the tab key was pressed
		event.preventDefault();
		event.stopPropagation();
	}
}

function validZip(country, zipCode) {

	nation = country.value;
	zipCode.value = trim(zipCode.value); //trim it on the form
	zip =  zipCode.value;

	switch(nation)
	{
		case 'USA' :
			re = /^\d{5}(-\d{4})?$/;
			OK = re.exec(zip);
			if (!OK) {
				alert ("Invalid zip code. Expected format is 'NNNNN' or 'NNNNN-NNNN'. Please reenter the zip code and resubmit.");				
			}
			break;
		case 'CAN':
			//re = /^([a-zA-Z0-9]{3}) ?([a-zA-Z0-9]{3})$/;
			re = /^([A-Z]{1}[0-9]{1}[A-Z]{1}) ?([0-9]{1}[A-Z]{1}[0-9]{1})$/;
			OK = re.exec(zip.toUpperCase());
			if (!OK){
				alert ("Invalid postal code. Expected format is 'ANA NAN'. Please reenter the postal code and resubmit.");
			}else{
				zipCode.value = RegExp.$1 +  ' ' + RegExp.$2;
			}
			break;
		default:
			OK = true;
			if (zipCode.value.length > 7 && zipCode.value.length != 0) 
			{
				alert('Zip code for countries other than U.S. cannot exceed 7 characters.');
				OK = false;
			}
			
	}
	if (!OK){
		zipCode.focus();
		zipCode.select();
		return false;
	}
	else{
		return true;
	}
}

// double click validation
// @return 0: ok to sumbit; 1: dont submit; 2: retry to submit
function checkDoubleClick( countClick , type ) {
	if (null!=countClick && "0"==countClick.value)
	{
		setDblChkForm(countClick, "1");
	}
	else
	{
		if (null!=countClick && "1"==countClick.value)
		{
			if ( type != null && type == "alert" ) {
				alert( "Your request is being processed. Please wait ..." );
				return 1;
			}
			else
			{
				if( confirm ( "Did you double-click?  Please answer 'OK' and wait for the page to return.  If you arrived at this page by using the back button, answer 'Cancel' and you will be taken to the next page." ) )
				{
					return 1;
				}
				else
				{
					return 2;
				}
			}
		}
	}
	return 0;
}

function setDblChkForm(fldDblChk, fldValue)
{
	fldDblChk.value = fldValue;
}

	// sets focus to specified link (not field)
	// preferred
function setFocusToLink( lnkName ) {
	var elemFocus = document.getElementById( lnkName );
	if ( elemFocus != null ) {
		elemFocus.focus( );
	}
}

function setCookie(name, value, path, expires) {
	var c = name + "=" + value;
	if (path != null && path.length > 0) {
		c += "; path=" + path;
	}
	if (expires != null) {
		c += "; expires=" + expires.toGMTString();
	}
	document.cookie = c;
}

function getCookie(Name, valueIfUndefined) {
	var search = Name + "="
	var result = undefined;
	if (document.cookie.length > 0) { // if there are any cookies
		offset = document.cookie.indexOf(search)
		if (offset != -1) { // if cookie exists
			offset += search.length
			// set index of beginning of value
			end = document.cookie.indexOf(";", offset)
			// set index of end of cookie value
			if (end == -1)
				end = document.cookie.length
			result = unescape(document.cookie.substring(offset, end))
		}
	}
	if (result == undefined && valueIfUndefined != null) {
		result = valueIfUndefined;
	}
	return result;
}

// **************************************************************************
// Date Validation functions from date_validation.js
// **************************************************************************
//***** Last update: 2003-08-25 (dv) ( BJU-00492)

var _nameField = "form-test.date-one";
var _dateCurrent = applyFormat( new Date( ) , "mm/dd/yyyy" );
var _msgWindow = "";
var _onCalendarClose = "";

var _months = new Array ( "January" , "February" , "March" , "April" , "May" , "June" , "July" , "August" , "September" , "October" , "November" , "December" );
var _calendarWindow = null;

	// converts a string to date
function checkValidDate( value ) {
	if ( value != null ) {
  		var dateIn = new Date( Date.parse( value ) );
  		return isNaN( dateIn ) ? null : dateIn;
	}
	return null;
}


	// gets the difference between 2 dates in days
function getDaysDifference( dateOne , dateTwo ) {
	return ( dateOne.getTime( ) - dateTwo.getTime( ) ) / 86400000;
}


	// returns formatted token based on format and date specified
function formatToken( token , date ) {
	token = token.toLowerCase( );
	switch( token ) {
		case "m" 	: 	return pad( date.getMonth( ) + 1 , '0' , 1 );
		case "mm"	: 	return pad( date.getMonth( ) + 1 , '0' , 2 );
		case "mmm"	: 	return _months[ date.getMonth( ) ].substring( 0 , 3 );
		case "mmmm"	: 	return _months[ date.getMonth( ) ];
		case "y"	:
		case "yy"	:	return String( date.getFullYear( ) ).substring( 2 , 4 );
		case "yyy"	:
		case "yyyy"	: 	return date.getFullYear( );
		case "d"	: 	return pad( date.getDate( ) , '0' , 1 );
		case "dd"	: 	return pad( date.getDate( ) , '0' , 2 );
	}
	return( token );
}


	// gets next token
function getNextToken( value , ptr ) {

	var token = "";
	if ( value != null && value.length > ptr ) {
		do {
			token += value.charAt( ptr++ );
		} while ( token.charAt( 0 ) == value.charAt( ptr ) );
		return token;
	}
	return null;
}


	// pads a value with characters specified up to size
function pad( value , padWith , size ) {
	var valueStr = String( value );
	var padding = "";
	for ( var i = valueStr.length ; i < size ; i ++ )
		padding += padWith;
	return padding + valueStr;
}



	// applies format to date
function applyFormat( date , format ) {
	var ptr = 0;
	var result = "";
	var token = "";
	for ( token = getNextToken( format , ptr ) ; token != null ; token = getNextToken( format , ptr ) ) {
		ptr += token.length;
		result += formatToken( token , date );
	}
	return result;
}


	// shows calendar
function showCalendar( name , dateSelectedStr , caption , path, onCalendarClose ){
	if ( _calendarWindow == null || _calendarWindow.closed ) {
		_nameField = name;
		_dateCurrent = dateSelectedStr == null ? "" : dateSelectedStr;
		_msgWindow = caption;
		_onCalendarClose = onCalendarClose == null ? "" : onCalendarClose;
		var winAtts = "toolbar=0,scrollbars=0,width=288,height=270";
		_calendarWindow = window.open( path == null ? '/calendar.html' : path , 'Calendar' , winAtts );
	}
	else
		_calendarWindow.focus( );
}


	// closes the window
 function closeWindow( ) {
	 if ( _calendarWindow != null && ! _calendarWindow.closed )
	 	_calendarWindow.close( );
}
// end of common date presentation functions

//------------------------------------------------------------
/**
 * Alias for updateCheckboxes.
 */
function checkCheckboxes(form, namePrefix) {
	return updateCheckboxes(form, namePrefix, true);
}

/**
 * Alias for updateCheckboxes.
 */
function uncheckCheckboxes(form, namePrefix) {
	return updateCheckboxes(form, namePrefix, false);
}

/**
 * Checks all checkboxes on the form that are not already checked.
 * If all boxes are checked, unchecks all boxes.
 *
 * @param form The form containing the checkbox elements to toggle.
 * @param namePrefix Optional.  Default is "".  Prefix of checkbox name to match.
 * @param checkedFlag Optional.  Default is true.  Pass false to invert logic.
 * @return Whether all checkboxes are now checked.
 */
function updateCheckboxes(form, namePrefix, checkedFlag) {

	if (namePrefix == null) {
		namePrefix = "";
	}
	if (checkedFlag == null) {
		checkedFlag = true;
	}

	var allChecked = true;

	for (i = 0; i < form.elements.length; i++) {
		if (form.elements[i].type == "checkbox" && form.elements[i].name.indexOf(namePrefix) == 0) {
			allChecked &= form.elements[i].checked == checkedFlag;
		}
	}

	var newValue = allChecked ? !checkedFlag : checkedFlag;

	for (i = 0; i < form.elements.length; i++) {
		if (form.elements[i].type == "checkbox" && form.elements[i].name.indexOf(namePrefix) == 0) {
			form.elements[i].checked = newValue;
		}
	}
	return newValue;
}

//------------------------------------------------------------
/**
 * @param a select element
 * @return the value of the selected option
 */
function selectedValue(element) {
	if (element == null) {
		return null;
	} else if (element.type == "select") {
		return element.options[element.selectedIndex].value;
	} else {
		return element.value;
	}
}

/**
 * @param a select element
 * @param a value to select the index of
 * @return the index or -1
 */
function selectValue(sel, val) {
	for (var i=0; i < sel.options.length; i++) {
		if (sel.options[i].value == val) {
			sel.selectedIndex = i;
			return i;
		}
	}
	return -1;
}

//------------------------------------------------------------
/**
 * Helper functions for asynchronous XML over HTTP requests.
 *
 * ajax_request
 * @param url the url to target
 * @param callback the function that will be called when the request comes back.  (Will be passed the req object or null if the request failed.)
 * @param retry [optional, default -1] number of times to retry if the request fails; -1 is unlimited.
 * @param delay [optional, default 0] millis to wait before retry 
 * @param ... Any additional parameters will be passed to the callback following the request parameter
 * @return false if another request is already being processed
 * 
 * ajax_response
 * - If the response is successful, will call callback passing request object followed by any extra parameters.
 * - If the response fails, will retry as dictated by the retry/delay params to ajax_request.
 */
var ajax_request_object;	// Handle to the request object
var ajax_request_url;		// Last requested URL
var ajax_response_callback;	// Last registered callback
var ajax_retry_count;		// Number of times to retry a failed request.  -1 is unlimited.
var ajax_retry_delay;		// Time to wait between failed requests in millis.
var ajax_callback_args;		// Array of arguments to pass to the callback

function ajax_request(url, callback, retry, delay) {
	if (ajax_request_object) {
		return false; // already handling a request
	}
	ajax_request_object = null;
	ajax_requext_url = url;
	ajax_response_callback = callback;
	ajax_retry_count = (retry != null && retry >= 0) ? retry : -1;
	ajax_retry_delay = (delay != null && delay > 0) ? delay : 0;

	if (arguments.length > 4) {
		if (ajax_callback_args && arguments[4] == ajax_callback_args) {
			// retrying
		} else {
			arguments.slice = Array.prototype.slice;
			ajax_callback_args = arguments.length > 4 ? arguments.slice(4) : [];
		}
	}

	if (window.XMLHttpRequest) { // native XMLHttpRequest object
		ajax_request_object = new XMLHttpRequest();
		ajax_request_object.onreadystatechange = ajax_response;
		ajax_request_object.open("GET", url, true);
		ajax_request_object.send(null);

	} else if (window.ActiveXObject) { // IE/Windows ActiveX version
		ajax_request_object = new ActiveXObject("Microsoft.XMLHTTP");
		if (ajax_request_object) {
			ajax_request_object.onreadystatechange = ajax_response;
			ajax_request_object.open("GET", url, true);
			ajax_request_object.send();
		} else {
			setTimeout(callback, 1); // unsupported
		}

	} else {
		setTimeout(callback, 1); // unsupported
	}
	return true;
}

function ajax_response() {
	if (ajax_request_object.readyState == 4) { // "complete"
		if (ajax_request_object.status == 200) { // "OK"
			ajax_response_callback.apply(this, [ajax_request_object].concat(ajax_callback_args));
			ajax_request_object = null;
			ajax_callback_args = null;
		} else {
			if (ajax_retry_count == 0) {
				ajax_request_object = null;
				ajax_response_callback.apply(this, [ajax_request_object].concat(ajax_callback_args));
			} else if (ajax_retry_count > 0) {
				ajax_retry_count--;
				setTimeout(ajax_request, ajax_retry_delay, ajax_request_url, ajax_response_callback, ajax_retry_count, ajax_retry_delay, ajax_callback_args);
			}
		}
	}
}

//------------------------------------------------------------
/**
 * Scrolls the window to the first error message on the page.
 * @return true if an error was found.
 */
function scrollToFirstError(className) {

	if (!className) {
		var className = "bjupErrorText";
	}
	var spans = document.getElementsByTagName('SPAN');

	for (i = 0; i < spans.length; i++) {
		if (spans[i].className == className) {
			window.scrollTo(0,_curtop(spans[i])-50);
			return true;
		}
	}
	return false;
}

/** Scrolls the window to the element indicated by id.  Offset is added to the computed vertical position. */
function scrollToId(id, offset) {
	var el = document.getElementById(id);
	if (el) {
		window.scrollTo(0, _curtop(el) + (offset ? offset : 0));
	}
}

/** Private */
function _curtop(obj) {
	// START: http://www.quirksmode.org/js/findpos.html
	var curtop = 0;
	if (obj.offsetParent)
	{
		while (obj.offsetParent)
		{
			curtop += obj.offsetTop
			obj = obj.offsetParent;
		}
	}
	else if (obj.y)
		curtop += obj.y;
	// END: http://www.quirksmode.org/js/findpos.html
	return curtop;
}

/** Sets the value of the field, then selects and focuses it. */
function setSelectAndFocus(field, value) {
	field.value = value;
	selectAndFocus(field);
}

/** Selects and focuses the field. */
function selectAndFocus(field) {
	field.select();
	field.focus();
}

/** Swaps the node's content with the value of one of its attributes (title by default). */
function swapNodeValueWithAttribute(node, attrName) {
	if (node != null) {
		if (attrName == null) {
			attrName = "title";
		}
		var attr = node.getAttributeNode(attrName);
		if (attr != null) {
			var value = node.innerHTML;
			node.innerHTML = attr.nodeValue;
			node.setAttribute(attrName, value);
		}
	}
}

var __lastToggledPair = [];

/** 
 * Sets the display of id1 to the opposite of what it is currently.  Sets id2 (optional) to the opposite of id1.
 * @return true if id1 exists and is now displayed.
 */
function toggleDisplay(id1, id2) {
	if (!id1) {
		if (__lastToggledPair[1]) {
			id1 = __lastToggledPair[1];
			id2 = __lastToggledPair[0];
		} else if (__lastToggledPair[0]) {
			id1 = __lastToggledPair[0];
		} else {
			return;
		}
	}
	__lastToggledPair = [ id1, id2 ];
	
	var el1 = document.getElementById(id1);
	if (el1) {
		return _setDisplay(el1.style.display == "none" ? true : false, el1, id2);
	}
}

/** 
 * Sets the display of id1 to default/none based on flag.  Sets id2 (optional) to the opposite.
 * @return true if id1 exists and is now displayed.
 */
function setDisplay(flag, id1, id2) {
	var el1 = document.getElementById(id1);
	if (el1) {
		return _setDisplay(flag, el1, id2);
	}
}

/** Private */
function _setDisplay(flag, el1, id2) {
	el1.style.display = flag ? "" : "none";
	if (id2) {
		var el2 = document.getElementById(id2);
		if (el2 && el2 != el1) {
			el2.style.display = flag ? "none" : "";
		}
	}
	return flag;
}

/**
 * Sets text/password/radio/checkbox/select/textarea controls to blank/unchecked/unselected.
 * Optional filter is a function called on each element that returns true if the element can be cleared.
 */
function clearForm(form, filter) {

	var inputs = form.getElementsByTagName("INPUT");
	for (var i = 0; i < inputs.length; i++) {
		var input = inputs[i];
		if (input.type == "text" || input.type == "password") {
			if (!filter || filter(input)) {
				input.value = "";
			}
		} else if (input.type == "radio" || input.type == "checkbox") {
			if (!filter || filter(input)) {
				input.checked = false;
			}
		}
	}
	
	var textareas = form.getElementsByTagName("TEXTAREA");
	for (var i = 0; i < textareas.length; i++) {
		var textarea = textareas[i];
		if (!filter || filter(textarea)) {
			textarea.value = "";
		}
	}
	
	var selects = form.getElementsByTagName("SELECT");
	for (var i = 0; i < selects.length; i++) {
		var select = selects[i];
		if (!filter || filter(select)) {
			select.selectedIndex = 0;
		}
	}
}

//------------------------------------------------------------

// javascript emailer
// Gabriel Feindel
// A safe, simple way of emailing that confounds even the brightest email harvester.
// To use in an email link, set href to "#" and onclick to mailto("username") where
// username is the part before the @ sign in the email address. Only works with 
// users on bjupress.com unless domain is specified

function mailto(uname, domain) {
	if (domain == undefined)
		domain = 'bjupress.com';
	window.location.href = "mailto:" + uname + "@" + domain;
}

//------------------------------------------------------------
/**
 * Propagates the popup=1 parameter to all links on the page (or in the indicated element id).
 */
function propagatePopup(localhost, id) {
	var links = (id ? document.getElementById(id) : document.body).getElementsByTagName('a');
	var re = /^([^?#]*)(\?[^#]*)?(#.*)?$/;
	for (var i = 0; i < links.length; i++) {
		var link = links.item(i);
		if (link.href) {
			if (link.href[0] == '/' || link.href.toLowerCase().indexOf(localhost.toLowerCase()) != -1) {
				var m = re.exec(link.href);
				if (m) {
					if (!m[2]) {
						m[2] = "?popup=1";
					} else if (m[2].indexOf('popup=') == -1) {
						m[2] += "&popup=1";
					} else {
						continue;
					}
					link.href = (m[1] ? m[1] : '') + (m[2] ? m[2] : '') + (m[3] ? m[3] : '');
				}
			} else {
				if (!link.target) {
					link.target = "_blank"; // Open external links in a new window.
				}
			}
		}
	}
}
