//General Javascript Functions

function Trim(stringToTrim) { return stringToTrim.replace(/^\s+|\s+$/g,""); } 

function pause(millisecondi){    
	var now = new Date();    
	var exitTime = now.getTime() + millisecondi;     
	
	while(true) {
		now = new Date();        
		if(now.getTime() > exitTime) 
			return;    
	}
}

function NumericOnly(oField) {
	!/^[0-9]*$/.test(oField.value)?oField.value = oField.value.replace(/[^0-9]/g,''):null;
}

function IsNumeric(strString)
   //  check for valid numeric strings
{
   var strValidChars = "0123456789";
   var strChar;
   var blnResult = true;

   if (strString.length == 0) return false;

   //  test strString consists of valid characters listed above
   for (i = 0; i < strString.length && blnResult == true; i++)
      {
      strChar = strString.charAt(i);
      if (strValidChars.indexOf(strChar) == -1)
         {
         blnResult = false;
         }
      }
   return blnResult;
}

function ValidateNumeric(e,sExclude) {
  if (e.keyCode) 
  		keycode=e.keyCode;
  else keycode=e.which;
  		character=String.fromCharCode(keycode);
  if (character == sExclude) 
  		e.returnValue = false;
  if (!IsNumeric(character)) 
  		e.returnValue = false;
}


/// Count characters in text field function
function textCounter(oField, maxlimit ) {
	
	var FieldName = oField.name;
	var oCounterField = document.getElementById(FieldName + "_counter");

	var CurrLen = oField.value.length;

	if ( CurrLen > maxlimit )
	{
		oField.value = oField.value.substring(0,eval(maxlimit));
		alert(FieldName + ' value can only be ' + maxlimit + ' characters in length.' );
		oCounterField.innerHTML = oField.value.length;
		return false;
	} else {
		oCounterField.innerHTML = oField.value.length;
	}
}

///Generic Function to Show/Hide "Other" text field when drop down has "Other" option 
///*** Other option value must be "Other" for this to work, as well as use of <span id="Other<field>" style="display: 'none'"> tags, 
///where <field> is a numerical value for which <span> to hide/show
function ShowHideOther(field,fieldvalue) {	
	currValue = fieldvalue.value;
	currChecked = fieldvalue.checked;
	if (currValue == "Other") {	
		if(currChecked) {
			currOther = document.getElementById("Other" + String(field));
			currOther.style.display="";
		} else {
			currOther = document.getElementById("Other" + String(field));
			currOther.style.display="none";			
		}
   } else {
		currOther = document.getElementById("Other" + String(field));
		currOther.style.display="none";
	}
}

///Function: FormatPhone
///Purpose: Format phone numbers as xxx-xxx-xxxx, also validates for all numeric values
///Input: Phone field to check, passed as '<formname>.<fieldname>' 
///Output: Formatted phone number back to same field value 
///Prerequisites: None 
///Conditions: None 
///Added by: Marc Giguere 
///Date Added: 6-16-2004
///Notes: RegEx credit to Steven Smith (found at regexlib.com) 
function FormatPhone(sPhone){
	thisField = sPhone.name;
	var re= /\D/;
	// test for this format: (xxx)xxx-xxxx
	//var re2 = /^\({1}\d{3}\)\d{3}-\d{4}/; 
	// test for this format: xxx-xxx-xxxx
	var re2 = /^[2-9]\d{2}-\d{3}-\d{4}$/;
	
	var num = sPhone.value;
	
	var newNum;

	if (num == "") {
		return true
	} else {

		if (re2.test(num)!=true){
		   if (num != ""){
			 while (re.test(num)){
					num = num.replace(re,"");
			 }
		   }
			
			if (num.length != 10){
				alert('Please enter a 10 digit phone number');
				setTimeout("document.getElementById(thisField).select()", 5);
				return false;
			 } else {
				// for format (xxx)xxx-xxxx
				//newNum = '(' + num.substring(0,3) + ')' + num.substring(3,6) + '-' + num.substring(6,10);
				// for format xxx-xxx-xxxx
				newNum = num.substring(0,3) + '-' + num.substring(3,6) + '-' + num.substring(6,10);
				sPhone.value=newNum;
				return true;
			 }
		}
	}

}

///Function: Generic Form Validation
///Purpose: This script can validate any form
///Input: Form to be checked, passed as "document.<formname>"
///Output: True/False for submittal of form
///Prerequisites: Hidden form field with name "required" that has comma separated list of fields to be checked
///Conditions: Only checks that one checkbox is checked, only one radio button is selected, and that text areas are not blank.
///Added by: Marc Giguere 
///Date Added: 6-16-2004
///Date Update: 9-15-2005
///Change Log: 09/15/05 - MG - Added ability to do text areas, passwords, and file fields...
function validateForm(what,coloroverride) {
	var tmpValue = -1;
	var valid = true;
	var fieldtofix = "";
	var highlight = "";
	var friendlyname = "";
	//Make sure that we got a value for doing the color override...
	if(coloroverride != '') {
		var colorchangecheck = coloroverride;
	} else {
		var colorchangecheck = 0;	
	}
	
	var checkBoxes = false;
	var checkboxChecked = false;
	
	var radioButtons = false;
	var radioChecked = false;
	
	//If no required fields, allow to return valid!
	if (document.getElementById('Required').value == '') {
		return valid;
	}
		
	var reqfields=document.getElementById('Required').value.split(',');	
		
	MainLoop:
	for(i=0;i<reqfields.length;i++) {
	
		/// Check if this is new format where we pass in field name and "friendly name"
		reqcheck = reqfields[i].indexOf("|");
		if (reqcheck > 0) {
			tmpvar = reqfields[i].split('|');
			reqfields[i] = Trim(tmpvar[0]);
			friendlyname = tmpvar[1];
		} else {
			friendlyname = reqfields[i];
		}	
		
		//Get Type of field
		myType = eval("what." + reqfields[i] + ".type");
		
		//Check individual field length for fields with same name (ie: radio and checkboxes) 
		myLen = eval("what." + reqfields[i] + ".length");	
		
		//This field has more than one name valued that is the same, but ignore this check for select boxes
		if(myLen > 0 && (myType != 'select-one' && myType != 'select-multiple')) {
		
			SecondLoop:
				for(var j = 0; j < myLen; j++) {
				
				if(radioChecked == true) {
					break;
				}
				
				if(checkboxChecked == true) {
					break;
				}
				
				myType = eval("what." + reqfields[i] + "[" + j + "].type");
				
				//Only check for radio/checkboxes as other fields shouldn't ever share same name
				if (myType == 'radio') {
					radioButtons = true;
					if (eval("what." + reqfields[i] + "[" + j + "].checked")) 
						radioChecked = true;	
				}
				
				if (myType == 'checkbox') {
					checkBoxes = true;					
					if (eval("what." + reqfields[i] + "[" + j + "].checked")) 
						checkboxChecked = true;	
				}			  
			
			}//End SecondLoop For
			
			// Done w/loop, check if we have to alert
			//alert(reqfields[i]);
			if ((myType == 'radio' && radioChecked == false) || (myType == 'checkbox' && checkboxChecked == false)) {
				if (fieldtofix == '')
					fieldtofix = reqfields[i];
					highlight = 0;
					valid = false;
			}
		
		//Single Named fields checks, only if we still are ok and didn't find a multi-checkbox/radio problem
		} else if (valid) {
		
		
			if (myType == 'radio') {			  		
				radioButtons = true;
				if (eval("what." + reqfields[i] + ".checked")) {
					radioChecked = true;
				} else {
					valid = false;
					if (fieldtofix == '') {
						fieldtofix = reqfields[i];
						highlight = 0;
					}
				}
			}
			
			if (myType == 'checkbox') {
				checkBoxes = true;
				if (eval("what." + reqfields[i] + ".checked")) {
					checkboxChecked = true; 
				} else {
					valid = false;
					if (fieldtofix == '') {
						fieldtofix = reqfields[i];
						highlight = 0;
					}
				}
			}
			
			if (myType == 'text') {
				tmpValue = eval("what." + reqfields[i] + ".value");
				if (colorchangecheck) {
					eval("what." + reqfields[i] + ".style.backgroundColor = '#FFFFFF'");
					eval("what." + reqfields[i] + ".style.color = '#000000'");
				}
				if (tmpValue == '') {
					valid = false;
					if (fieldtofix == '') {
						fieldtofix = reqfields[i]; 
						highlight = 1;
					}
				}
			}
			
			if (myType == 'textarea') {
				tmpValue = eval("what." + reqfields[i] + ".value");
				if (colorchangecheck) {
					eval("what." + reqfields[i] + ".style.backgroundColor = '#FFFFFF'");
					eval("what." + reqfields[i] + ".style.color = '#000000'");
				}
				if (tmpValue == '') {
					valid = false;
					if (fieldtofix == '') {
						fieldtofix = reqfields[i]; 
						highlight = 1;
					}
				}
			}
			
			if (myType == 'password') {
				tmpValue = eval("what." + reqfields[i] + ".value");
				if (colorchangecheck) {
					eval("what." + reqfields[i] + ".style.backgroundColor = '#FFFFFF'");
					eval("what." + reqfields[i] + ".style.color = '#000000'");
				}
				if (tmpValue == '') {
					valid = false;
					if (fieldtofix == '') {
						fieldtofix = reqfields[i]; 
						highlight = 1;
					}
				}
			}
			
			if (myType == 'file') {
				tmpValue = eval("what." + reqfields[i] + ".value");
				if (colorchangecheck) {
					eval("what." + reqfields[i] + ".style.backgroundColor = '#FFFFFF'");
					eval("what." + reqfields[i] + ".style.color = '#000000'");
				}
				if (tmpValue == '') {
					valid = false;
					if (fieldtofix == '') {
						fieldtofix = reqfields[i]; 
						highlight = 1;
					}
				}
			}
			
			if (myType == 'select-one' || myType == 'select-multiple') {
				tmpValue = eval("what." + reqfields[i] + ".selectedIndex");
				if (colorchangecheck) {
					eval("what." + reqfields[i] + ".style.backgroundColor = '#FFFFFF'");
					eval("what." + reqfields[i] + ".style.color = '#000000'");
				}
				if (tmpValue == '' || tmpValue == '-1') {
					valid = false;
					if (fieldtofix == '') {
						fieldtofix = reqfields[i]; 
						highlight = 1;
					}
				}
			}
		}
		
		if (!valid) {
			break;
		}
	 
	}// End main loop?
	
	if ((checkBoxes && !checkboxChecked)) valid = false;
	
	if ((radioButtons && !radioChecked)) valid = false;
	
	if (!valid)	{	
		if (highlight) {
			eval("what." + fieldtofix + ".style.backgroundColor = '#FF0000'");
			eval("what." + fieldtofix + ".style.color = '#FFFFFF'");
			eval("what." + fieldtofix + ".focus()");
			alert('You have not completely filled out the form.\n\nPlease verify that all required fields are filled\nand/or at least one option is selected.\n\nPlease correct the ' + friendlyname + ' field, which is highlighted.');		  		  
		} else {
			//alert(fieldtofix);
			alert('You have not completely filled out the form.\n\nPlease verify that all required fields are filled\nand/or at least one option is selected.\n\nPlease correct the ' + friendlyname + ' field.');
		}
	}
	
	return valid;
}


///Function: Basic Email Validation
///Purpose: This script can validate any email field to ensure a properly formatted email is provided 
///Input: Email field to be checked, pass in as string
///Output: True/False for submittal of form
///Added by: Marc Giguere/Thomas Kumpik 
///Date Added: 7-20-2004 
///Change Log:
///	MG - 11/17/05 - Changed RegEx lib to more robust version

//Passes in object instead of direct string...
function IsEmailValid(sEmail)
{

	// Use Regular Expressions for Email Verification
	// Credit Reg-Ex Check: Gavin Sharp (http://www.glensharp.com/gavin/)
	REEmail = /^(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+@((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,6}$/
	
	thisField = sEmail.name;
	
	//Check if blank, if so, ignore for now
	if (sEmail.value != '') {
		if (!sEmail.value.match(REEmail)) {
			alert("Please enter a valid email address.");	
			document.getElementById(thisField).select();
			document.getElementById(thisField).value = '';			
		}
	}
	
}

///Function: Check two fields are identical
///Purpose: This script can validate any two fields values as being the same
///Input: Original Field and Secondary Field
///Output: True/False, if false returns focus to secondary item
///Added by: Marc Giguere
///Date Added: 11-23-2006 
///Change Log:

//Passes in object instead of direct string...
function VerifyFields(oField1,oField2)
{

	// Use Regular Expressions for Email Verification
	// Credit Reg-Ex Check: Gavin Sharp (http://www.glensharp.com/gavin/)
	
	thisField = oField2.name;
	
	//Check if blank, if so, ignore for now
	if (oField1.value == '') {
		return true;
	} else {
		if (oField1.value.toUpperCase() != oField2.value.toUpperCase()) {
			alert("Please be sure to enter the same value.");		
			oField2.value = '';
			setTimeout("document.getElementById(thisField).select()", 5);			
			return false;
		} else {
			return true;
		}
	}
}

///Function: Password Validater/Checker
///Purpose: This script can validate a password field for length/complexity
///Input: Original Field and Type Check (0 - Basic, 1 - Complex)
///Output: True/False, if false returns focus to password field
///Added by: Marc Giguere
///Date Added: 11-27-2006 
///Change Log:

function CheckPass(oPass,iType) {

	//Regular expression, must be 4-20 chars
	ComplexREPass = /(?=^.{4,20}$)((?=.*\d)(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[^A-Za-z0-9])(?=.*[a-z])|(?=.*[^A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[A-Z])(?=.*[^A-Za-z0-9]))^.*/
	BasicREPass = /^.{4,20}$/
	
	if (iType == 0) {
		REPass = BasicREPass;
	} else {
		REPass = ComplexREPass;	
	}
	
	thisField = oPass.name;
	
	//Check if blank, if so, ignore for now
	if (oPass.value == '') {
		return true;
	} else {
		if (!oPass.value.match(REPass)) {
			alert("Please enter a valid password.");
			oPass.value = '';
			setTimeout("document.getElementById(thisField).select()", 5);
			return false;
		} else {
			return true;
		}
	}
	
}

//Hide/Show States Function
function NonUSStateDefault(oField) {

	if (oField.value == 164) {
		
		document.getElementById('State').value = -1;
		
	} else {
		
		document.getElementById('State').value = 1;
		
	}
	
}

//Date Range Checks
function doDateCheck(from, to) {

	if (Date.parse(from.value) <= Date.parse(to.value)) {
		alert("The dates are valid.");
	} else {
		if (from.value == "" || to.value == "") 
			alert("Both dates must be entered.");
		else 
			alert("To date must occur after the from date.");
	   }
	   
}

// Date valid check
// Credit http://www.expertsrt.com/scripts/Rod/validate_date.php
function isValidDate(oDate) {	
	if (oDate.value.length > 0) {
	    var RegExPattern = /^(?=\d)(?:(?:(?:(?:(?:0?[13578]|1[02])(\/|-|\.)31)\1|(?:(?:0?[1,3-9]|1[0-2])(\/|-|\.)(?:29|30)\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})|(?:0?2(\/|-|\.)29\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))|(?:(?:0?[1-9])|(?:1[0-2]))(\/|-|\.)(?:0?[1-9]|1\d|2[0-8])\4(?:(?:1[6-9]|[2-9]\d)?\d{2}))($|\ (?=\d)))?(((0?[1-9]|1[012])(:[0-5]\d){0,2}(\ [AP]M))|([01]\d|2[0-3])(:[0-5]\d){1,2})?$/;
    	var errorMessage = 'Please enter valid date as month, day, and four digit year.\nYou may use a slash, hyphen or period to separate the values.';	
	    if (oDate.value.match(RegExPattern)) {
	       return true;
    	} else {
        	alert(errorMessage);
			oDate.value = '';
			thisField = oDate.name;
			setTimeout("document.getElementById(thisField).select()", 5);
			return false;        
	    } 
	} else {
		return true;
	}
}

function Trim(STRING){
	
	STRING = LTrim(STRING);
	return RTrim(STRING);
	
}

function RTrim(STRING){

	while(STRING.charAt((STRING.length -1))==" "){
		STRING = STRING.substring(0,STRING.length-1);
	}
	return STRING;
}


function LTrim(STRING){
	
	while(STRING.charAt(0)==" "){
		STRING = STRING.replace(STRING.charAt(0),"");
	}
	return STRING;
	
}


function SurveyWindow(mypage, myname, w, h, scroll) {
	var winl = (screen.width - w) / 2;
	var wint = (screen.height - h) / 2;
	winprops = 'height='+h+',width='+w+',top='+wint+',left='+winl+',scrollbars='+scroll+',resizable'
	win = window.open(mypage, myname, winprops)
	if (parseInt(navigator.appVersion) >= 4) { win.window.focus(); }
}

function Redirect(path) {
	alert(path);
	location.href=path;

}
/*---------------------------------------------------------------------------
 
  IsValidNumber - Check form element value to see if it is a valid number
 
-----------------------------------------------------------------------------*/
function IsValidNumber(formelement) {
	
	// Get the amount from the form element as dollar string
	var numberstring = formelement.value;
	
	// Check to see if the value is a number, if not, show error message, and clear form element
	if(isNaN(numberstring)) {
		alert("Please enter a valid number");
		formelement.value = "";
		formelement.focus();
	}
}
/*---------------------------------------------------------------------------
 
  IsValidDollarAmount - Check dollar amount form elements to ensure correct
 
-----------------------------------------------------------------------------*/
function IsValidDollarAmount(formelement) {
	
	// Get the amount from the form element as dollar string
	var dollarstring = formelement.value;
	
	// Take $ and , out of the dollar string
	dollarstring = dollarstring.toString().replace(/\$|\,/g,'');
	
	// Check to see if the value is a number, if not, show error message, and clear form element
	if(isNaN(dollarstring)) {
		alert("Please enter a valid dollar amount");
		formelement.value = "";
		formelement.focus();
	}
}
/*---------------------------------------------------------------------------
 
  IsZipCodeValid - Check form Zip Code to ensure it is correct
 
-----------------------------------------------------------------------------*/
function IsZipCodeValid(formelement) {

      var strValidChars = "0123456789";
      var strChar;
      var zipCodeLength = formelement.value.length;
      var blnResult = true;

      if ( zipCodeLength != 0 ) {
         for (i=0;i<zipCodeLength && blnResult == true; i++) {
            strChar = formelement.value.charAt(i);
            if (strValidChars.indexOf(strChar) == -1) {
               blnResult = false;
            }
         }
         if (blnResult != true) {
            alert("Please enter a valid Zip Code.");
            formelement.value = "";
            formelement.focus();
         }
      }
}
/*---------------------------------------------------------------------------
 
  IsEmailValid - validate and check Email type form elements
 
-----------------------------------------------------------------------------*/
function IsEmailValid(formelement) {

    // Credit Reg-Ex Check: Gavin Sharp (http://www.glensharp.com/gavin/)
	REEmail = /^(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+@((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,6}$/

    if (formelement.value != "") {
       if (!formelement.value.match(REEmail)) {
          alert("Please enter a valid Email Address.")
          formelement.value = "";
          formelement.focus();
       }
    }
}

function parseDec(val,places,sep) {

	// This function takes two arguments:
	//   (string || number)  val
	//            (integer)  places
	//             (string)  sep
	// val is the numeric string or number to parse
	// places represents the number of decimal
	// places to return at the end of the parse.
	// sep is an optional string to be used to separate
	// the whole units from the decimal units (default: '.')

	val = '' + val;
		// Implicitly cast val to (string)
	
	if (!sep) {
		sep = '.';
		// If separator isn't specified, then use a decimal point '.'
	}
	
	if (!places) { places = 0; }
	places = parseInt(places);
		// Make sure places is an integer
	
	if (!parseInt(val)) {
		// If val is null, zero, NaN, or not specified, then
		// assume val to be zero.  Add 'places' number of zeros after
		// the separator 'sep', and then return the value.  We're done here.
		val = '0';
		if (places > 0) {
			val += sep;
			while (val.substring((val.indexOf(sep))).length <= places) {
				val += '0';
			}
		}
		return val;
	}
	
	if ((val.indexOf('.') > -1) && (sep != '.')) {
		val = val.substring(0,val.indexOf('.')) + sep + val.substring(val.indexOf('.')+1);
			// If we're using a separator other than '.' then convert now.
	}
		
	if (val.indexOf(sep) > -1) {
		// If our val has a separator, then cut our value
		// into pre and post 'decimal' based upon the separator.
		pre = val.substring(0,val.indexOf(sep));
		post = val.substring(val.indexOf(sep)+1);
	} else {
		// Otherwise pre gets everything and post gets nothing.
		pre = val;
		post = '';
	}
	
	if (places > 0) {
		// If we're dealing with a decimal then...
		
		post = post.substring(0,(places+1));
			// We care most about the digit after 'places'
		
		if (post.length > places) {
			// If we have trailing decimal places then...
			
			//alert (parseInt(post.substring(post.length - 1)));

			if ( parseInt(post.substring(post.length - 1)) > 4 ) {
				post = '' + Math.round(parseInt(post) / 10);
				//post = '' + post.substring(0,post.length - 2) + (1/Math.pow(10,places));
				//post = ('' + post.substring(0,post.length - 2)) + (parseInt(post.substring(post.length - 1)) + 1);
			} else {
				post = '' + Math.round(parseInt(post));
			}
		}
		
		if (post.length > places) {
			post = '' + Math.round(parseInt(post.substring(0,places)));
		} else if (post.length < places) {
			while (post.length < places) {
				post += '0';
			}
		}
	
	} else {

		if (parseInt((post.substring(0,1))) > 4) {
			pre = '' + (parseInt(pre) + 1);
		} else {
			pre = '' + (parseInt(pre));	
		}
		post = '';
	}
	
	sep = (post.length > 0) ? sep : '';
		// Should we use a separator?

	val = pre + sep + post;
		// Rebuild val

	return val;
}

function parseMoney(val,sep) {

	// Specialized version of parseDec useful for
	// parsing money-related data.  Arguments:
	//   (string || number)  val
	//             (string)  sep
	// val is the monetary value to be parsed,
	// sep is an optional decimal separator (default: '.')
	
	return parseDec(val,2,sep);
}

function sepToDec(val,sep) {

	val = '' + val;

	if ((val.indexOf(sep) > -1) && (sep != '.')) {
		val = val.substring(0,val.indexOf(sep)) + '.' + val.substring(val.indexOf(sep)+1);
	}
	
	return val;
}

function decToSep(val,sep) {

	val = '' + val;
	sep = '' + sep;

	if ((val.indexOf('.') > -1) && (sep.length > 0)) {
		val = val.substring(0,val.indexOf('.')) + sep + val.substring(val.indexOf('.')+1);
	}

	return val;
}

/*

This routine checks the credit card number. The following checks are made:

1. A number has been provided
2. The number is a right length for the card
3. The number has an appropriate prefix for the card
4. The number has a valid modulus 10 number check digit if required

If the validation fails an error is reported.

The structure of credit card formats was gleaned from a variety of sources on 
the web.

Parameters:
            cardnumber           number on the card
            cardname             name of card as defined in the card list below

Author:     John Gardner
Date:       1st November 2003
Updated:    26th Feb. 2005      Additional cards added by request

*/

/*
   If a credit card number is invalid, an error reason is loaded into the 
   global ccErrorNo variable. This can be be used to index into the global error  
   string array to report the reason to the user if required:
   
   e.g. if (!checkCreditCard (number, name) alert (ccErrors(ccErrorNo);
*/

var ccErrorNo = 0;
var ccErrors = new Array ()

ccErrors [0] = "Unknown card type";
ccErrors [1] = "No card number provided";
ccErrors [2] = "Credit card number is in invalid format";
ccErrors [3] = "Credit card number is invalid or does not match card type selected.";
ccErrors [4] = "Credit card number has an inappropriate number of digits";

function checkCreditCard (cardnumber, cardname) {

     
  // Array to hold the permitted card characteristics
  var cards = new Array();

  // Define the cards we support. You may add addtional card types.
  
  //  Name:      As in the selection box of the form - must be same as user's
  //  Length:    List of possible valid lengths of the card number for the card
  //  prefixes:  List of possible prefixes for the card
  //  checkdigit Boolean to say whether there is a check digit
  
  cards [0] = {name: "Visa", 
               length: "13,16", 
               prefixes: "4",
               checkdigit: true};
  cards [1] = {name: "MasterCard", 
               length: "16", 
               prefixes: "51,52,53,54,55",
               checkdigit: true};
  cards [2] = {name: "DinersClub", 
               length: "14,", 
               prefixes: "300,301,302,303,304,305,36,38",
               checkdigit: true};
  cards [3] = {name: "CarteBlanche", 
               length: "14", 
               prefixes: "300,301,302,303,304,305,36,38",
               checkdigit: true};
  cards [4] = {name: "AmEx", 
               length: "15", 
               prefixes: "34,37",
               checkdigit: true};
  cards [5] = {name: "Discover", 
               length: "16", 
               prefixes: "6011",
               checkdigit: true};
  cards [6] = {name: "JCB", 
               length: "15,16", 
               prefixes: "3,1800,2131",
               checkdigit: true};
  cards [7] = {name: "Enroute", 
               length: "15", 
               prefixes: "2014,2149",
               checkdigit: true};
               
  // Establish card type
  var cardType = -1;
  for (var i=0; i<cards.length; i++) {

    // See if it is this card (ignoring the case of the string)
    if (cardname.toLowerCase () == cards[i].name.toLowerCase()) {
      cardType = i;
      break;
    }
  }
  
  // If card type not found, report an error
  if (cardType == -1) {
     ccErrorNo = 0;
     return ccErrors[ccErrorNo]; 
  }
   
  // Ensure that the user has provided a credit card number
  if (cardnumber.length == 0)  {
     ccErrorNo = 1;
     return ccErrors[ccErrorNo]; 
  }
  
  // Check that the number is numeric, although we do permit a space to occur  
  // every four digits. 
  var cardNo = cardnumber
  var cardexp = /^([0-9]{4})\s?([0-9]{4})\s?([0-9]{4})\s?([0-9]{1,4})$/;
  if (!cardexp.exec(cardNo))  {
     ccErrorNo = 2;
     return ccErrors[ccErrorNo]; 
  }
    
  // Now remove any spaces from the credit card number
  cardexp.exec(cardNo);
  cardNo = RegExp.$1 + RegExp.$2 + RegExp.$3 + RegExp.$4;
       
  // Now check the modulus 10 check digit - if required
  if (cards[cardType].checkdigit) {
    var checksum = 0;                                  // running checksum total
    var mychar = "";                                   // next char to process
    var j = 1;                                         // takes value of 1 or 2
  
    // Process each digit one by one starting at the right
    var calc;
    for (i = cardNo.length - 1; i >= 0; i--) {
    
      // Extract the next digit and multiply by 1 or 2 on alternative digits.
      calc = Number(cardNo.charAt(i)) * j;
    
      // If the result is in two digits add 1 to the checksum total
      if (calc > 9) {
        checksum = checksum + 1;
        calc = calc - 10;
      }
    
      // Add the units element to the checksum total
      checksum = checksum + calc;
    
      // Switch the value of j
      if (j ==1) {j = 2} else {j = 1};
    } 
  
    // All done - if checksum is divisible by 10, it is a valid modulus 10.
    // If not, report an error.
    if (checksum % 10 != 0)  {
     ccErrorNo = 3;
     return ccErrors[ccErrorNo]; 
    }
  }  

  // The following are the card-specific checks we undertake.
  var LengthValid = false;
  var PrefixValid = false; 
  var undefined; 

  // We use these for holding the valid lengths and prefixes of a card type
  var prefix = new Array ();
  var lengths = new Array ();
    
  // Load an array with the valid prefixes for this card
  prefix = cards[cardType].prefixes.split(",");
      
  // Now see if any of them match what we have in the card number
  for (i=0; i<prefix.length; i++) {
    var exp = new RegExp ("^" + prefix[i]);
    if (exp.test (cardNo)) PrefixValid = true;
  }
   
  // If it isn't a valid prefix there's no point at looking at the length
  if (!PrefixValid) {
     ccErrorNo = 3;
     return ccErrors[ccErrorNo]; 
  }
    
  // See if the length is valid for this card
  lengths = cards[cardType].length.split(",");
  for (j=0; j<lengths.length; j++) {
    if (cardNo.length == lengths[j]) LengthValid = true;
  }
  
  // See if all is OK by seeing if the length was valid. We only check the 
  // length if all else was hunky dory.
  if (!LengthValid) {
     ccErrorNo = 4;
     return ccErrors[ccErrorNo]; 
  };   
  
  // The credit card is in the required format.
  return 0;
}

/*============================================================================*/

// This code was written by Tyler Akins and has been placed in the
// public domain.  It would be nice if you left this header intact.
// Base64 code from Tyler Akins -- http://rumkin.com

var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

function VerifyCaptcha(input) {
   var output = "";
   var chr1, chr2, chr3;
   var enc1, enc2, enc3, enc4;
   var i = 0;

   do {
      chr1 = input.charCodeAt(i++);
      chr2 = input.charCodeAt(i++);
      chr3 = input.charCodeAt(i++);

      enc1 = chr1 >> 2;
      enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
      enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
      enc4 = chr3 & 63;

      if (isNaN(chr2)) {
         enc3 = enc4 = 64;
      } else if (isNaN(chr3)) {
         enc4 = 64;
      }

      output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + 
         keyStr.charAt(enc3) + keyStr.charAt(enc4);
   } while (i < input.length);
   
   return output;
}

