/*
Generic Form Validation.
tboland@gmail.com
http://www.techtoolblog.com
License: Free To Use, If Modified/Added
please send updated source to tboland@gmail.com

To Validate a Form Element Add the Custom Attribute:
	validate="VALIDATEHOW"

Your Current Options Are:
	"not_empty"
	"integer"
	"number" - decimal allowed
	"email"
	"phone" - includes international phone numbers

Multiple Validation uses the following syntax:
	validate="not_empty|integer"

To Add a Message Add the Custom Attribute:
	msg="Name is a required field" 

By Default the Messages are shown next to the form element.
To Show Alert Boxes add a Custom Attribute in the form tag (show_alert):
<form action="mypage.aspx" show_alert="1" onSubmit="return Validate(this);">
Examples:
<html>
<head>
	<script language="JavaScript" src="gfv.js" type="text/javascript"></script>
</head>
<body>
	<form action="mypage.php" show_alert="1" onSubmit="return Validate(this);">
	First Name <input type="Text" name="FirstName" maxlength="25" validate="not_empty" msg="First Name is Required" /><br/>
	Email <input type="text" name="Email" maxlength="25" validate="email" msg="Email is Required" /><br/>
	<input type="submit" value="Go">
	</form>
</body>
</html>

ADVANCED USERS:
	Add Your Own Function Calls to the validate attribute.
	It Must return true or false
	example:
		<input type="text" name="Age" validate="ValidateAge" />

MODIFICATIONS BY:
	Graciela Travieso (graciela@cariaco.com)
	New Function:
		- Validate Email uses regular expession now
		- Validate Zip Code
		- Validate Password
		- Password Confirmation
		- Validate Credit Card Number
			* ALERT NOTE: 
				- Validate the CC Number (MOD 10) against CC Type. CC Type must be the field BEFORE CC Number
				- If CC Number is locate in a diferent position modify the value for "alt_element"
			* PENDING CHANGES:
				- To pas the incrementing/decrementing value for "alt_element" as ATTRIBUTE
		- Validate Credit Card Expiration Date
		- Validate Credit Card CID
*/

// Regular Expressions.
var oneDigitReg = /^\d$/
var anyDigitReg = /^\d/;
var integerReg = /^\d+$/;
var numberReg = /(^(0|[1-9][0-9]*)$)|((^(0?|[1-9][0-9]*)\.(0*[1-9][0-9]*)$)|(^[1-9]+[0-9]*\.0+$)|(^0\.0+$))/;
var zipReg = /(^\d{5}$)|(^\d{5}-\d{4}$)/;
var googleReg = /(^\d{3}-\d{3}-\d{4}$)/;
var emailReg = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*\.(\w{2}|\w{3}|(com|net|org|edu|int|mil|gov|arpa|biz|aero|name|coop|info|pro|museum))$/;
var visaReg = /^4\d{3}-?\d{4}-?\d{4}-?\d{4}$/;
var mastReg = /^5[1-5]\d{2}-?\d{4}-?\d{4}-?\d{4}$/;
var discReg = /^6011-?\d{4}-?\d{4}-?\d{4}$/;
var amexReg = /^3[4,7]\d{13}$/;
var dinnReg = /^3[0,6,8]\d{12}$/;
var ssnReg = /^(?!000)([0-6]\d{2}|7([0-6]\d|7[012]))([ -]?)(?!00)\d\d\3(?!0000)\d{4}$/;
var fnameReg = /^([a-zA-Z]+(?:\.)?(?: [a-zA-Z]+(?:\.)?)*)$/;
var cidReg = /(^\d{3}$)|(^\d{4}$)/;
var paswReg = /^.{4,8}$/;
var phoneRegex = /^\(?(\d{3})\)?[- ]?(\d{3})[- ]?(\d{4})$/;

function Validate(objForm) {
	var arrValidated=new Array();
	for (var i=0; i<objForm.elements.length; i++) {
		var element=objForm.elements[i];
		var elName=element.name;

		if ((!elName)||(elName.length == 0)||(arrValidated[elName]))
		continue;
		
		arrValidated[elName] = true;
		var validationType = element.getAttribute("validate");
		
		if ((!validationType)||(validationType.length == 0))
		continue;

		var strMessages=element.getAttribute("msg");
		
		if (!strMessages)
		strMessages = "";
		var arrMessages = strMessages.split("|");
		var arrValidationTypes = validationType.split("|"); 
		
		for (var j=0; j<arrValidationTypes.length; j++) {
			var curValidationType = arrValidationTypes[j];
			var blnValid=true;
			switch (curValidationType) {
				case "not_empty":
					blnValid = ValidateNotEmpty(element);
					break;
				case "integer":
					blnValid = ValidateInteger(element);
					break;
				case "number":
					blnValid = ValidateNumber(element);
					break;
				case "name":
					blnValid = ValidateName(element);
					break;
				case "email":
					blnValid = ValidateEmail(element);
					break;
				case "zip_code":
					blnValid = ValidateZip(element);
					break;
				case "google_account":
					blnValid = ValidateGoogleAccount(element);
					break;
				case "cc_cid":
					blnValid = ValidateCDI(element);
					break;
				case "password":
					blnValid = ValidatePassword(element);
					break;
				case "psw_confirmation":
					// ALERT!!!!! Only for confirmations. Main password in the previous field
					var alt_element=objForm.elements[i-1];
					blnValid = ValidatePswConfirmation(element,alt_element);
					break;
				case "credit_card":
					// ALERT!!!!! Only for CC Numbers with CC Type in the previous field
					var alt_element=objForm.elements[i-1];
					blnValid = ValidateCC(element,alt_element);
					break;
				case "date_expire":
					// ALERT!!!!! 	Only for Expiration Date with separated MONTH and YEAR values. 
					//				The validation goes on YEAR field. MONTH field must be in the previous field
					var alt_element=objForm.elements[i-1];
					blnValid = ValidateDateExpire(element,alt_element);
					break;
				case "phone":
					blnValid = ValidatePhone(element);
					break;
				default:
				try {
					blnValid = eval(curValidationType+"(element)");
				}
				catch (ex) {
					blnValid = true;
				}
			}
			
			if (blnValid == false) {
				var message="invalid value for "+element.name;
				
				if ((j < arrMessages.length)&&(arrMessages[j].length > 0))
				message = arrMessages[j];
				InsertError(element, message);

				if ((typeof element.focus == "function")||(element.focus)) {
					element.focus();
				}
				return false;
			}
			else
			ClearError(element);
		}
	}
	return true;
}

//Empty Validation
function ValidateNotEmpty(objElement) {
	var strValue = GetElementValue(objElement);
	var blnResult = true;
	if(allTrim(strValue) == "") //check for nothing
	{
		blnResult = false;
	}
	return blnResult;
}

/* OLD Integer Validation. Replaced with regular expresion validation
function ValidateInteger(objElement)
// check for valid numeric strings 
{
	var strString = GetElementValue(objElement);
	var strValidChars = "0123456789";
	var strChar;
	var blnResult = true;
	// test strString consists of valid characters listed above
	
	for (i = 0; i < strString.length && blnResult == true; i++)
	{
		strChar = strString.charAt(i);
		if (strValidChars.indexOf(strChar) == -1)
		{
			blnResult = false;
		}
	}
	return blnResult;
}
*/
// Validate Integer.
function ValidateInteger(objElement) {
	var strValue = GetElementValue(objElement);
	return integerReg.test(strValue)
}

/* OLD Number Validation. Replaced with regular expresion validation
function ValidateNumber(objElement)
// check for valid numeric strings 
{
	var strString = GetElementValue(objElement);
	var strValidChars = ".0123456789"; //decimal ok
	var strChar;
	var blnResult = true;
	// test strString consists of valid characters listed above

	for (i = 0; i < strString.length && blnResult == true; i++)
	{
		strChar = strString.charAt(i);
		
		if (strValidChars.indexOf(strChar) == -1)
		{
			blnResult = false;
		}
	}
	return blnResult;
}
*/
// Validate Integer.
function ValidateNumber(objElement) {
	var strValue = GetElementValue(objElement);
	return numberReg.test(strValue)
}

/* OLD Email Validation. Replaced with regular expresion validation
function ValidateEmail(objElement) {
	// Will check for @, period after @ and text in between
	var strValue = GetElementValue(objElement);
	var in_space = strValue.indexOf(" ");

	if (in_space != -1)
	{ return false; }

	var len = strValue.length;
	var alpha = strValue.indexOf("@");
	var last_alpha = strValue.lastIndexOf("@");

	if (alpha != last_alpha)
	{ return false; }
	
	// No @, in first position, or name too short
	if (alpha == -1 || alpha == 0 || len<6 )
	{ return false; }
 	var last_p = strValue.lastIndexOf(".");
	
	// Be sure period at least two spaces after @, but not last char.
	if (last_p - alpha < 2 || last_p == (len - 1) )
	{ return false; }
}
*/
// Validate email address.
function ValidateEmail(objElement) {
	var strValue = GetElementValue(objElement);
	return emailReg.test(strValue)
}

/* OLD Email Validation. Replaced with regular expresion validation
//Valid PhoneNumber
function ValidatePhone(objElement){

	alert(objElement);
	// non-digit characters which are allowed in phone numbers
	var phoneNumberDelimiters = "()- ";
	
	// characters which are allowed in international phone numbers
	// (a leading + is OK)
	var validWorldPhoneChars = phoneNumberDelimiters + "+";
	
	// Minimum no of digits in an international phone no.
	var minDigitsInIPhoneNumber = 10;
	var strValue = GetElementValue(objElement);
	s=stripCharsInBag(strValue,validWorldPhoneChars);
	return (ValidateInteger(s) && s.length >= minDigitsInIPhoneNumber);
}
*/
// Validate Phone Number
function ValidatePhone(objElement) {
	var strValue = GetElementValue(objElement);
	return phoneRegex.test(strValue)
}


//Validate US Zip Code
function ValidateZip (objElement)
{   
	var strValue = GetElementValue(objElement);
	return zipReg.test(strValue)
}
//Validate Google Account Number
function ValidateGoogleAccount (objElement)
{   
	var strValue = GetElementValue(objElement);
	return googleReg.test(strValue)
}
//Validate Personal Name
function ValidateName (objElement)
{   
	var strValue = GetElementValue(objElement);
	return fnameReg.test(strValue)
}
//Validate Credi Card CID
function ValidateCDI (objElement)
{   
	var strValue = GetElementValue(objElement);
	return cidReg.test(strValue)
}
//Validate Password
function ValidatePassword (objElement)
{   
	var strValue = GetElementValue(objElement);
	return paswReg.test(strValue)
}
//Validate Password Confirmation
function ValidatePswConfirmation (objElement,altElement)
{   
	var pswConfirm = false;
	var passOne = GetElementValue(objElement);
	var passTwo = GetElementValue(altElement);
	
	if (passOne == passTwo) {
		pswConfirm = true;
	}
	return pswConfirm;
}

function GetElementValue(objElement) {
	var result="";
	switch (objElement.type) {
		case "text":
		case "hidden":
		case "textarea":
		case "password":
			result = objElement.value;
			break;
		case "select-one":
		case "select":
			if (objElement.selectedIndex >= 0)
			result = objElement.options[objElement.selectedIndex].value;
			break;
		case "radio":
		case "checkbox":
			for (var i=0; i<objElement.form.elements.length; i++) {
				if (objElement.form.elements[i].name == objElement.name) {
					if (objElement.form.elements[i].checked)
					result += objElement.form.elements[i].value+",";
				}
			}
			break;
		}
	return result;
}

function InsertError(element, strMessage) {
	if ((element.form.getAttribute("show_alert")) && (element.form.getAttribute("show_alert") != "0")) {
		alert(strMessage);
		return;
	}
	
	var strSpanID = element.name+"_val_error";
	var objSpan = document.getElementById(strSpanID);
	if (!objSpan) {
		if ((element.type == "radio")||(element.type == "checkbox")) {
			for (var i=0; i<element.form.elements.length; i++) {
			if (element.form.elements[i].name == element.name) {
				element = element.form.elements[i];
			}
		}
	}
	objSpan = document.createElement("span");
	objSpan.id = strSpanID;
	objSpan.className = "validation_error";
	var nodeAfter=0;
	var nodeParent = element.parentNode;
	for (var i=0; i<nodeParent.childNodes.length; i++) {
		if (nodeParent.childNodes[i] == element) {
			if (i < (nodeParent.childNodes.length-1))
				nodeAfter = nodeParent.childNodes[i+1];
				break;
			}
		}
		if ((!nodeAfter)&&(nodeParent.parentNode)) {
			nodeParent = nodeParent.parentNode;
			for (var i=0; i<nodeParent.childNodes.length; i++) {
				if (nodeParent.childNodes[i] == element.parentNode) {
					if (i < (nodeParent.childNodes.length-1))
					nodeAfter = nodeParent.childNodes[i+1];
					break;
				}
			}
		}
		if (nodeAfter)
			nodeParent.insertBefore(objSpan, nodeAfter);
		else
			document.body.appendChild(objSpan);
	}
	objSpan.innerHTML = strMessage;
}

function ClearError(element) {
	var strSpanID = element.name+"_val_error";
	var objSpan = document.getElementById(strSpanID);
	if (objSpan) {
		objSpan.innerHTML = "";
	}
}

function allTrim(cValue){
	var lDone=false;
	while (lDone==false){
		if (cValue.length==0) {return cValue;}
		
		if (cValue.indexOf(' ')==0){cValue=cValue.substring(1);lDone=false; continue;}
		else {lDone=true;}

		if (cValue.lastIndexOf(' ')==cValue.length-1){cValue=cValue.substring(0, cValue.length-1);lDone=false;continue;}
		else {lDone=true;}
	}
	return cValue;
}

function stripCharsInBag(s, bag)
{ 
	var i;
	var returnString = "";
	// Search through string’s characters one by one.
	// If character is not in bag, append to returnString.
	for (i = 0; i < s.length; i++)
	{ 
		// Check that current character isn’t whitespace.
		var c = s.charAt(i);
		if (bag.indexOf(c) == -1) returnString += c;
	}
	return returnString;
}


// BEGING Validate CC.
function isVisa(cc) {
  var regex = new RegExp(visaReg);
  if (isCreditCard(cc) == true) {
  	return regex.test(cc);
  } else {
  	return (false);
  }
}
function isMasterCard(cc) {
  var regex = new RegExp(mastReg);
  if (isCreditCard(cc) == true) {
  	return regex.test(cc);
  } else {
  	return (false);
  }
}
function isDiscover(cc) {
  var regex = new RegExp(discReg);
  if (isCreditCard(cc) == true) {
  	return regex.test(cc);
  } else {
  	return (false);
  }
}
function isAmericanExpress(cc) {
  var regex = new RegExp(amexReg);
  if (isCreditCard(cc) == true) {
  	return regex.test(cc);
  } else {
  	return (false);
  }
}
function isDinersClub(cc) {
  var regex = new RegExp(dinnReg);
  if (isCreditCard(cc) == true) {
  	return regex.test(cc);
  } else {
  	return (false);
  }
}
function isCreditCard(st) {
  // Encoding only works on cards with less than 19 digits
  if (st.length > 19)
    return (false);

  sum = 0; mul = 1; l = st.length;
  for (i = 0; i < l; i++) {
    digit = st.substring(l-i-1,l-i);
    tproduct = parseInt(digit ,10)*mul;
    if (tproduct >= 10)
      sum += (tproduct % 10) + 1;
    else
      sum += tproduct;
    if (mul == 1)
      mul++;
    else
      mul--;
  }
  if ((sum % 10) == 0)
    return (true);
  else
    return (false);
}
function ValidateCC (objElement,altElement)
{
	var doesMatch = true;
	
	var cardNumber = GetElementValue(objElement);
	var cardType = GetElementValue(altElement);

	if ((cardType == "Visa") && (!isVisa(cardNumber)))
		doesMatch = false;
	if ((cardType == "Mastercard") && (!isMasterCard(cardNumber)))
		doesMatch = false;
	if ((cardType == "Amex") && (!isAmericanExpress(cardNumber))) doesMatch = false;
	if ((cardType == "Discover") && (!isDiscover(cardNumber)))
		doesMatch = false;
	if ((cardType == "Diners") && (!isDinersClub(cardNumber)))
		doesMatch = false;
	return doesMatch;

}
function ValidateDateExpire (objElement,altElement)
{
  	var now = new Date();
  	var expInval = true;
	var y = GetElementValue(objElement);
	var m = GetElementValue(altElement);

  	if (m == "" || y == "") {
		expInval = false;
  	}
  	if (m <= now.getMonth() && y <= now.getYear()) {
		expInval = false;
  	}
  	return expInval;
}

