//please do not make changes to this file!  
//if you need to modify it, please make a copy, since this script is used by multiple sites.

/*** DEFAULT ERROR MESSAGES ***/
var DefaultBlankError = 'Please enter a value.';
var DefaultIntegerError = 'Please enter an integer value.';
var DefaultNumericError = 'Please enter a numeric value.';
var DefaultAlphaNumericError = 'Please enter an alpha-numeric value.';
var DefaultEmailError = 'Please enter a valid e-mail address.';
var CCStep1Message = " - Credit card is not known or is invalid.\n";
var CCStep2Message = " - Credit card number is invalid.\n";
var CCStep3Message = " - Credit card is not known.\n";

/*** DEFAULT CURRENCY FORMATTING VARIABLES ***/
var DecimalPointSymbol = '.';
var CommaSeparatorSymbol = ',';
var NumbersBetweenCommas = 3; // Number of digits between each comma
var FormatDecimalPlaces = 2; // Number of decimal places to display

/*** COMMON GLOBAL VARIABLES ***/
var ProvinceList = new Array('AB','BC','MB','NB','NL','NT','NS','NU','ON','PE','QC','SK','YT','PR');
var CurrencyPrefix = '';
var CurrencySuffix = '';

/*** CC VALIDATION VARIABLES ***/
var ccType = '';
var ccNumberOkay = 0;
var ccNumberChecked = '';

/*** COMMON FUNCTIONS ***/

// Makes sure all dynamically-displayed content is displaying properly after the user enters the page using the back button
function checkDynamicContent() {
   for (var i=0;i<document.forms.length;i++) {
      with (document.forms[i]) {
         for (var j=0;j<length;j++) {
            if ((typeof elements[j].type == 'string') && ((elements[j].type == 'checkbox') || (elements[j].type == 'radio')) && (elements[j].checked != elements[j].defaultChecked)) {
               elements[j].checked = !elements[j].checked;
               elements[j].click();
            }
         }
      }
   }
}

// Only allows numeric characters to be input (and use of navigation keys)
function catchKeyStroke(e) {
   var KeyCode = (e.keyCode) ? e.keyCode : e.which;
   return ((KeyCode == 8) // backspace
        || (KeyCode == 9) // tab
        || (KeyCode == 13) // enter
        || (KeyCode == 37) // left arrow
        || (KeyCode == 39) // right arrow
        || ((KeyCode >= 46) && (KeyCode <= 57))); // 46 is delete, 47-57 is 0-9
}

// Returns true if the function exists
function functionExists(FunctionName) {
   return (eval('typeof ' + FunctionName) == 'function');
}

// Dynamically calls the function, if it exists
function dynamicFunctionCall(FunctionName) {
   if (functionExists(FunctionName)) {
      var FunctionCall = FunctionName + '(';
      for (var j=1;j<arguments.length;j++) {
         if (j > 1) FunctionCall += ',';
         FunctionCall += 'arguments[' + j + ']';
      }
      eval(FunctionCall + ')');
      return true;
   }
   else return false;
}

// Returns the supplied string with leading/trailing spaces removed 
function trimWhiteSpace(paddedString) { 
   return paddedString.substring(paddedString.search(/\S+/), paddedString.search(/\s*$/)); 
}

// Returns the supplied string with non-integer characters stripped out
function stripNonInteger(mixedString) {
   return mixedString.replace(/\D/g, '');
}

// Returns true if the specified value exists in the array
function existsInArray(SomeArray, MatchValue) {
   var ReturnStatus = false;
   for (var p=0;p<SomeArray.length;p++) {
      if (SomeArray[p] == MatchValue) {
         ReturnStatus = true;
         break;
      }
   }
   return ReturnStatus;
}

// Returns the value from the select option that will be submitted
function getOptionValue(OptionElement) {
   var OptionValue = OptionElement.value;
   return ((OptionValue == '') && (navigator.appName == 'Microsoft Internet Explorer') && (!/\s+value\s*=/i.test(OptionElement.outerHTML))) ? OptionElement.text : OptionValue;
}

// Returns the number formatted with commas and 2 decimal places
function numberFormat(MoneyAmount, DecimalPlaces, DecimalCharacter, DigitsBetweenCommas, CommaSeparator) {
   if (isNumeric(MoneyAmount)) {
      // Check parameters, use defaults when necessary
      // Checking the undefined property doesn't work on Mac IE, need to check arguments.length instead!
      if (arguments.length < 2) var DecimalPlaces = FormatDecimalPlaces;
      if (arguments.length < 3) var DecimalCharacter = DecimalPointSymbol;
      if (arguments.length < 4) var DigitsBetweenCommas = NumbersBetweenCommas;
      if (arguments.length < 5) var CommaSeparator = CommaSeparatorSymbol;
      // Start logic
      if ((DecimalPlaces <= 0) || (DecimalCharacter == '')) {
         var MoneyString = Math.round(MoneyAmount).toString();
         var DecimalString = '';
      }
      else {
         var MoneyString = MoneyAmount.toString();
         var DecimalIndex = MoneyString.lastIndexOf('.');
         // Need to round off extra decimal points
         if ((MoneyString.length - DecimalIndex) > (DecimalPlaces + 1)) {
            var Rounder = Math.pow(10, DecimalPlaces);
            MoneyAmount = Math.round(MoneyAmount * Rounder) / Rounder;
            MoneyString = MoneyAmount.toString();
         }
         // Re-check the decimal point position, in case the number was rounded
         DecimalIndex = MoneyString.lastIndexOf('.');
         if ((DecimalIndex == -1) || ((MoneyString.length - DecimalIndex) <= DecimalPlaces)) {
            if (DecimalIndex == -1) MoneyString += '.';
            else DecimalPlaces = DecimalPlaces - (MoneyString.length - DecimalIndex - 1);
            for (var j=1;j<=DecimalPlaces;j++) MoneyString += '0';
         }
         var DecimalString = MoneyString.replace(/^(\d+)\.(\d+)$/, DecimalCharacter + '$2');
         MoneyString = RegExp.$1;
      }
      // Separate the thousands with a comma
      if ((DigitsBetweenCommas > 0) && (CommaSeparator != '') && (Math.abs(MoneyAmount) >= Math.pow(10, DigitsBetweenCommas))) { // Added check for amount >= 1000 to fix issue on Mac IE
         var ThousandRE = new RegExp('(\\d{' + DigitsBetweenCommas + '})', 'g');
         var MoneyArray = MoneyString.split('').reverse().join('').replace(ThousandRE, '$1' + CommaSeparator).split('');
         if (MoneyArray[MoneyArray.length-1] == CommaSeparator) MoneyArray.pop();
         MoneyString = MoneyArray.reverse().join('');
      }
      return MoneyString + DecimalString;
   }
   else return MoneyAmount;
}

// Strips off currency formatting, including comma separators
function stripCurrency(FormattedPriceWithCurrency) {
   var MainNumberExpression = ((NumbersBetweenCommas > 0) && (CommaSeparatorSymbol != '')) ? '\\d{1,' + NumbersBetweenCommas + '}(\\' + CommaSeparatorSymbol + '?\\d{' + NumbersBetweenCommas + '})*' : '\\d+';
   var DecimalExpression = (DecimalPointSymbol != '') ? '\\' + DecimalPointSymbol + '?\\d*' : '';
   var CurrencyRE = new RegExp('^(\\D*)(' + MainNumberExpression + DecimalExpression + ')(\\D*)$');
   var PriceChunk = CurrencyRE.exec(FormattedPriceWithCurrency); // Finds the matches, and puts them into an array
   if (PriceChunk == null) return 0; // If the input price doesn't match, return 0
   else {
      CurrencyPrefix = PriceChunk[1];
      CurrencySuffix = PriceChunk[PriceChunk.length-1]; // Must be dynamic, because a match may be missing if no comma-separator is supplied
      if (CommaSeparatorSymbol != '') {
         var CommaRE = new RegExp('\\' + CommaSeparatorSymbol, 'g');
         PriceChunk[2] = PriceChunk[2].replace(CommaRE, ''); // Strips out the commas
      }
      if ((DecimalPointSymbol != '') && (DecimalPointSymbol != '.')) {
         var DecimalRE = new RegExp('\\' + DecimalPointSymbol);
         PriceChunk[2] = PriceChunk[2].replace(DecimalRE, '.'); // Replaces the weird decimal point symbol with a real one
      }
      return parseFloat(PriceChunk[2]);
   }
}


/*** STAND-ALONE VALIDATION FUNCTIONS ***/

// Returns true if the string is blank
function isBlank(SomeString) {
   return (SomeString.toString().length == 0);
}

// Returns true if the value is an integer
function isInteger(SomeValue) {
   return (/^\d+$/.test(SomeValue));
}

// Returns true if the value is numeric
function isNumeric(SomeValue) {
   return ((!isNaN(SomeValue)) && (!isBlank(SomeValue)));
}

// Returns true if the value is alpha-numeric (excludes underscore)
function isAlphaNumeric(SomeValue) {
   return (/^[A-Z0-9]+$/i.test(SomeValue));
}

// Returns true if the value is long enough
function isLongEnough(SomeValue, MinSize) {
   return (SomeValue.length >= MinSize);
}

// Returns true if the value too long
function isTooLong(SomeValue, MaxSize) {
   return (SomeValue.length > MaxSize);
}

// Returns true if the length of the value fits between the min and max
function lengthFits(SomeValue, MinSize, MaxSize) {
   // Have to use the typeof function to check for the existence of the parameter -- Mac IE issue
   return (typeof(MaxSize) == 'undefined') ? isLongEnough(SomeValue, MinSize) : ((SomeValue.length >= MinSize) && (SomeValue.length <= MaxSize));
}
 

// Returns true if the values match (optional case-sensitive flag)
function valuesMatch(ValueOne, ValueTwo, CaseSensitive) {
   // Checking the undefined property doesn't work on Mac IE, need to check arguments.length instead!
   if (arguments.length < 3) var CaseSensitive = false; // Defaults to a case-insensitive match
   if (!CaseSensitive) {
      ValueOne = ValueOne.toUpperCase();
      ValueTwo = ValueTwo.toUpperCase();
   }
   return (ValueOne == ValueTwo);
}

// Returns true if the e-mail is in a  syntactical format
function isValidEmail(EmailString) {
   return (/^[\w-]+(\.[\w-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*\.[a-z]{2,4}$/i.test(EmailString));
}

// Returns true if the string matches the regular expression pattern
function matchPattern(TestString, REPattern, IgnoreCase) {
   // Checking the undefined property doesn't work on Mac IE, need to check arguments.length instead!
   if (arguments.length < 3) var IgnoreCase = true; // Defaults to true when not passed in
   var REFlags = (IgnoreCase) ? 'i' : '';
   var TestRE = new RegExp(REPattern, REFlags);
   return TestRE.test(TestString);
}

// Returns the index of the test string in the select list
// If no parameter passed, returns the index of the 1st selected option in the list
function getOptionIndex(SelectList, TestString) {
   var OptionIndex = -1;
   if (arguments.length < 2) TestString = '';
   for (var m=0;m<SelectList.length;m++) {
      // Checking the undefined property doesn't work on Mac IE, need to check arguments.length instead!
      if (((isBlank(TestString)) && (SelectList[m].selected)) || (getOptionValue(SelectList.options[m]).toUpperCase() == TestString.toUpperCase())) {
         OptionIndex = m;
         break;
      }
   }
   return OptionIndex;
}

// Returns the index of the test string in the radio group
// If no parameter passed, returns the index of the checked radio button
function getRadioIndex(RadioGroup, TestString) {
   var RadioIndex = -1;
   if (arguments.length < 2) TestString = '';
   for (var m=0;m<RadioGroup.length;m++) {
      // Checking the undefined property doesn't work on Mac IE, need to check arguments.length instead!
      if (((isBlank(TestString)) && (RadioGroup[m].checked)) || (RadioGroup[m].value.toUpperCase() == TestString.toUpperCase())) {
         RadioIndex = m;
         break;
      }
   }
   return RadioIndex;
}

// Returns a reference to the form element, searching first by element name, then by p_name/p_val
function getFormElement(SomeForm, ElementName) {
   var TestElement = SomeForm.elements[ElementName];
   if (typeof TestElement == 'undefined') { // Element name doesn't exist, search by p_name/p_val
      for (var j=0;j<SomeForm.length;j++) {
         if ((SomeForm.elements[j].type == 'hidden') && (SomeForm.elements[j].name.toLowerCase() == 'p_name') && (SomeForm.elements[j].value.toUpperCase() == ElementName.toUpperCase()) && (SomeForm.elements[j+1].name.toLowerCase() == 'p_val')) {
            TestElement = SomeForm.elements[j+1];
            if (TestElement.type == 'radio') TestElement = SomeForm.elements[TestElement.name]; // Reset to reference the group by its name, not the individual radio button
            break;
         }
      }
   }
   return TestElement;
}


/*** FORM-SUBMISSION VALIDATION ***/

// General methods

// Returns a reference to the form element, searching first by element name, then by p_name/p_val
function getElementByName(ElementName) {
   return getFormElement(this.form, ElementName);
}

// Loops through the form elements, searching first by element name, then by p_name/p_val, and returns the index of the specified field
function getIndexByName(ElementName) {
   var ElementIndex = -1;
   var TestElement = this.form.elements[ElementName];
   for (var j=0;j<this.form.length;j++) {
      if (typeof TestElement == 'object') { // Named form element exists
         if (this.form.elements[j].name.toUpperCase() == ElementName.toUpperCase()) {
            ElementIndex = j;
            break;
         }
      }
      else { // Named form element name doesn't exist, search by p_name/p_val
         if ((this.form.elements[j].type == 'hidden') && (this.form.elements[j].name.toLowerCase() == 'p_name') && (this.form.elements[j].value.toUpperCase() == ElementName.toUpperCase()) && (this.form.elements[j+1].name.toLowerCase() == 'p_val')) {
            ElementIndex = j + 1;
            break;
         }
      }
   }
   return ElementIndex;
}

// Returns the selected value (for radio or select), or the text-input value
function returnElementValue(ElementName) {
   var ReturnValue = '';
   var TestElement = this.getElement(ElementName);
   if (typeof TestElement == 'object') {
      switch (TestElement.type.substr(0,6)) {
         case 'select' :
            ReturnValue = TestElement.options[TestElement.selectedIndex].value;
            break;
         case 'radio' :
            var RadioIndex = this.getRadioIndex(TestElement);
            if (RadioIndex >= 0) ReturnValue = TestElement[RadioIndex].value;
            break;
         default : // checkbox or text input
            ReturnValue = TestElement.value;
            break;
      }
   }
   return ReturnValue;
}

// Sets the value in text-input field, or selects the item in a radio group or select list
function setElementValue(ElementName, ValueToSet) {
   var ValueWasSet = false;
   var TestElement = this.getElement(ElementName);
   if (typeof TestElement == 'object') {
      if (typeof TestElement.length == 'number') { // radio group
         if (typeof ValueToSet == 'string') ValueToSet = getRadioIndex(TestElement, ValueToSet);
         if (ValueToSet >= 0) {
            TestElement[ValueToSet].checked = true;
            ValueWasSet = true;
         }
      }
      else if (TestElement.type.substr(0,6) == 'select') {
         if (typeof ValueToSet == 'string') ValueToSet = getOptionIndex(TestElement, ValueToSet);
         if (ValueToSet >= 0) {
            TestElement.options[ValueToSet].selected = true;
            ValueWasSet = true;
         }
      }
      else { // text input
         TestElement.value = ValueToSet;
         ValueWasSet = true;
      }
   }
   return ValueWasSet;
}

// Returns true if the field is left blank
function fieldValueIsBlank(InputName) {
   var TestInput = this.getElement(InputName);
   return ((typeof TestInput == 'object') && (isBlank(TestInput.value)));
}

// Returns true if a particular item in the the select-list or radio button group was picked. If no parameter passed, checks to see if at least one item was picked
function elementIsCheckedOrSelected(ElementName, SearchElement) {
   var PickedStatus = false;
   var TestElement = this.getElement(ElementName);
   if (typeof TestElement == 'object') {
      if (typeof TestElement.type == 'string') {
         if (TestElement.type.substr(0,6) == 'select') {
            // Checking the undefined property doesn't work on Mac IE, need to check arguments.length instead!
            if ((arguments.length < 2) || (typeof SearchElement == 'string')) SearchElement = getOptionIndex(TestElement, SearchElement);
            if (SearchElement >= 0) PickedStatus = TestElement.options[SearchElement].selected;
         }
         else PickedStatus = TestElement.checked; // single radio button
      }
      else { // Radio group
         // Checking the undefined property doesn't work on Mac IE, need to check arguments.length instead!
         if ((arguments.length < 2) || (typeof SearchElement == 'string')) SearchElement = getRadioIndex(TestElement, SearchElement);
         if (SearchElement >= 0) PickedStatus = TestElement[SearchElement].checked;
      }
   }
   return PickedStatus;
}

// Returns true if no errors were encountered after validating the form
function formIsValid() {
   return (this.invalidFields.length == 0);
}

// Adds the error message and field reference to the global array
function attachErrorToArray(OffendingElement, AlertMessage) {
   function FieldErrorObject(FieldIndex, ErrorMessage) {
      this.index = FieldIndex;
      this.error = ErrorMessage;
   }
   if (typeof OffendingElement == 'string') OffendingElement = this.getIndex(OffendingElement);
   this.invalidFields[this.invalidFields.length] = new FieldErrorObject(OffendingElement, AlertMessage);
   return false;
}

// Displays in-field errors, if they exist, and returns true or false
function displayInFields(ValidationMode, InitialMessage, SummaryMessage) {
   // Checking the undefined property doesn't work on Mac IE, need to check arguments.length instead!
   ValidationMode = (arguments.length < 1) ? 'ALL' : ValidationMode.toUpperCase();
   if (arguments.length < 2) var InitialMessage = '';
   if (arguments.length < 3) var SummaryMessage = '';
   var ErrorMessage = '';
   if (this.invalidFields.length > 0) {
      switch (ValidationMode) {
         case 'FIRST' : // Display the error message and put the cursor on the first-encountered invalid field
            ErrorMessage = this.invalidFields[0].error; 
            var FocusField = 0;
            break;
         case 'LAST' : // Display the error message and put the cursor on the last-encountered invalid field
            ErrorMessage = this.invalidFields[invalidFields.length-1].error;
            var FocusField = invalidFields.length - 1;
            break;
         case 'ALL' : // Displays the error messages from every in field, and puts the cursor on the first-encountered in field
            for (var k=0;k<this.invalidFields.length;k++) ErrorMessage += this.invalidFields[k].error;
            var FocusField = 0;
            break;
         default : var FocusField = -1; break; // 'NONE' -- don't display an error or put focus on a field
      }
      if (FocusField >= 0) {
         alert(InitialMessage + ErrorMessage + SummaryMessage);
         this.form.elements[this.invalidFields[FocusField].index].focus();
      }
      return false;
   }
   else return true;
}

// Dynamically adds a method to the object, then calls it
function dynamicMethodCall(FunctionName) {
   if (functionExists(FunctionName)) {
      eval('this.Dynamic' + FunctionName + '=' + FunctionName);
      var MethodCall = 'this.Dynamic' + FunctionName + '(';
      for (var j=1;j<arguments.length;j++) {
         if (j > 1) MethodCall += ',';
         MethodCall += 'arguments[' + j + ']';
      }
      eval(MethodCall + ')');
   }
}

// Specific validation methods

// Adds error information to the array if a value was not entered
function checkForBlank(InputName, AlertMessage) {
   // Checking the undefined property doesn't work on Mac IE, need to check arguments.length instead!
   if (arguments.length < 2) var AlertMessage = DefaultBlankError;
   return (this.isFieldBlank(InputName)) ? this.attachError(InputName, AlertMessage) : true;
}

// Adds error information to the array if the value is not an integer (or blank when required)
function checkForInteger(InputName, AlertMessage, IsRequired) {
   // Checking the undefined property doesn't work on Mac IE, need to check arguments.length instead!
   if (arguments.length < 2) var AlertMessage = DefaultIntegerError;
   if (arguments.length < 3) var IsRequired = true; // Defaults to true when not passed in
   var ElementIndex = this.getIndex(InputName);
   return ((ElementIndex >= 0) && (!((!IsRequired && isBlank(this.form.elements[ElementIndex].value)) || (isInteger(this.form.elements[ElementIndex].value))))) ? this.attachError(ElementIndex, AlertMessage) : true;
}

// Adds error information to the array if the value is not numeric (any number), or blank when required
function checkForNumeric(InputName, AlertMessage, IsRequired) {
   // Checking the undefined property doesn't work on Mac IE, need to check arguments.length instead!
   if (arguments.length < 2) var AlertMessage = DefaultNumericError;
   if (arguments.length < 3) var IsRequired = true; // Defaults to true when not passed in
   var ElementIndex = this.getIndex(InputName);
   return ((ElementIndex >= 0) && (!((!IsRequired && isBlank(this.form.elements[ElementIndex].value)) || (isNumeric(this.form.elements[ElementIndex].value))))) ? this.attachError(ElementIndex, AlertMessage) : true;
}

// Adds error information to the array if the value is not alpha-numeric (0-9 or alphabetic)
function checkForAlphaNumeric(InputName, AlertMessage, IsRequired) {
   // Checking the undefined property doesn't work on Mac IE, need to check arguments.length instead!
   if (arguments.length < 2) var AlertMessage = DefaultAlphaNumericError;
   if (arguments.length < 3) var IsRequired = true; // Defaults to true when not passed in
   var ElementIndex = this.getIndex(InputName);
   return ((ElementIndex >= 0) && (!((!IsRequired && isBlank(this.form.elements[ElementIndex].value)) || (isAlphaNumeric(this.form.elements[ElementIndex].value))))) ? this.attachError(ElementIndex, AlertMessage) : true;
}

// Adds error information to the array if the value isn't long enough
function checkForEnoughChars(InputName, AlertMessage, MinLength) {
   var ElementIndex = this.getIndex(InputName);
   return ((ElementIndex >= 0) && (!isLongEnough(this.form.elements[ElementIndex].value, MinLength))) ? this.attachError(ElementIndex, AlertMessage) : true;
}

// Adds error information to the array if the length of the value does not fit between the parameters
function checkForLength(InputName, AlertMessage, MinLength, MaxLength) {
   var ElementIndex = this.getIndex(InputName);
   return ((ElementIndex >= 0) && (!lengthFits(this.form.elements[ElementIndex].value, MinLength, MaxLength))) ? this.attachError(ElementIndex, AlertMessage) : true;
}

// Adds error information to the array if the value is not an integer or if its length does not fit between the parameters
function checkForIntegerLength(InputName, AlertMessage, MinLength, MaxLength) {
   var ElementIndex = this.getIndex(InputName);
   return ((ElementIndex >= 0) && (!((MinLength == 0 && isBlank(this.form.elements[ElementIndex].value)) || (isInteger(this.form.elements[ElementIndex].value) && lengthFits(this.form.elements[ElementIndex].value, MinLength, MaxLength))))) ? this.attachError(ElementIndex, AlertMessage) : true;
}

// Adds error information to the array if the values in the 2 fields don't match
function checkForMatchingValues(InputNameOne, InputNameTwo, AlertMessage, IsRequired, CaseSensitive) {
   // Checking the undefined property doesn't work on Mac IE, need to check arguments.length instead!
   if (arguments.length < 4) var IsRequired = true; // Defaults to true when not passed in
   var ElementOneIndex = this.getIndex(InputNameOne);
   var ElementTwoIndex = this.getIndex(InputNameTwo);
   return (((ElementOneIndex >= 0) && (ElementTwoIndex >= 0)) && ((IsRequired && (isBlank(this.form.elements[ElementOneIndex].value) && isBlank(this.form.elements[ElementTwoIndex].value))) || (!valuesMatch(this.form.elements[ElementOneIndex].value, this.form.elements[ElementTwoIndex].value, CaseSensitive)))) ? this.attachError(ElementTwoIndex, AlertMessage) : true;
}

// Adds error information to the array if the e-mail address is not , or blank when required
function checkValidEmail(InputName, AlertMessage, IsRequired) {
   // Checking the undefined property doesn't work on Mac IE, need to check arguments.length instead!
   if (arguments.length < 2) var AlertMessage = DefaultEmailError;
   if (arguments.length < 3) var IsRequired = true; // Defaults to true when not passed in
   var ElementIndex = this.getIndex(InputName);
   return ((ElementIndex >= 0) && (!((!IsRequired && isBlank(this.form.elements[ElementIndex].value)) || (isValidEmail(this.form.elements[ElementIndex].value))))) ? this.attachError(ElementIndex, AlertMessage) : true;
}

// Adds error information to the array if the
function checkValidMatchingPattern(InputName, AlertMessage, REPattern, IgnoreCase) {
   var ElementIndex = this.getIndex(InputName);
   return ((ElementIndex >= 0) && (!matchPattern(this.getValue(InputName), REPattern, IgnoreCase))) ? this.attachError(ElementIndex, AlertMessage) : true;
}

// Adds error information to the array if the specified item's selected/checked status is not equal to the status that is passed in
function checkElementCheckedOrSelected(ElementName, AlertMessage, PickedValue, ValidPickStatus) {
   // Checking the undefined property doesn't work on Mac IE, need to check arguments.length instead!
   if (arguments.length < 3) var PickedValue = ''; // When not passed in, checks to see if at least 1 item in the list/group was checked/selected
   if (arguments.length < 4) var ValidPickStatus = true; // When not passed in, defaults to true, meaning the passed-in value must be picked
   var ElementIndex = this.getIndex(ElementName);
   return ((ElementIndex >= 0) && (this.isPicked(ElementName, PickedValue) != ValidPickStatus)) ? this.attachError(ElementIndex, AlertMessage) : true;
}

// Adds error information to the array if the checkbox doesn't match the ValidCheckedStatus
function checkCheckBoxStatus(BoxName, AlertMessage, ValidCheckedStatus) {
   // Checking the undefined property doesn't work on Mac IE, need to check arguments.length instead!
   if (arguments.length < 3) var ValidCheckedStatus = true; // Defaults to true (for checked) when not passed in
   var ElementIndex = this.getIndex(BoxName);
   return ((ElementIndex >= 0) && (this.form.elements[ElementIndex].checked != ValidCheckedStatus)) ? this.attachError(ElementIndex, AlertMessage) : true;
}

function CheckPOboxAddress(addressCheckArray, AlertMessage){
	//list of po box strings to check for
	var poBoxFound = 0;
	var invalidAddressArray = new Array('p.o. box','po box','p.o.box','apo ','a.p.o.','a.po.','ap.o.','office box','p.obox','p.o.box','a.po','ap.o.','apo.','f.p.o.','fpo.','fp.o.','f.po','fpo ','post box','box ','pobox','p.o','p0','p.0','p0b','pob ','p 0');
	
	//check each item in the addressCheckArray against the list of po strings
	for (j=0; j<addressCheckArray.length; j++) {
		var ElementIndex = this.getIndex(addressCheckArray[j]);
		var addressToCheck = this.getValue(addressCheckArray[j]).toLowerCase();
		for (k=0; k<invalidAddressArray.length; k++){
			if (addressToCheck.indexOf(invalidAddressArray[k]) != -1) {
				poBoxFound++;
				var fixThisAddress = this.getIndex(addressCheckArray[j]);
			}
		}
		
	}
	return ((fixThisAddress >= 0) && (poBoxFound > 0)) ? this.attachError(fixThisAddress, AlertMessage) : true;
	if (poBoxFound > 0) {
		return false;
	}
}

// CC validation functions
function StripNonDigits(number) {
var Re = /\d+/g;
if(Re.lastIndex > 1) { Re.lastIndex = 0; }
var Array = Re.exec(number);
if(Re.lastIndex < 1) { return 'X'; }
var ss = Array.join();
while(Re.lastIndex > 0 && Re.lastIndex < number.length) {
	Array = Re.exec(number);
	if(Array) { ss += Array.join(); }
	}
return ss;
} // StripNonDigits()


function GetType(number) {
var len = number.length;
var Re = /^5[1-5]/;
	if(Re.lastIndex > 1) { Re.lastIndex = 0; }
		var Array = Re.exec(number);
			if(Array && len == 16) { return 'MasterCard'; }
Re = /^4/;
	if(Re.lastIndex > 1) { Re.lastIndex = 0; }
		Array = Re.exec(number);
			if(Array && (len == 13 || len == 16)) { return 'Visa'; }
Re = /^3[47]/;
	if(Re.lastIndex > 1) { Re.lastIndex = 0; }
		Array = Re.exec(number);
			if(Array && len == 15) { return 'American Express'; }
Re = /^(30[0-5]|3[68])/;
	if(Re.lastIndex > 1) { Re.lastIndex = 0; }
		Array = Re.exec(number);
			if(Array && len == 14) { return 'Diners Club'; }
Re = /^6011/;
	if(Re.lastIndex > 1) { Re.lastIndex = 0; }
		Array = Re.exec(number);
			if(Array && (len == 14 || len == 16)) { return 'Discover'; }
Re = /^(3|1800|2131)/;
	if(Re.lastIndex > 1) { Re.lastIndex = 0; }
		Array = Re.exec(number);
			if(Array && (len == 15 || len == 16)) { return 'JCB'; }
return '';
} // GetType()


function Reverse(number) {
var n = '';
for(i = number.length; i >= 0; i--) { n += number.substr(i,1); }
return n;
} // Reverse()


function AddedTogether(number) {
var n = 0;
for(i = 0; i < number.length; i++) {
	var s = number.substr(i,1);
	var si = parseInt(s,10);
	if(i % 2 > 0) {
		var ii = si * 2;
		if(ii < 10) { n += ii; }
		else {
			var ss = ' ' + ii;
			for(xi = 1; xi < ss.length; xi++) {
				var xs = ss.substr(xi,1);
				var xsi = parseInt(xs,10);
				n += xsi;
				} // for
			} // else
		} // if
	else { n += si; }
	} // for
return n;
} // AddedTogether()


function Mod10(n) {
var reversed = Reverse(n);
var total = AddedTogether(reversed);
if(total % 10 > 0) { return 0; }
return 1;
} // Mod10()

function CheckTestCard(n) {
   isTest = false;   
   if (n == ("4567765445677654" || "4321123443211234")) { isTest = true;}
   return isTest;
} // CheckTestCard

function ValidateCC(formContents) {
   ccNumberChecked = StripNonDigits(formContents);
   ccType = GetType(ccNumberChecked);
   ccNumberOkay = Mod10(ccNumberChecked);
   testCard = CheckTestCard(ccNumberChecked);
   if (!testCard) {
      if(     CCStep1Message.length > 0 && ccType.length < 2 && ccNumberOkay == 0) { errorMessage = CCStep1Message; }
      else if(CCStep2Message.length > 0 && ccNumberOkay == 0                     ) { errorMessage = CCStep2Message; }
      else if(CCStep3Message.length > 0 && ccType.length < 2                     ) { errorMessage = CCStep3Message; }
      else {
         errorMessage = "";
      }
   } else {
      errorMessage = "";
   }
   return errorMessage;
}

// The FormValidationObject function
function FormValidationObject(SuspectForm) {
   /*** PROPERTIES ***/
   this.form = (typeof SuspectForm == 'string') ? document.forms[SuspectForm] : SuspectForm; // Assigns a reference of the form to this property
   this.invalidFields = new Array();
   /*** METHODS ***/
   // General
   this.getElement = getElementByName;
   this.getIndex = getIndexByName;
   this.getValue = returnElementValue;
   this.setValue = setElementValue;
   this.isFieldBlank = fieldValueIsBlank;
   this.isPicked = elementIsCheckedOrSelected;
   this.isValid = formIsValid;
   this.attachError = attachErrorToArray;
   this.displayErrors = displayInFields;
   this.callFunction = dynamicMethodCall;
   // Specific validation
   this.checkBlank = checkForBlank;
   this.checkInteger = checkForInteger;
   this.checkNumeric = checkForNumeric;
   this.checkAlphaNumeric = checkForAlphaNumeric
   this.checkLongEnough = checkForEnoughChars
   this.checkLength = checkForLength;
   this.checkIntegerLength = checkForIntegerLength;
   this.checkForMatch = checkForMatchingValues;
   this.checkEmail = checkValidEmail;
   this.checkPattern = checkValidMatchingPattern;
   this.checkPicked = checkElementCheckedOrSelected;
   this.checkCheckbox = checkCheckBoxStatus;
   this.CheckPObox = CheckPOboxAddress;
}