/* ***************************************************************
 * script: validate.js											 *
 * purpose: javascript validation functions						 *
 * Created 9/26/2009 G Szabo (grant@hydeparksoftware.com)     	 *
 *****************************************************************/
 
//Custom JavaScript Functions to Provide Extended Capabilities
String.prototype.trim=function(){
    return this.replace(/^\s*|\s*$/g,'');
}

String.prototype.ltrim=function(){
    return this.replace(/^\s*/g,'');
}

String.prototype.rtrim=function(){
    return this.replace(/\s*$/g,'');
}

String.prototype.removePunct=function() {
	return this.replace(/[;|'|"|,]*/g,'');
}
 
 //Redirects from utlData.cfm Please Wait after processing is completed
 function fcnRedirect(url)
 {
	location.href(url);
 }
 
 function fcnRemoveSavedOrder(order_no)
 {
 	var f = confirm("Are you sure you want to remove this order?");
	if(f == true)
		fcnRedirect('savedOrders.cfm?order_no=' + order_no);
 }
 
// parses query string into name/value pairs object
// call like this: var args = fcnGetArgs(location.search.substring(1));
// then, you can get at the name/value pairs by saying args.email if email was one of the querystring variables present
function fcnGetArgs(query) 
{
	var args = new Object();
	var pairs = query.split(",");
	for(var i=0; i < pairs.length; i++) 
	{	
		var pos = pairs[i].indexOf('='); // look for "name=value"
		if(pos == -1) continue; //if not found, skip
		var argname = pairs[i].substring(0,pos); //extract the name
		var value = pairs[i].substring(pos+1); //extract the value 
		args[argname] = unescape(value); //store as a property
	}
	return args;
}

//only checks for required fields
function fcnBasicValidation(f) 
{
var msg;
	var empty_fields = "";
	var errors = "";
	var aRadioGroup = new Array(); //array to hold radio button groups
	
	//loop through the elements of the form, looking for all
	//text, textarea, and select-one (html select max 1) elements that don't have an "optional" property defined.
	//Also, if any of these elements have a "min" or a "max" property definied, then 
	//verify that they are numbers and that they are in the correct range.  If the 
	//element has a "numeric" propery defined, verify that it is a number, but don't
	//check its range.  Put together an error message based on result.
	for(var i=0; i < f.length; i++)
	{
		var e = f.elements[i];
		
		if (((e.type == "text") || (e.type == "textarea") || (e.type == "select-one") || (e.type == "radio") || (e.type == "password")) && !e.optional)
		{
			//first check if the field is empty
			if ((e.value == null) || (e.value == "") || isblank(e.value)) 
			{
				
				if(e.alt == null)
					empty_fields += "\n      " + e.name;
				else
					empty_fields += "\n      " + e.alt;
					
				continue;
			}
			
			//handle radio buttons.  Routine below groups radio buttons on e.NAME
			if (e.type == "radio")
			{
				//add this radio group to the aRadioGroup array and get 
				//back the array position for the element.  If the value
				//has already been processed, then POS will be the positon
				//where the value was found.
				pos = AddRadioGroup(aRadioGroup, e.name, false);

				fieldName = e.name;
				bOK = false;

				//process all form elements, looking for the radio group
				//as long as the group hasn't been processed already
				if(!aRadioGroup[pos][1])
				{
					for(var x=0; x < f.length; x++) 
					{
						var z = f.elements[x];
						
						if(z.name == aRadioGroup[pos][0]) 
						{
							if(z.checked) 
							{
								bOK = true;
								break;
							}
						}	
						
						//indicate that the radio group has been processed
						aRadioGroup[pos][1] = true;	
					}
					
					if(!bOK) 
					{
						if(e.alt == null)
							empty_fields += "\n      " + e.name;
						else
							empty_fields += "\n      " + e.alt;
						continue;				
					}
				}
			}
		}
		
		//now check for fields that are supposed to be numeric
		if(e.numeric || (e.min !=null) || (e.max !=null))
		{
			var v = parseFloat(e.value);
			if (isNaN(v) ||
				((e.min != null) && (v < e.min)) || 
				((e.max != null) && (v > e.max)))
			{
				errors += "- The field " + e.name + " must be a number";
				if (e.min != null)
					errors += " that is greater than " + e.min;
				if (e.max != null)
					errors += " and less than " + e.max;
				else if (e.max !=null)
					errors += " that is less than " + e.max;
				errors += ".\n";
			}
		}		
		
	} //end for loop
	
	//now if there were any errors, display the messages and return false to prevent form from
	//being submitted.  Otherwise return true after stripping punctuation and converting fields to uppercase.
	if(!empty_fields && !errors)  
	{
		return true;
	}
	else 
	{
		msg  = "____________________________________________________\n\n"
		msg += "The form was not submitted because of the following error(s).\n";
		msg += "Please correct these error(s) and re-submit.\n"; 
		msg += "____________________________________________________\n\n"		
		
		if (empty_fields)
		{
			msg += "- The following required field(s) are empty:" + empty_fields + "\n";
			if (errors) msg += "\n";
		}
	
		msg += errors;
		alert(msg);
		return false;
	}
}
 
//works with alt OR name tags
function fcnValidateWithEmail(f) 
{
	var msg;
	var empty_fields = "";
	var errors = "";
	var aRadioGroup = new Array(); //array to hold radio button groups
	
	//loop through the elements of the form, looking for all
	//text, textarea, and select-one (html select max 1) elements that don't have an "optional" property defined.
	//Also, if any of these elements have a "min" or a "max" property definied, then 
	//verify that they are numbers and that they are in the correct range.  If the 
	//element has a "numeric" propery defined, verify that it is a number, but don't
	//check its range.  Put together an error message based on result.
	for(var i=0; i < f.length; i++)
	{
		var e = f.elements[i];
		
		if (((e.type == "text") || (e.type == "textarea") || (e.type=="myselect") || (e.type == "select-one") || (e.type == "radio") || (e.type == "radio")) && !e.optional)
		{
			//first check if the field is empty
			if ((e.value == null) || (e.value == "") || isblank(e.value)) 
			{
				
				if(e.alt == null)
					empty_fields += "\n      " + e.name;
				else
					empty_fields += "\n      " + e.alt;
					
				continue;
			}
			
			//handle radio buttons.  Routine below groups radio buttons on e.NAME
			if (e.type == "radio")
			{
				//add this radio group to the aRadioGroup array and get 
				//back the array position for the element.  If the value
				//has already been processed, then POS will be the positon
				//where the value was found.
				pos = AddRadioGroup(aRadioGroup, e.name, false);

				fieldName = e.name;
				bOK = false;

				//process all form elements, looking for the radio group
				//as long as the group hasn't been processed already
				if(!aRadioGroup[pos][1])
				{
					for(var x=0; x < f.length; x++) 
					{
						var z = f.elements[x];
						
						if(z.name == aRadioGroup[pos][0]) 
						{
							if(z.checked) 
							{
								bOK = true;
								break;
							}
						}	
						
						//indicate that the radio group has been processed
						aRadioGroup[pos][1] = true;	
					}
					
					if(!bOK) 
					{
						if(e.alt == null)
							empty_fields += "\n      " + e.name;
						else
							empty_fields += "\n      " + e.alt;
						continue;				
					}
				}
			}
		}
	} //end for loop
	
	//perform email address checks
	if(document.getElementById("email") != null)
	{
		//trim any whitespace characters from email address
		document.getElementById("email").value = document.getElementById("email").value.trim();
		document.getElementById("email_confirm").value = document.getElementById("email_confirm").value.trim();		
		
		//verify that field email is a valid looking email address
		if( !fcnIsEmail(document.getElementById("email")) )
			errors += "- The entered email address does not appear to be a valid email address.\n";

		//verify that the email and confirm email fields match
		if( !fcnEmailConfirmMatch() ) 
			errors += "- The fields email and email_confirm do not match.\n";	
						
		//Removed 1/20/2009						
		//if( !fcnIsValidZip(document.getElementById("zipcode")) )
			//errors += "- The zip code / postal code entered does not appear to be valid.\n";
	}
	
	//now if there were any errors, display the messages and return false to prevent form from
	//being submitted.  Otherwise return true after stripping punctuation and converting fields to uppercase.
	if(!empty_fields && !errors)  
	{
	
		//loop through all elements, removing bad punctuation and converting to uppercase
		for(var i=0; i < f.length; i++)
		{
			var e = f.elements[i];
			
			if ( (e.type == "text") || (e.type == "textarea") )
			{
				e.value = e.value.removePunct().toUpperCase();
			}
		} //end for loop	
	
		//immediately before returning true, write out missing LT's to the form
		return true;
	}
	else 
	{
		msg  = "____________________________________________________\n\n"
		msg += "The form was not submitted because of the following error(s).\n";
		msg += "Please correct these error(s) and re-submit.\n"; 
		msg += "____________________________________________________\n\n"		
		
		if (empty_fields)
		{
			msg += "- The following required field(s) are empty:" + empty_fields + "\n";
			if (errors) msg += "\n";
		}
	
		msg += errors;
		alert(msg);
		return false;
	}
} //end fcnDMRValidate

//used by fcnValidate
function isblank(s)
{
	for(var i=0; i < s.length; i++) 
	{
		var c = s.charAt(i);
		if ((c != ' ') && (c != '\n') && (c != '\t')) return false;
	}
	return true;
}

//used by fcnValidate
function fcnEmailConfirmMatch() 
{
	if(document.getElementById("email").value.toUpperCase() == document.getElementById("email_confirm").value.toUpperCase()) return true;
	return false;
}

//tests for 5-digit US zip, zip plus 4, and canadian postal code
function fcnIsValidZip(s)
{
	val = s.value.trim();

	usZip = new RegExp(/(^\d{5}$)|(^\d{5}-\d{4}$)/);
	caZip = new RegExp(/(^[A-Z][0-9][A-Z][0-9][A-Z][0-9]$)|(^[A-Z][0-9][A-Z].[0-9][A-Z][0-9]$)/); //matches V3A3N1 or V3A 3N1 or V3A.3N1
	
	if (usZip.test(val)) 
	{
		return true;
	}
	
	val = val.toUpperCase();

	if (caZip.test(val.toUpperCase()))
	{
		return true;
	}
	
	//zip fails validation
	return false;
}

//validate email address
function fcnIsEmail ( obj ) 
{
	var emailStr = obj.value.toLowerCase(); //make sure don't run into a case issue when pattern matching by setting to lowercase
	var isOK = true;
	/* The following variable tells the rest of the function whether or not
	to verify that the address ends in a two-letter country or well-known
	TLD.  1 means check it, 0 means don't. */
	
	var checkTLD=1;
	
	/* The following is the list of known TLDs that an e-mail address must end with. */
	
	var knownDomsPat=/^(com|net|org|edu|int|mil|gov|arpa|biz|aero|name|coop|info|pro|museum|cc|org)$/;
	
	/* The following pattern is used to check if the entered e-mail address
	fits the user@domain format.  It also is used to separate the username
	from the domain. */
	
	var emailPat=/^(.+)@(.+)$/;
	
	/* The following string represents the pattern for matching all special
	characters.  We don't want to allow special characters in the address. 
	These characters include ( ) < > @ , ; : \ " . [ ] */
	
	var specialChars="\\(\\)><@,;:\\\\\\\"\\.\\[\\]";
	
	/* The following string represents the range of characters allowed in a 
	username or domainname.  It really states which chars aren't allowed.*/
	
	var validChars="\[^\\s" + specialChars + "\]";
	
	/* The following pattern applies if the "user" is a quoted string (in
	which case, there are no rules about which characters are allowed
	and which aren't; anything goes).  E.g. "jiminy cricket"@disney.com
	is a legal e-mail address. */
	
	var quotedUser="(\"[^\"]*\")";
	
	/* The following pattern applies for domains that are IP addresses,
	rather than symbolic names.  E.g. joe@[123.124.233.4] is a legal
	e-mail address. NOTE: The square brackets are required. */
	
	var ipDomainPat=/^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/;
	
	/* The following string represents an atom (basically a series of non-special characters.) */
	
	var atom=validChars + '+';
	
	/* The following string represents one word in the typical username.
	For example, in john.doe@somewhere.com, john and doe are words.
	Basically, a word is either an atom or quoted string. */
	
	var word="(" + atom + "|" + quotedUser + ")";
	
	// The following pattern describes the structure of the user
	
	var userPat=new RegExp("^" + word + "(\\." + word + ")*$");
	
	/* The following pattern describes the structure of a normal symbolic
	domain, as opposed to ipDomainPat, shown above. */
	
	var domainPat=new RegExp("^" + atom + "(\\." + atom +")*$");
	
	/* Finally, let's start trying to figure out if the supplied address is valid. */
	
	/* Begin with the coarse pattern to simply break up user@domain into
	different pieces that are easy to analyze. */
	
	var matchArray=emailStr.match(emailPat);
	
	if (matchArray==null) {
	
	/* Too many/few @'s or something; basically, this address doesn't
	even fit the general mould of a valid e-mail address. */
	
	//alert("The email address you entered is incorrect.    \nPlease reenter (checking for @ and .)");
	return false;
	}
	var user=matchArray[1];
	var domain=matchArray[2];
	
	// Start by checking that only basic ASCII characters are in the strings (0-127).
	for (i=0; i<user.length; i++) {
		if (user.charCodeAt(i)>127) {
		//alert("The username portion of the email address contains invalid characters.");
		return false;
	   	}
	}
	for (i=0; i<domain.length; i++) {
		if (domain.charCodeAt(i)>127) {
			//alert("Ths domain name portion of the email address contains invalid characters.");
			return false;
		   }
	}
	
	// See if "user" is valid 
	if (user.match(userPat)==null) {
		// user is not valid
		//alert("The username portion of the email address doesn't seem to be valid.");
		return false;
	}
	
	/* if the e-mail address is at an IP address (as opposed to a symbolic
	host name) make sure the IP address is valid. */
	
	var IPArray=domain.match(ipDomainPat);
	if (IPArray!=null) {
		// this is an IP address
		for (var i=1;i<=4;i++) {
		if (IPArray[i]>255) {
			//alert("Destination IP address of the email address is invalid!");
			return false;
		   }
		}
		return true;
	}
	
	// Domain is symbolic name.  Check if it's valid.
	// ^[^\s\(\)><@,;:\\\"\.\[\]]+$ = RegEx Pattern of atom
	var atomPat=new RegExp("^" + atom + "$");
	var domArr=domain.split(".");
	var len=domArr.length;
	for (i=0;i<len;i++) {
		if ( !domArr[i].match(atomPat) ) {
			//alert("The domain name portion of the email address does not seem to be valid.");
			return false;
		}
	}
	
	/* domain name seems valid, but now make sure that it ends in a
	known top-level domain (like com, edu, gov) or a two-letter word,
	representing country (uk, nl), and that there's a hostname preceding 
	the domain or country. */
	
	if (checkTLD && domArr[domArr.length-1].length!=2 && domArr[domArr.length-1].search(knownDomsPat)==-1) {
		//alert("The address must end in a well-known domain or two letter " + "country.");
		return false;
	}
	
	// Make sure there's a host name preceding the domain.
	
	if (len<2) {
		//alert("This address is missing a hostname!");
		return false;
	}
	
	// If we've gotten this far, everything's valid!
	return true;
}


//assumes aKeys and aVals are 1d arrays that are exactly aligned
//takes two arrays, a key array and a value array, along with the key to find the value for
//returns the value
function fcnGetKeyValue( aKeys, aVals, key ) {
	var msg = "";
	var rVal = "";

	for(i=0; i < aKeys.length; i++) {
		msg = msg + aKeys[i].trim().toUpperCase() + " = " + aVals[i].trim() + "\n";		
		if( aKeys[i].trim().toUpperCase() == key.trim().toUpperCase() ) {
			rVal = aVals[i].trim().toUpperCase();
		}
	}
	
	//uncomment for debugging purposes, shows key being returned, its value, and a full dump of key/value pairs
	//alert("key = " + key + "\n rVal = " + rVal + "\n\n" + msg);
	return rVal;
}

//searches a comma seperated values string for a specified value
function fcnValueFound(valToFind, stringToSearch) {
	var aVals = stringToSearch.split(","); //split csv string into an array
	for(var i=0; i < aVals.length; i++) //iterate over values, testing each one
	{	
		val = aVals[i]; //the value to test
 		
		if(	val.trim() == valToFind.trim() ) 
			return true; //the value is found, stop iterating and return true
	}
	
	//if we got here, the value wasn't found
	return false;
}

function AddRadioGroup(aRadioGroup, name, bProcessed) 
{
	//fcnValidate instantiates the aRadioGroup array, which we pass into this method
	//this method takes aRadioGroup and adds an array named aGroup to it.  Thus, we have an
	//array of arrays.  To access the elements:
	
	//aRadioGroup[0][0] : this will retrieve the NAME in the first aRadioGroup position
	//aRadioGroup[0][1] : this will retreive the boolean value for whether or not the NAME was processed already

	var L = aRadioGroup.length;
	var bFound = false; //variable to indicate whether the NAME has already been processed
	var aGroup = new Array();
	aGroup[0] = name; //position 0 will hold the NAME property of the radio button
	aGroup[1] = bProcessed; //position 1 will hold the true/false value for bProcessed

	//check to see if the NAME has already been processed
	if(L > 0) 
	{
		for(var i = 0; i < aRadioGroup.length; i++)
		{
			if (aRadioGroup[i][0] == name)
			{
				bFound = true;
				L = i; //set the position that gets returned to the array location where the value was found
				break;
			}
		}
	}
	
	//it the radio group NAME has not been found, go ahead and add it
	if(!bFound)
	{
		aRadioGroup[L] = aGroup;
	}
	
	//return the array position
	return L;
}

//used on supplyOrder/checkout_step2.cfm
function fcnValidateCheckoutStep2(f)
{
	var msg;
	var empty_fields = "";
	var errors = "";
	
	for(var i=0; i < f.length; i++)
	{
		var e = f.elements[i];
	
		//check if third party ship to is filled out, and if it is make sure it is numeric
		if(e.id == "ThirdParty_ShiptoNo")
		{
			if(e.value.trim().length > 0)
			{
				var v = parseFloat(e.value);
				if (isNaN(v))
					errors += "- The field " + e.alt + " must be a number\n";
			}
		}

		//check the service_code and make sure it isn't 0
		if(e.id == "service_code")
		{
			if(e.value == 0)
				errors += "- Please select the Shipping Service\n";
		}

	} //end for loop
	
	//now if there were any errors, display the messages and return false to prevent form from
	//being submitted.  Otherwise return true after stripping punctuation and converting fields to uppercase.
	if(!empty_fields && !errors)  
	{
		return true;
	}
	else 
	{
		msg  = "____________________________________________________\n\n"
		msg += "The form was not submitted because of the following error(s).\n";
		msg += "Please correct these error(s) and re-submit.\n"; 
		msg += "____________________________________________________\n\n"		
		
		if (empty_fields)
		{
			msg += "- The following required field(s) are empty:" + empty_fields + "\n";
			if (errors) msg += "\n";
		}
	
		msg += errors;
		alert(msg);
		return false;
	}
}

//used on supplyOrder/checkout_step3.cfm
function fcnConfirmOrder() 
{
	if( confirm('By selecting "Ok" your order will be placed!') ) 
		return true;
	else 
		return false;
}

function fcnConfirmUnload()
{
	var strMsg = "By continuing, the items currently in your shopping cart will be saved as a 'Saved Order' and checkout will be initiated for the items from this previous order.";
	strMsg

	if( confirm(strMsg) )
		return true;
	else
		return false;
}

//button click event handler from /sales_room/add_dealerlocation.cfm 
function fcnRemoveDealerLocation(CustNo, Code)
{
	strMsg = "Are you sure you want to remove this dealer location?";
	
	if( confirm(strMsg) ) 
	{
		var url = "add_dealerlocation_insert.cfm?removeLocation=1&Cust_No=" + CustNo + "&Code=" + Code;
		location.href(url);
	}		
	else 
	{
		return false;
	}
}