/****************************************************************************************************
Author: brhurley@jamestower.com
Date: 06/10/2005
Purpose: Collection of common validation functions.
Dependencies: None
Revision History:
	SKP - 6/19/2009 Changed RegEx in IsEmail() to allow - and _

****************************************************************************************************/
// validates that the field has been assigned data (for checking required fields)
function hasValue(objField)
{
	var blnHasValue;
	// if it is a text, password, textarea, hidden, file
	if(objField.type == "text" || objField.type == "password" || objField.type == "textarea" || objField.type == "hidden" || objField.type == "file")
	{
		blnHasValue = (objField.value.replace(/\s+/g, "").length > 0)
	}
	// if it is a select box
	else if(objField.type == "select-one" || objField.type == "select-multiple")
	{
		blnHasValue = (objField.selectedIndex >= 0);
	}
	// if it is a single radio btn or checkbox
	else if(objField.type == "radio" || objField.type == "checkbox")
	{
		blnHasValue = objField.checked;
	}
	// if it is a set of radio btn or checkboxes
	else if(objField.length > 0 && (objField[0].type == "radio" || objField[0].type == "checkbox"))
	{
		blnHasValue = false;
		for(var i = 0; i < objField.length; i++)
		{
			if(objField[i].checked)
			{
				blnHasValue = true;
				break;
			}
		}
	}
	// else just set it to true because it's something that you shouldn't do required checks on
	else
	{
		blnHasValue = true;
	}
	return blnHasValue;
}

// validates that the numeric or date value is in the given range
// returns false if value, min, and max are not all of the same type
// passing null or '' for either min or max leaves range open on that end
function isValueInRange(strValue, strMin, strMax)
{
	var blnInRange;
	if(strMin.length == 0) strMin = null;
	if(strMax.length == 0) strMax = null;
	if(isNumeric(strValue) && (strMin == null || isNumeric(strMin)) && (strMax == null || isNumeric(strMax)))
	{
		blnValid = ((strMin == null || parseFloat(strMin) <= parseFloat(strValue)) && (strMax == null || parseFloat(strMax) >= parseFloat(strValue)));
	}
	else if(isDate(strValue) && (strMin == null || isDate(strMin)) && (strMax == null || isDate(strMax)))
	{
		strValue = new Date(strValue);
		blnValid = ((strMin == null || new Date(strMin) <= strValue) && (strMax == null || new Date(strMax) >= strValue));
	}
	else
	{
		blnValid = false;
	}
	return blnValid;
}

// validates that a value is numeric, only allows leading 0 or . when value is between 0 and 1
function isNumeric(strValue)
{
	return /^(0|(-{0,1}((0\.[0-9]+)|([1-9][0-9]*(\.[0-9]+){0,1})|(\.[0-9]+))))$/.test(strValue);
}

// validates that a value is an integer, leading 0 not allowed unless value is 0
function isInteger(strValue) 
{
	return /^(0|(-{0,1}[1-9][0-9]*))$/.test(strValue);
}

// validates that a value is a date
// allowed formats: mm/dd/yyyy, mm/dd/yy, mm/d/yyyy, mm/d/yy, m/dd/yyyy, m/dd/yy, m/d/yyyy, m/d/yy
function isDate(strValue) 
{
	var blnValid = /^((0{0,1}[1-9])|(1[0-2]))\/((0{0,1}[1-9])|([1-2][0-9])|(3[0-1]))\/(([0-9]{2})|([1-9][0-9]{3}))$/.test(strValue);
	
	// if it was formatted correctly, continue on to test that the day is in range for the month/year
	if(blnValid)
	{
		var intMaxDays;
		var int1stSlash = strValue.indexOf('/');
		var int2ndSlash = strValue.indexOf('/', int1stSlash + 1);
		var intMonth = parseInt(strValue.substring(0, int1stSlash));
		var intDay = parseInt(strValue.substring(int1stSlash + 1, int2ndSlash));
		var intYear = parseInt(strValue.substring(int2ndSlash + 1));
		// February
		if(intMonth == 2)
		{
			// if it's not a leap year, Feb has 28 days
			if(intYear % 4 > 0 || (intYear % 100 == 0 && intYear % 400 > 0))
			{
				intMaxDays = 28;
			}
			// else it is a leap year, so make it 29
			else
			{
				intMaxDays = 29;
			}
		}
		// April, June, September, November have 30 days
		else if(intMonth == 4 || intMonth == 6 || intMonth == 9 || intMonth == 11)
		{
			intMaxDays = 30;
		}
		// all others have 31 days
		else
		{
			intMaxDays = 31;
		}
		blnValid = (intDay <= intMaxDays);
	}
	return blnValid;
}

// validates that a value is a valid time in the standard (AM/PM) time format
// allowed formats: hh:mm:ss tt, h:mm:ss tt, hh:mm tt, h:mm tt
function isStandardTime(strValue)
{
	return /^((0{0,1}[1-9])|(1[0-2]))(:[0-5][0-9]){1,2} (a|A|p|P)(m|M)$/.test(strValue);
}

// validates that a value is a valid time in the military time format
// allowed formats: hh:mm:ss, h:mm:ss, hh:mm, h:mm
function isMilitaryTime(strValue)
{
	return /^(([0-1]{0,1}[0-9])|(2[0-3]))(:[0-5][0-9]){1,2}$/.test(strValue);
}

// validates that a value is a valid time in either the standard (AM/PM) or military time formats
// allowed formats: see isStandardTime & isMilitaryTime
function isTime(strValue) 
{
	return (isStandardTime(strValue) || isMilitaryTime(strValue));
}

// validates that a value is a valid date & time
// allowed formats: see isDate & isTime, date must precede time and they must be separated by 1 [SPACE]
// time is optional, if a valid date is passed in with no time attached, will return as valid
function isDateTime(strValue)
{
	var blnValid = false;
	var int1stSpace = strValue.indexOf(' ');
	// if a space was found, validate the date & time
	if(int1stSpace > -1)
	{
		blnValid = (isDate(strValue.substring(0, int1stSpace)) && isTime(strValue.substring(int1stSpace + 1)));
	}
	// if no space, then just validate the whole string as a date only
	else
	{
		blnValid = isDate(strValue);
	}
	return blnValid;
}

// validates that a value is a phone number
// allowed formats: xxx-xxx-xxxx, (xxx) xxx-xxxx
function isPhone(strValue)
{
	return /^((\([0-9]{3}\) )|([0-9]{3}-))[0-9]{3}-[0-9]{4}$/.test(strValue);
}

// validates that a value is an email address
function isEmail(strValue)
{
	// SKP - 6/19/2009 Changed RegEx to allow - and _
	// return /^\w+(\.\w+)*@\w+(-)?\w+(\.\w+)+$/.test(strValue);
	return /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/.test(strValue);
}

// validates that a value is a zip code
// allowed formats: xxxxx, xxxxx-xxxx
function isZipCode(strValue)
{
	return /^[0-9]{5}((-[0-9]{4})|)$/.test(strValue);
}

// validates that a value is a social security number
// allowed formats: xxx-xx-xxxx, xxx xx xxxx
function isSocialSecurityNumber(strValue)
{
	return /^[0-9]{3}((-[0-9]{2}-)|( [0-9]{2} ))[0-9]{4}$/.test(strValue);
}

// validates that a value is a credit card number
function isCreditCardNumber(strCardNumber, strCardType)
{
	var blnValid = true;
	var intLength = strCardNumber.length;
	var intMultiplier = 2;
	var intSum = 0;
	var intProduct;
	strCardType = strCardType.toUpperCase();

	// Visa
	if(strCardType == "V" || strCardType == "VI")
	{
		blnValid = /^4(([0-9]{12})|([0-9]{15}))$/.test(strCardNumber);
	}
	// Mastercard
	else if(strCardType == "M" || strCardType == "MC")
	{
		blnValid = /^5[0-9]{15}$/.test(strCardNumber);
	}
	// Discover
	else if(strCardType == "D" || strCardType == "DI")
	{
		blnValid = /^6011(([0-9]{10})|([0-9]{12}))$/.test(strCardNumber);
	}
	// American Express
	else if(strCardType == "A" || strCardType == "AX")
	{
		blnValid = /^3(4|7)[0-9]{13}$/.test(strCardNumber);
	}
	// Unsupported Type
	else
	{
		blnValid = false;
	}
	
	// if it made it through all of that, do the %10 algorithm
	if(blnValid)
	{
		// walk through the string starting at 2nd to last char & working back to the beginning
		for(var i = intLength - 2; i >= 0; i--)
		{
			intProduct = intMultiplier * strCardNumber.charAt(i);
			if(intProduct > 9)
			{
				intSum = intSum + intProduct - 9;
			}
			else
			{
				intSum = intSum + intProduct;
			}
			intMultiplier = 3 - intMultiplier;
		}
		// last char of number should equal (10 - (SUM % 10)) unless (SUM % 10) is 0, then last char should also be 0
		intSum = intSum % 10;
		if(intSum != 0)
		{
			intSum = 10 - intSum;
		}
		blnValid = (intSum == strCardNumber.charAt(intLength - 1));
	}
	return blnValid;
}

// validates that a value is valid for a SQL Server INT field
function isSQL_INT(strValue)
{
	return (isInteger(strValue) && isValueInRange(strValue, -2147483648, 2147483647));
}

// validates that a value is valid for a SQL Server SMALLINT field
function isSQL_SMALLINT(strValue)
{
	return (isInteger(strValue) && isValueInRange(strValue, -32768, 32767));
}

// validates that a value is valid for a SQL Server TINYINT field
function isSQL_TINYINT(strValue)
{
	return (isInteger(strValue) && isValueInRange(strValue, 0, 255));
}

// validates that a value is valid for a SQL Server DATETIME field
function isSQL_DATETIME(strValue)
{
	return (isDateTime(strValue) && isValueInRange(strValue, '1/1/1753', '12/31/9999'));
}

// validates that a value is valid for a SQL Server SMALLDATETIME field
function isSQL_SMALLDATETIME(strValue)
{
	return (isDateTime(strValue) && isValueInRange(strValue, '1/1/1900', '6/6/2079'));
}

// validates that a value is valid for SQL Server DECIMAL field with the given precision & scale
function isSQL_DECIMAL(strValue, intPrecision, intScale)
{
	var intBeforeDecimal = intPrecision - intScale;
	var strRegExp = '^[0-9]{0,' + intBeforeDecimal + '}(\\.[0-9]{0,' + intScale + '}){0,1}$';
	var reValidator = new RegExp(strRegExp);
	return reValidator.test(strValue);
}

