/*
	check.js
	
	For any form input items that have been assigned a 'check-*' class, will
	assign callback functions that will attempt an on-the-fly validation whenever
	focus leaves the form element. Only one 'check-*' class can be assigned to
	an element.
	
	Current checks:
		check-date - Ensure that dates are entered in yyyy/mm/dd or mm/dd/yyyy format.
		check-time - Ensures that times are entered in hh:mm:ss or hh:mm am/pm format.
		check-datetime - Ensure that datetime strings are entered in <check-date> <check-time> format.
		check-year - Ensures a valid non-negative number. Can pass an optional window to limit years entered.
		check-number - Ensures a numeric value with an optional minimum and maximum range.
		check-email - Ensures a valid email address.
*/

addEvent(window, 'load', check_init);

var __oFocusObj = null;

function check_init() {
    if (!document.getElementsByTagName) return;
	
	var aFormTags = new Array('input', 'textarea');
	for (var i = 0; i < aFormTags.length; i++) {
		_assignChecks(document.getElementsByTagName(aFormTags[i]));
	}
}

/*
	Parses out information about the type of check to be run and assigns
	callback functions to the blur() event of the element.
*/
function _assignChecks(aFormElements) {
	
	for (var i = 0; i < aFormElements.length; i++) {
		var oElem = aFormElements[i];
		
		if ((' ' + oElem.className + ' ').indexOf('check-') != -1) {
			addEvent(oElem, 'blur', _checkFactory);
		}
	}
}

function _checkFactory(e) {

	if (!e) var e = window.event;
	var oFormElem = getTarget(e);
	
	var reCheckType = /(check-[a-z]+)_?(-?\w+)?/
	var aCheckType = reCheckType.exec(oFormElem.className);
	if (aCheckType != null && oFormElem.value != '') {
		var sCheckType = aCheckType[1];
		var sArgs = aCheckType[2];
		if (!eval(
					"__" + sCheckType.replace(/-/, '_') + 
					"(oFormElem.value" + 
					(sArgs != null ? (", '" + sArgs.replace(/_/, "', '") + "'") : ("")) +
					");"
				)
			)
		{
			__oFocusObj = oFormElem;
			setTimeout('__oFocusObj.focus();__oFocusObj.select();', 50);			
		}
	}
}

function __check_date(sVal) {
	// Check to make sure date is in one of two formats -- mm/dd/yyyy or yyyy/mm/dd
	var reEUDate = /^(\d{4}|\d{2})[- \/]+[0-1]?\d[- \/]+[0-3]?\d$/;
	var reUSDate = /^[0-1]?\d[- \/]+[0-3]?\d[- \/]+(\d{4}|\d{2})$/;
			
	var aEUMatch = reEUDate.exec(sVal);
	var aUSMatch = reUSDate.exec(sVal);

	if (!(aEUMatch || aUSMatch)) {								
		alert('The following are examples of accepted date formats:\n\n01/31/2005, 1/31/2005\n2005/01/31, 2005/1/31\n\nPlease correct or remove the entered value.');
		return false;
	} else {
		return true;
	}
}

function __check_time(sVal) {
	var reTime = /^[0-1]?\d:[0-5]\d (AM|PM)$/i;	
	if (!reTime.exec(sVal)) {
		alert('Please enter a time in a valid format, such as \'10:10 am\'');
		return false;
	} else {
		return true;
	}
}

function __check_datetime(sVal) {
	// Check to make sure datetime is in one of two formats -- mm/dd/yyyy or yyyy/mm/dd
	var reEUDateTime = /^(\d{4}|\d{2})[- \/]+[0-1]?\d[- \/]+[0-3]?\d [0-1]?\d:[0-5][0-9] (AM|PM)$/i;
	var reUSDateTime = /^[0-1]?\d[- \/]+[0-3]?\d[- \/]+(\d{4}|\d{2}) [0-1]?\d:[0-5][0-9] (AM|PM)$/i;
			
	var aEUMatch = reEUDateTime.exec(sVal);
	var aUSMatch = reUSDateTime.exec(sVal);

	if (!(aEUMatch || aUSMatch)) {								
		alert('The following are examples of accepted date/time formats:\n\n01/31/2005 10:10 am, 1/31/2005 10:10 pm\n2005/01/31 10:10 am, 2005/1/31 10:10 pm\n\nPlease correct or remove the entered value.');
		return false;
	} else {
		return true;
	}
}

/*
	sBack, sForward denote valid year range. If not specified, just ensure
	a valid (non-negative) number is provided.
	
	Acceptable values are positive integers, which coorespond to concrete years
	or integers prefixed with 'w', to denote a sliding window of time.
		e.g. w20 w10 means 20 years in the past and 10 in the future.
	Windows and years can be mixed. But both need to be specified.
*/

function __check_year(sVal, sBack, sForward) {

	if (__check_numeric(sVal)) {
		if (sBack != null && sForward != null) {
			var iBack, iForward;
			
			var oDate = new Date();
			var iCurrYear = oDate.getFullYear();
			
			if (sBack.charAt(0) == 'w') {
				iBack = iCurrYear - new Number(sBack.substring(1));
			} else {
				iBack = sBack;
			}
			
			if (sForward.charAt(0) == 'w') {
				iForward = iCurrYear + new Number(sForward.substring(1));
			} else {
				iForward = sForward;
			}
			
			iCheckYear = new Number(sVal);
			
			if ((iBack <= iCheckYear) && (iCheckYear <= iForward)) {
				return true;
			} else {
				alert('Please enter a year between ' + iBack + ' and ' + iForward + '.');
				return false;
			}
		} else {
			return true;
		}
	} else {
		return false;
	}
}

/*
	sMin, sMax denote valid numeric ranges. If not specified, just ensure
	a valid number is provided.
*/
function __check_numeric(sVal, sMin, sMax) {
	var reNumber = /^-?\d+(\.\d+)?$/;
	if (!reNumber.exec(sVal)) {
		alert('Please enter a numeric value in the space provided.');
		return false;
	} else {
		var bRet = true;
		var iVal = new Number(sVal);
		
		var iMin, iMax;
		
		if (sMax == null) {
			// One argument provided. Disambiguate: m = min, x = max
			if (sMin.charAt(0) == 'x') {
				iMax = new Number(sMin.substring(1));
			} else {
				iMin = new Number(sMin.substring(1));
			}
		} else {
			iMin = new Number(sMin);
			iMax = new Number(sMax);
		}
		
		if (iMin != null) {
			bRet = bRet && (iMin <= iVal);
		}
		
		if (iMax != null) {
			bRet = bRet && (iVal <= iMax)
		}
		
		if (!bRet) {
			if (iMin != null && iMax != null) {
				alert('Please enter a number between ' + iMin + ' and ' + iMax + '.');
			} else if (iMin != null) {
				alert('Please enter a number greater than ' + (iMin - 1) + '.');
			} else {
				alert('Please enter a number less than ' + (iMax + 1) + '.');
			}
		}
		return bRet;
	}
}

function __check_email(sVal) {
	var reEmail = /^[_a-z0-9-]+(\.[_a-z0-9-]+)*(\+[_a-x0-9-]+)?@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,6})$/;
	if (!reEmail.exec(sVal.toLowerCase())) {
		alert('Please enter a valid email address.');
		return false;
	} else {
		return true;
	}
}