// Variables
var objRegExpState = /^[A-Za-z]{2}$/;
var objRegExpZipCode = /^(\d{5})-?(\d{4})?$/;
var objRegExpPhoneLocal = /^(\d{3}).?(\d{4})$/;
var objRegExpPhoneLD = /^.?(\d{3}).{0,2}(\d{3}).?(\d{4})$/;
var objRegExpEmail = /^[a-zA-Z0-9\._\-]+@[a-zA-Z0-9\-]+(\.[a-zA-Z0-9]{2,63})+$/;
var objRegExpDate = /^(\d{1,2})([-\/]|\. ?)(\d{1,2})\2((\d{4})|(\d{2}))$/;
var objRegExpWhiteSpace = /\s/g;
var selectedElements = new Array();
var flaggedElements = new Array();
var inErrorCheckMode = false;

// Prototypes
Array.prototype.Contains = function(value) {
	for (i in this) {
		if (this[i] == value) return true;
	}
	return false;
}

if (!Array.indexOf) {
	Array.prototype.indexOf = function(obj) {
		for (var i = 0; i < this.length; i++){
			if (this[i] == obj) {
				return i;
			}
		}
		return -1;
	}
}

// Validation Functions
function IsEntered(element) {
	if (!element.value) {
		return false;
	}
	return true;
}

function RequireField(element) {
	TrimField(element);
	if (!IsEntered(element)) {
		Flag(element, 'Required');
		return;
	}
	UnFlag(element);
}

// Filter Functions
function FilterNonNumeric(element) {
	if (element.value != StripNonNumeric(element.value)) element.value = StripNonNumeric(element.value);
}

function FilterNonNumericStrict(element) {
	if (element.value != StripNonNumericStrict(element.value)) element.value = StripNonNumericStrict(element.value);
}

function StripNonNumeric(value) {
	var result = new String(value);
	result = result.replace(/[^0-9\.-]/g, '');
	return result;
}

function StripNonNumericStrict(value) {
	var result = new String(value);
	result = result.replace(/[^0-9]/g, '');
	return result;
}

// Shortcut Functions
function SelectField(element) {
	if (inErrorCheckMode) {
		if (!element && flaggedElements.length > 0) {
			element = flaggedElements[flaggedElements.length - 1];
		}
		if (element) {
			if (!selectedElements.Contains(element)) {
				element.focus();
				if (element.value != '') {
					element.select();
				}
				selectedElements.push(element);
			}
		}
	}
}

// Formatting Functions
function TrimField(element) {
	var objRegExp = /(^\s*)([^\b]*\S)(\s*$)/;
	if (objRegExp.test(element.value)) {
		element.value = element.value.replace (objRegExp, "$2");
	} else {
		element.value = "";
	}
}

function LimitCharacters(element, numberOfCharacters) {
	element.value = element.value.substring(0, numberOfCharacters);
}

function UpperCase(element) {
	element.value = element.value.toUpperCase();
}

function LowerCase(element) {
	element.value = element.value.toLowerCase();
}

// state
function IsValidState(state) {
	if (objRegExpState.test(state)) {
		return true;
	}
	return false;
}

function FormatState(element, required) {
	if (!required) { required = false; }
	TrimField(element);
	if (IsValidState(element.value)) {
		UpperCase(element);
	} else if (IsEntered(element)) {
		Flag(element, 'Invalid state code (ex. ID)');
		SelectField(element);
		return;
	} else if (required) {
		RequireField(element);
		return;
	}
	UnFlag(element);
}

// zip code
function IsValidZipCode(zip) {
	if (objRegExpZipCode.test(zip)) {
		return true;
	}
	return false;
}

function FormatZipCode(element, required) {
	if (!required) { required = false; }
	TrimField(element);
	if (IsValidZipCode(element.value)) {
		if (element.value.length > 5) {
			element.value = element.value.replace(objRegExpZipCode, "$1-$2");
		}
	} else if (IsEntered(element)) {
		Flag(element, 'Invalid zip code (ex. 83201)');
		SelectField(element);
		return;
	} else if (required) {
		RequireField(element);
		return;
	}
	UnFlag(element);
}

// phone
function IsValidPhone(phone) {
	if (objRegExpPhoneLocal.test(phone)) {
		return true;
	} else if (objRegExpPhoneLD.test(phone)) {
		return true;
	}
	return false;
}

function FormatPhone(element, required) {
	if (!required) { required = false; }
	TrimField(element);
	if (IsValidPhone(element.value)) {
		if (objRegExpPhoneLocal.test(element.value)) {
			element.value = element.value.replace(objRegExpPhoneLocal, "$1-$2");
		} else if (objRegExpPhoneLD.test(element.value)) {
			element.value = element.value.replace(objRegExpPhoneLD, "$1-$2-$3");
		}
	} else if (IsEntered(element)) {
		Flag(element, 'Invalid phone (ex. 221-3400)');
		SelectField(element);
		return;
	} else if (required) {
		RequireField(element);
		return;
	}
	UnFlag(element);
}

// email
function IsValidEmail(email) {
	if (objRegExpEmail.test(email)) {
		return true;
	}
	return false;
}

function FormatEmail(element, required) {
	if (!required) { required = false; }
	TrimField(element);
	if (IsValidEmail(element.value)) {
		LowerCase(element);
	} else if (IsEntered(element)) {
		Flag(element, 'Invalid e-mail (ex. johndoe@aol.com)');
		SelectField(element);
		return;
	} else if (required) {
		RequireField(element);
		return;
	}
	UnFlag(element);
}

// multiple emails
function IsValidEmails(emails) {
	var strEmails = emails.replace(objRegExpWhiteSpace, '');
	emails = strEmails.split(',');
	for (var i = 0; i < emails.length; i++) {
		if (!IsValidEmail(emails[i])) {
			return false;
		}
	}
	return true;
}

function FormatEmails(element, required) {
	if (!required) { required = false; }
	TrimField(element);
	if (IsValidEmails(element.value)) {
		var strEmails = element.value.replace(objRegExpWhiteSpace, '');
		var emails = strEmails.split(',');
		for (var i = 0; i < emails.length; i++) {
			emails[i] = emails[i].toLowerCase();
		}
		element.value = emails[0];
		for (var i = 1; i < emails.length; i++) {
			element.value += ", " + emails[i];
		}
	} else if (IsEntered(element)) {
		Flag(element, 'Invalid e-mail (ex. user@aol.com)');
		SelectField(element);
		return;
	} else if (required) {
		RequireField(element);
		return;
	}
	UnFlag(element);
}

// date
function IsValidDate(date) {
	m = date.match(objRegExpDate)
	if (m != null) {
		return true;
	}
	return false;
}

function FormatDate(element, required) {
	if (!required) { required = false; }
	TrimField(element);
	if (IsValidDate(element.value)) {
		m = element.value.match(objRegExpDate)
		day = m[3];
		month = m[1];
		year = (m[5].length == 4) ? m[5] : 20 + m[6]
		element.value = month + '/' + day + '/' + year;
	} else if (IsEntered(element)) {
		Flag(element, 'Invalid date (ex. mm/dd/yyyy)');
		SelectField(element);
		return;
	} else if (required) {
		RequireField(element);
		return;
	}
	UnFlag(element);
}

// currency
function IsValidCurrency(currency) {
	currency = StripNonNumeric(currency);
	if (isNaN(parseFloat(currency))) {
		return false;
	}
	return true;
}

function FormatCurrency(element, required) {
	if (!required) { required = false; }
	TrimField(element);
	if (IsValidCurrency(element.value)) {
		value = StripNonNumeric(element.value);
		value = parseFloat(value) * 100;
		intCents = value % 100;
		strCents = intCents.toString();
		value = Math.floor(value/100).toString();
		if (intCents < 10)
			strCents = "0" + strCents;
		for (var i = 0; i < Math.floor((value.length-(1+i))/3); i++)
			value = value.substring(0,value.length-(4*i+3))+','+
			value.substring(value.length-(4*i+3));
		element.value = '$' + value + '.' + strCents;
	} else if (IsEntered(element)) {
		Flag(element, 'Invalid currency (ex. $25.00)');
		SelectField(element);
		return;
	} else if (required) {
		RequireField(element);
		return
	}
	UnFlag(element);
}

// Flagging Functions
function Flag(element, message) {
	if (inErrorCheckMode) {
		var name = element.name + 'Error';
		document.getElementById(name).innerHTML = '*' + message;
		element.style.borderColor = 'Red';
		element.style.borderStyle = 'Solid';
		element.style.borderWidth = '1px';
		element.style.padding = '2px';
		if (!flaggedElements.Contains(element)) {
			flaggedElements.push(element);
		}
	}
}

function UnFlag(element) {
	if (inErrorCheckMode) {
		var name = element.name + 'Error';
		document.getElementById(name).innerHTML = '';
		element.style.borderColor = '#798293';
		element.style.borderStyle = 'Solid';
		element.style.borderWidth = '1px';
		element.style.padding = '2px';
		if (flaggedElements.Contains(element)) {
			flaggedElements.splice(flaggedElements.indexOf(element), 1);
		}
	}
}