/*
---------------------------------------------------------------------------
			syntax of functions using the error object
---------------------------------------------------------------------------

		oErrMsg.initErrMsgs ();

		[call desired functions]

		if (oErrMsg.errMsgAdded == true) {
			oErrMsg.dispErrMsgs();
			oErrMsg.focusFirst();
			return false;
		}
		else {
			return true;
		}
		
*/

function ErrorMsgObj () {
	
	this.errMsgArray = new Array();

	function errMsgsInit () {
		this.errMsgArray.length = this.errMsgIndex = 0;
		this.errMsgAdded = false;
	}

	function errorMsgAdd (msg) {
		this.errMsgArray [this.errMsgIndex++] = '' + msg + '';
		this.errMsgAdded = true;
	}

	function alertErrMsg () {
		var lne = '________________________________________';
		var msg = 'The form was not submitted because of the following error. \n';

		msg += lne + '\n\n';

		for (var n = 0; n < this.errMsgIndex; ++n)
			msg += '*   ' + this.errMsgArray [n] + '\n';

		msg += lne + '\n\nPlease correct ';
		msg += (this.errMsgIndex > 1) ? 'these errors' : 'this error';
		msg += ' and try again.';

		alert (msg);
	}

	function setErrorField(errField) {
		if (this.errMsgArray.length == 1) this.errField = errField;
	}

	function setFocusOnFirstError() {
		var theField = this.errField;
		var eIndex = this.elementIndex(theField);
		if (eIndex > -1) var fieldType = theField.form.elements[eIndex].type;
		if (fieldType != "hidden" && fieldType != undefined) theField.focus();
	}

	function getElementIndex(obj) {
		var theform = obj.form;
		if (typeof(theform) != "undefined") {
			for (var i=0; i<theform.elements.length; i++) {
				if (obj.name == theform.elements[i].name) return i;
			}
		}
		return -1;
	}

	//declare object's functions to outbound names
    ErrorMsgObj.prototype.initErrMsgs = errMsgsInit;
    ErrorMsgObj.prototype.addErrorMsg = errorMsgAdd;
    ErrorMsgObj.prototype.dispErrMsgs = alertErrMsg;
	ErrorMsgObj.prototype.setError = setErrorField;
	ErrorMsgObj.prototype.focusFirst = setFocusOnFirstError;
	ErrorMsgObj.prototype.elementIndex = getElementIndex;

}

//---------------------------------------------------------------------------

var oErrMsg = new ErrorMsgObj();

//==========================================

function chkEmptyFld (fld, nam) {
	if (fld.value.length == 0) {
		oErrMsg.addErrorMsg ('You have not filled in the \'' + nam + '\'.');
		oErrMsg.setError(fld);
		return;
	}
	else if (fld.value == null) {
		oErrMsg.addErrorMsg ('You have not filled in the \'' + nam + '\'.');
		oErrMsg.setError(fld);
		return;
	}
	else {
		for (var i=0; i<fld.value.length; i++) {
			var ch = fld.value.charAt(i);
			if (ch != ' ' && ch != '\t') {
				break;
			}
			else {
				if ((i + 1) == fld.value.length) {
					oErrMsg.addErrorMsg ('You have not filled in the \'' + nam + '\'.');
					oErrMsg.setError(fld);
					break;
				}
			}
		}
	}
}

//==========================================

function chkCheckbox(fld, nam) {	
	if (!fld.checked) {
		oErrMsg.addErrorMsg ('Please confirm \'' + nam + '\'.');
		oErrMsg.setError(fld);
		return;
	}
}

//==========================================

function chkSelect (fld, nam) {
	if (fld.value == '') {
		oErrMsg.addErrorMsg ('You have not chosen a \'' + nam + '\'.');
		oErrMsg.setError(fld);
		return;
	}
}

//==========================================

function chkPassword (fld1, nam1)
{
	var fieldVal = fld1.value;
	
	//check for existence of numbers
	var numArray=fieldVal.match(/[0-9]/g);
	var alphaArray=fieldVal.match(/[A-Z,a-z]/g);
	
	if (numArray==null || alphaArray==null) 
	{
		oErrMsg.addErrorMsg ("The " + nam1 + " must contain letters (a-z) and numbers (0-9).");
		oErrMsg.setError(fld1);
	}
	
	if (fieldVal.length < 5)
	{
		oErrMsg.addErrorMsg ("The " + nam1 + " must be 5 characters or more in length.");
		oErrMsg.setError(fld1);
	}
}

//==========================================

function chkCompare (fld1, val1, nam1, val2, nam2, op) {
	if (!eval("'" + val1 + "'" + op + "'" + val2 + "'")) {
		var msg='';
		switch (op) {
			case '<':
				msg = 'be less than';
				break;
			case '<=':
				msg = 'be less than or equal to';
				break;
			case '>':
				msg = 'be greater than';
				break;
			case '>=':
				msg = 'be greater than or equal to';
				break;
			case '==':
				msg = 'be equal to';
				break;
			case '!=':
				msg = 'not be equal to';
				break;
			default:
				msg = op;
				break;
		}
		oErrMsg.addErrorMsg ('The \'' + nam1 + '\' must ' + msg + ' the \'' + nam2 + '\'.');
		oErrMsg.setError(fld1);
		return;
	}
}

//==========================================

function chkValidDate(fld, nam) {
	var dateStr = fld.value;
	if (chkDate(dateStr)) {
		return true;
	}
	else {
		oErrMsg.addErrorMsg ('The \'' + nam + '\' field is formatted incorrectly');
		oErrMsg.setError(fld);
		return false;
	}
}

//---------------------------------------------------------------------------

function chkDate (fld) {
	var datePat = /^(\d{4})(\/|-)(\d{1,2})(\/|-)(\d{1,2})$/;
	var matchArray = fld.match(datePat); // is the format ok?
	
	if (matchArray == null) return false;
	
	 // parse date into variables
	year = matchArray[1];
	month = matchArray[3];
	day = matchArray[5];
	
	if (month < 1 || month > 12) return false;
	
	if (day < 1 || day > 31) return false;
	
	if ((month==4 || month==6 || month==9 || month==11) && day==31) return false;
	
	if (month == 2) { // check for february 29th
		var isleap = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
		if (day > 29 || (day==29 && !isleap)) return false;
	}
	
	return true;
}

//==========================================

function chkValidEmail(fld, nam) {
	var emailStr = fld.value;
	if (chkEmailAddress(emailStr)) {
		return true;
	}
	else {
		oErrMsg.addErrorMsg ('The \'' + nam + '\' field is formatted incorrectly');
		oErrMsg.setError(fld);
		return false;
	}
}

//---------------------------------------------------------------------------

function chkEmailAddress(emailStr) {

	if (emailStr.length == 0 || emailStr == null) return false;
	
	var checkTLD=1;
	
	// http://www.iana.org/gtld/gtld.htm
	// knownDomsPat is a list of known domain suffixes larger than 2 characters in length
	var knownDomsPat=/^(aero|arpa|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro)$/;
	
	var emailPat=/^(.+)@(.+)$/;
	var specialChars="\\(\\)><@,;:\\\\\\\"\\.\\[\\]";
	var validChars="\[^\\s" + specialChars + "\]";
	var quotedUser="(\"[^\"]*\")";
	var ipDomainPat=/^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/;
	var atom=validChars + '+';
	var word="(" + atom + "|" + quotedUser + ")";
	var userPat=new RegExp("^" + word + "(\\." + word + ")*$");
	var domainPat=new RegExp("^" + atom + "(\\." + atom +")*$");
	var matchArray=emailStr.match(emailPat);

	if (matchArray==null) return false;

	var user=matchArray[1];
	var domain=matchArray[2];

	for (i=0; i<user.length; i++) {
		if (user.charCodeAt(i)>127) return false;
	}
	for (i=0; i<domain.length; i++) {
		if (domain.charCodeAt(i)>127) return false;
	}

	if (user.match(userPat)==null) return false;

	var IPArray=domain.match(ipDomainPat);
	if (IPArray!=null) {
		for (var i=1;i<=4;i++) {
			if (IPArray[i]>255) return false;
		}
	}

	var atomPat=new RegExp("^" + atom + "$");
	var domArr=domain.split(".");
	var len=domArr.length;
	for (i=0;i<len;i++) {
		if (domArr[i].search(atomPat)==-1) return false;
	}

	if (checkTLD && domArr[len-1].length!=2 && domArr[len-1].search(knownDomsPat)==-1) return false;

	if (len<2) return false;

	return true;
}

//==========================================

function chkValidPostal(fld, nam) {
	var postal = fld.value;
	postal = postal.toUpperCase();
	var ch = postal.charAt(3);
	
	if (postal.length < 6 || postal.length > 7) {
		oErrMsg.addErrorMsg('The \''+nam+'\' is not in a valid format (X9X9X9 or X9X 9X9)');
		oErrMsg.setError(fld);
		return;
	}
	else if (postal.length == 7) {
		var ch = postal.charAt(3);
		if (ch == ' ') {
			postal = postal.substring(0,3) + postal.substring(4);
		}
		else {	
			oErrMsg.addErrorMsg('The \''+nam+'\' is not in a valid format (X9X9X9 or X9X 9X9)');
			oErrMsg.setError(fld)
			return;
		}
	}
		
	for (var i = 0; i<postal.length; i++) {
		var ch = postal.charAt(i);
		if (i == 0 || i == 2 || i == 4) {
			if (ch < 'A' || ch > 'Z') {
				// it is not a letter
				oErrMsg.addErrorMsg ('The \''+nam+'\' is not in a valid format (X9X9X9 or X9X 9X9)');
				oErrMsg.setError(fld)
				return;
			}
		}
		else if (i == 1 || i == 3 || i == 5) {
			if (ch < '0' || ch > '9') {
				// it is not a number
				oErrMsg.addErrorMsg ('The \''+nam+'\' is not in a valid format (X9X9X9 or X9X X9X)');
				oErrMsg.setError(fld)
				return;
			}
		}
	}
	
	fld.value = postal;
}

//==========================================

function chkRadio(fld, nam) {
	var radio_choice = false;
	
	for (var counter=0; counter < fld.length; counter++) {
		if (fld[counter].checked) radio_choice = true;
	}

	if (!radio_choice) {
		oErrMsg.addErrorMsg ('The \''+nam+'\' intention has not been selected.');
		oErrMsg.setError(fld);
		return;
	}
}

//==========================================

function returnMatches(parsePattern, searchString) {
	var matchArray=searchString.match(parsePattern);
	if (matchArray==null) return false;
	var newStr = '';
	for (i=0; i<matchArray.length; i++) {
		newStr += matchArray[i];
	}
	return newStr;
}

//==========================================

function chk10DigitPhone(fld, nam) {
	var phone = returnMatches(/[0-9]/gi, fld.value);
	if (!phone) {
		oErrMsg.addErrorMsg ('The \'' + nam + '\' must have 10 numeric digits.');
		oErrMsg.setError(fld);
		return;
	}
	fld.value = phone;
	if (phone.length < 10 || phone.length > 10) {
		oErrMsg.addErrorMsg ('The \'' + nam + '\' must have 10 numeric digits.');
		oErrMsg.setError(fld);
		return;
	}
}

//==========================================

function chk10DigitPhoneOptional(fld, nam) {
	if (fld.value == '') return;
	var phone = returnMatches(/[0-9]/gi, fld.value);
	if (!phone) {
		oErrMsg.addErrorMsg ('The \'' + nam + '\' must have 10 numeric digits.');
		oErrMsg.setError(fld);
		return;
	}
	fld.value = phone;
	if (phone.length < 10 || phone.length > 10) {
		oErrMsg.addErrorMsg ('The \'' + nam + '\' must have 10 numeric digits.');
		oErrMsg.setError(fld);
		return;
	}
}

//==========================================

	var ccErrorNo = 0;
	var ccErrors = new Array();
	
	ccErrors [0] = "Unknown Credit Card Type.";
	ccErrors [1] = "No Credit Card Number was provided.";
	ccErrors [2] = "The Credit Card Number is in an invalid format.";
	ccErrors [3] = "The Credit Card Number is invalid.";
	ccErrors [4] = "The Credit Card Number has an inappropriate number of digits.";
	ccErrors [5] = "The Credit Card has expired.";

function checkCreditCard (cardnumber, cardname, month, year) {
	
  var cards = new Array();
  
  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: "Diners Club", 
               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: "American Express", 
               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};
               
	var cardType = -1;
	for (var i=0; i<cards.length; i++) {
		if (cardname.toLowerCase() == cards[i].name.toLowerCase()) {
			cardType = i;
			break;
		}
	}

	if (cardType == -1) {
		ccErrorNo = 0;
		return false; 
	}
   
	if (cardnumber.length == 0)  {
		ccErrorNo = 1;
		return false; 
	}
  
	// 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 false; 
	}
    
	// 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 false; 
		}
	}  

	// 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 false; 
	}
    
	// 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 false; 
	};   

	// Now check the expiry date
	if (isNaN(parseInt(year)) || isNaN(parseInt(month))) {
		ccErrorNo = 5;
		return false; 
	}

	today = new Date();
	
	if (year <= today.getYear()) {
		if (month < (today.getMonth()+1)) {
			ccErrorNo = 5;
			return false; 
		}
	}
	
	// The credit card is in the required format.
	return true;
}

//---------------------------------------------------------------------------
/*
function chkValidCC(fld, fldType, month, year) {
	if (!checkCreditCard(fld.value, fldType.value, month.value, year.value)) {
		oErrMsg.addErrorMsg (ccErrors[ccErrorNo]);
		oErrMsg.setError(fld);
		return;
	}
}
*/

function chkValidCC(fld, fldType, month, year) {
	if (fld.value != '') {
		if (!checkCreditCard(fld.value, fldType.value, month.value, year.value)) {
			oErrMsg.addErrorMsg (ccErrors[ccErrorNo]);
			oErrMsg.setError(fld);
			return;
		}
		chkEmptyFld (document.frmForm.regCCName, 'Name on Credit Card');
	}
}

//==========================================
