/* documentation at bottom of this document */

	addLoadEvent(initializeValidation);		
	
	// create global variables used for validation on this page
		 var dataTypes = new Array();
		 var disallowedDataTypes = new Array();
		 var mandatoryDataTypes = new Array();
		 var disallowedCharacters = new Array();
		 var patterns = new Array();
		 var existingStyles = new Array();
		 var sysmsg="";
		 var msg="";
		 var warningMessage = "";
		 var componentMessage = "";
		 var aSynchFlag=true;
		 var currFieldRef;
		 
		 var validationPassed = false;
		 
	function initializeValidation()
		{
		 if(typeof disableAllValidation == "undefined" || disableAllValidation==false)
		 	{
			 	addValidation();  // add validation to the forms and preserve existing onsubmits
			 	setUpVariables(); // set up all the pattern values, etc
		 	}
		}
	
	function updateDynamicFields()
		{	
			try
				{
			
					var iFrames = document.getElementsByTagName('iframe');
					for(var i=0;i<iFrames.length;i++)
						{						
							if(iFrames[i].id && iFrames[i].id.indexOf("___Frame") > -1)
								{	
									var instanceName = iFrames[i].id.replace("___Frame","");
									if(window.FCKeditorAPI && FCKeditorAPI.GetInstance(instanceName))
										{									
											FCKeditorAPI.GetInstance(instanceName).UpdateLinkedField();
										}
								}
						}
				}
			catch(e)
				{
				}
		}
	
	function validateThisForm(formReference)
		{	
			// update any dynamic fields for the FCK editor;
			// normally it does not update the underlying
			// hidden field until after validation
			updateDynamicFields();
			if(this.getAttribute('preventMultipleSubmit') && this.getAttribute('preventMultipleSubmit') == "yes")
				{
					for (i=0;i<this.elements.length;i++)
					 	{
						 	if(this.elements[i].type=="submit")
						 		{	
						 			this.elements[i].disabled=true;
						 			this.elements[i].savedValue = this.elements[i].value;
							 		this.elements[i].value = "Submitting.....please wait";
						 		}
					 	}
				}
				
		
			var formReference=this;
			
			msg="";
			warningMessage="";
			componentMessage="";
			
			//get rid of all flags and restore styles
			if(typeof validationDOMAdditions == 'undefined' || validationDOMAdditions != false) 
				{
					clearErrorMessages(formReference);
				}
			
			//so we can restore it after it validates
			if(typeof validationStyleRestore == 'undefined' || validationStyleRestore != false) 
				{
					getCurrentStyle(formReference);
				}
			
			/* Go through the form.  Hidden fields with name="required" can each have the following attributes: 
			
			   1.  value - the name of the field on the form that is required
			   2.  class (optional) - the type of data required, which can be:
			   		a. anything - any non-blank value
			   		b. url - a valid URL
			   		c. email - a valid email address or comma-delimited string of emails
			   		d. integer - an integer 
			   		e. parmlist - a URI parameter list
			   		f. s1url - a valid S1URL value for Cold Fusion e.g. #local.s1vrsnurl#/blahblah
			   		g. uid - a valid UID xxnnne   where x is a letter, n is a numeric, and e is either a letter or a number
			   		h. dt - mm/dd/yyyy date; does not check e.g. Feb 30 - in here for legacy only; use validdt for new code
			   		i. validdt - mm/dd/yyyyy; DOES check for e.g. Feb 30
			   		j. regexp - a user-defined regular expression
			   3.  title - the message to appear if the field fails validation
			   4.  lang - if class=regexp, the regular expression, without / and /
			*/ 
			   		
			// go through each element on the form...
			for(var i=0;i<formReference.elements.length;i++)
				{					
					// if the field is a stopvalidation field, stop all validation for this case
					if(formReference.elements[i].name && (formReference.elements[i].name.toLowerCase()=="stopvalidation"))
						{
							break;
						}
					
					// if the field's function is dependent on which submit
					// button was pressed, check it now and activate it
					var errorclass=formReference.elements[i].getAttribute("errorclass");
									
					if(formReference.elements[i].getAttribute("whensubmittedby") && 
						formReference.elements[i].getAttribute("whensubmittedby") != "" &&
						formReference.getAttribute("submittedby") && 
						formReference.elements[i].getAttribute("whensubmittedby").indexOf(formReference.getAttribute("submittedby")) > -1)
						{	
							formReference.elements[i].name = 
							formReference.elements[i].name.replace("_validationDisabled-","");
						}
					

					// if its name is "required" or "optional" it will tell us about a field on the form that's required....
					// send this validation element to the validateSingleField function
					if(formReference.elements[i].name && (formReference.elements[i].name.toLowerCase()=="required" || formReference.elements[i].name.toLowerCase()=="optional"))
						{ 										
							msg+=validateSingleField(formReference.elements[i]);
						}	
						
					// For functions where we need to compare one field...e.g. field 1 must be "greater than" field 2.
					// If the function does not actually compare the two values, i.e. you just want field X to meet some pattern 1
					// IF field Y meets some pattern 2, then use the 'conditional' logic. 
					if(formReference.elements[i].name && (formReference.elements[i].name.toLowerCase()=="requiredcompare" || formReference.elements[i].name.toLowerCase()=="optionalcompare"))
						{ 										
							msg+=validateFieldRelationships(formReference.elements[i]);
						}	
						
					// to ensure that 'at least' n number of a given list have to have some non-blank value
					else if(formReference.elements[i].name && (formReference.elements[i].name.toLowerCase()=="atleast"))
						{	var howMany, fieldArray, totalMatches=0;
							if(formReference.elements[i].lang && formReference.elements[i].lang != "")
								{
									howMany = formReference.elements[i].lang;
								}
							else 
								{
									howMany = 1;
								}
							if (formReference.elements[i].value)
								{
									fieldArray = formReference.elements[i].value.split(",");
								}
							for (var j=0;j<fieldArray.length;j++)
								{
									if(!formReference.elements[fieldArray[j]])
										{
											//sysmsg += "System: Field " + formReference.elements[j].value + " not defined for at least clause \n";
										}
									else
										{	
											var valueToMatch=validationGetFieldValue(formReference.elements[fieldArray[j]]);											
											if (valueToMatch.match(/\S/) != null)
												{
													totalMatches++;													
												}
										}
								}
							
							if (totalMatches < howMany)
								{
									msg += formReference.elements[i].title + "\n";
									for (var j=0;j<fieldArray.length;j++)
										{	
											insertWarning(formReference.elements[fieldArray[j]], "error",null,null,errorclass);
										}
								}
						}		
						
					// group inputs into classes; this says inputs from at least x classes must be chosen (default 1)
					else if(formReference.elements[i].name && (formReference.elements[i].name.toLowerCase()=="atleastbyclass"))
						{	var howMany, fieldClassArray, totalMatches=0;
							if(formReference.elements[i].lang)
								{
									howMany = formReference.elements[i].lang;
								}
							else 
								{
									howMany = 1;
								}
							if (formReference.elements[i].value)
								{
									fieldClassArray = formReference.elements[i].value.split(",");
								}
							for (var j=0;j<fieldClassArray.length;j++)
								{
									if(getElementsByClassName(formReference, "input", fieldClassArray[j]).length == 0)
										{
											sysmsg += "System: Field " + formReference.elements[j].value + " not defined \n";
										}
									else
										{	
											var valueToMatch=validationArrayToList(getElementsByClassName(formReference, "input", fieldClassArray[j]));																							
											if (valueToMatch.match(/\S/) != null)
												{
													totalMatches++;													
												}
										}
								}
							
							if (totalMatches < formReference.elements[i].lang)
								{
									for (z=0;z<fieldClassArray.length;z++)
										{
											fieldsToMark = getElementsByClassName(formReference,"input",fieldClassArray[z]);
											for (fieldRef=0;fieldRef<fieldsToMark.length;fieldRef++)
												{
													insertWarning(fieldsToMark[fieldRef], "error",null,null,errorclass);
												}
										}
									msg += formReference.elements[i].title + "\n";									
								}
						}								
						
					// now check for fields that are mutually exclusive					
					else if(formReference.elements[i].name && (formReference.elements[i].name.toLowerCase()=="exclusive"))
						{	
							var mutuallyExclusiveFields = new Array();
							var mutuallyExclusiveFieldsChecked = new Array();
							if(formReference.elements[i].value)
								{
									mutuallyExclusiveFields = formReference.elements[i].value.split(",");
								}
							for (var j=0;j<mutuallyExclusiveFields.length;j++)
								{
									var fieldsInClass = getElementsByClassName(formReference, "input", mutuallyExclusiveFields[j]);
									mutuallyExclusiveFieldsChecked[j] = false;
									for (k=0;k<fieldsInClass.length;k++)
										{
										 	if (fieldsInClass[k].checked || (fieldsInClass[k].type != "checkbox" && fieldsInClass[k].type != "radio" && fieldsInClass[k].value && fieldsInClass[k].value!=""))
												{	
													mutuallyExclusiveFieldsChecked[j] = true;
												}
										}
								}
							
						
							// now loop through and see which set has elements checked
							var totalChecked = 0;
							for (var x=0; x<mutuallyExclusiveFieldsChecked.length; x++)
								{
									if (mutuallyExclusiveFieldsChecked[x] == true)
										{
											totalChecked++
										}
								}
							if (totalChecked > 1)
								{									
									if(formReference.elements[i].title)
										{
											msg += formReference.elements[i].title + "\n";											
										}
									else
										{
											msg += "Mutually exclusive fields chosen \n";
										}
									for (y=0;y<mutuallyExclusiveFields.length;y++)
										{
											fieldsToAlert=getElementsByClassName(formReference, "input", mutuallyExclusiveFields[y]);															
											for (z=0;z<fieldsToAlert.length;z++)
												{
													insertWarning(fieldsToAlert[z],"error","#",null,errorclass);																	
												}
										}
								}
						}	
						
						
						
					// conditional logic, e.g. if (fieldX matches regexp1 and fieldY matches regexp2) OR (field z matches regexp3) 
					// then validate field A according to rule M
					else if(formReference.elements[i].name && (formReference.elements[i].name.toLowerCase()=="conditional"))
						{	
							if(formReference.elements[i].getAttribute('conditionalfield') == false || formReference.elements[i].getAttribute('conditionalvalue') == false )
								{
									sysmsg += "System: Conditional field or conditional value not defined \n";								
								}
							else
								{
									conditionalFieldsOR = formReference.elements[i].getAttribute('conditionalfields').split("|");
									conditionalValuesOR = formReference.elements[i].getAttribute('conditionalvalues').split("|");	
																	
									conditionalResults=new Array();								
																	
									if (conditionalFieldsOR[0] == "" || conditionalValuesOR[0] == "" || conditionalValuesOR.length != conditionalFieldsOR.length)
										{
											sysmsg += "System: Conditional fields or conditional values out of synch or don't have values \n";
										}
									else
										{
											for(j=0;j<conditionalFieldsOR.length;j++)
												{
													conditionalFieldSegmentAND = conditionalFieldsOR[j].split("&");
													conditionalValueSegmentAND = conditionalValuesOR[j].split("&");
													if (conditionalFieldSegmentAND[0] == "" || conditionalValueSegmentAND[0] == "" || conditionalFieldSegmentAND.length != conditionalValueSegmentAND.length)
															{
																sysmsg += "System: Conditional fields AND condition " + j +  " is out of synch \n";
															}
													else
															{
																var meetsANDcondition = true;
																for (k=0;k<conditionalFieldSegmentAND.length;k++)
																	{
																		if(formReference.elements[conditionalFieldSegmentAND[k]])
																			{
																				var valueToMatch;
																				valueToMatch = "" + validationGetFieldValue(formReference.elements[conditionalFieldSegmentAND[k]]);			
																				//alert("matching " + valueToMatch + " and " + conditionalValueSegmentAND[k]);
																				matchExpression = new RegExp("^" + conditionalValueSegmentAND[k] + "$");
																				if(valueToMatch.match(matchExpression) == null)
																					{
																						meetsANDcondition = false;
																					}
																				// now set the result for this OR condition in the array
																				conditionalResults[j] = meetsANDcondition;
																			}
																		else
																			{
																				sysmsg += "System: Conditional fields AND field " + conditionalFieldSegmentAND[k] +  " not found \n";
																			}
																	}
																																	
																var meetsAnyCondition = false;																	
															}
														
												}
											
											
											for (var x=0;x<conditionalResults.length;x++)
												{
													if (conditionalResults[x] == true)
														{	
															meetsAnyCondition = true;
														}
												}
											
											if(meetsAnyCondition)
												{	//alert("validating " + formReference.elements[i].name);
													msg += validateSingleField(formReference.elements[i]);													
												}
										}							
								}							
						}												
					
					
					if(typeof window.disableDisallowedCharacterCheck == "undefined")
						{
							// no matter what the field function, check for disallowed character control
							for(var x=0;x<disallowedCharacters.length;x++)		
								{	
									if(formReference.elements[i].getAttribute(disallowedCharacters[x][0]) && 
									   formReference.elements[i].getAttribute(disallowedCharacters[x][0]) == disallowedCharacters[x][1])	
									{
										if(formReference.elements[i].value.match(disallowedCharacters[x][2]) != null)
									 	 	{
										 	 insertWarning(formReference.elements[i],disallowedCharacters[x][0],disallowedCharacters[x][4],null,errorclass);
										 	 msg += disallowedCharacters[x][3] + "\n";											 	
									 	 	}
						 	 		}
				 	 			}
			 	 		}
					}
					
				
			if (msg && msg != "")
				{	
					alert(msg);
					warningMessage=msg;					
				}
			if (sysmsg && sysmsg != "")
				{
					alert(sysmsg);														
				}	
				
			if(msg && msg!= "")	
				{
					validationPassed = false;
					if(this.getAttribute('preventMultipleSubmit') && this.getAttribute('preventMultipleSubmit') == "yes")
						{
							for (i=0;i<this.elements.length;i++)
							 	{
								 	if(this.elements[i].type=="submit")
								 		{	
								 			this.elements[i].disabled=false;
									 		this.elements[i].value = this.elements[i].savedValue;
								 		}
							 	}
						}
					return false;
				}
			
			validationPassed = true;
			return true;
		}

	function resetDependentRules()
		{
			for(var i=0;i<document.forms.length;i++)
				{
					for (j=0;j<document.forms[i].elements.length;j++)
						{						
							document.forms[i].elements[j].name = document.forms[i].elements[j].name.replace("_validationDisabled-","");
							
							if(document.forms[i].elements[j].type=="hidden" && 
					 			document.forms[i].elements[j].name && 
					 			(	document.forms[i].elements[j].name.toLowerCase()=="required" || 
					 				document.forms[i].elements[j].name.toLowerCase()=="optional" ||
					 			 	document.forms[i].elements[j].name.toLowerCase()=="atleast" || 
					 		 		document.forms[i].elements[j].name.toLowerCase()=="atleastbyclass" ||
					 		 		document.forms[i].elements[j].name.toLowerCase()=="exclusive" ||
					 		 		document.forms[i].elements[j].name.toLowerCase()=="conditional") && 
					 		 		document.forms[i].elements[j].getAttribute("whensubmittedby") &&  
					 		 		document.forms[i].elements[j].getAttribute("whensubmittedby") != "")
								{
									var fieldNameToActivate=document.forms[i].elements[j].getAttribute("whensubmittedby");
									if(document.forms[i].elements[fieldNameToActivate])
										{	// change the field's name so that it doesn't cause validation.  This will
											// be "undone" if the given submit button was used.											
											document.forms[i].elements[j].name = "_validationDisabled-" + document.forms[i].elements[j].name.toLowerCase();													
										}
								}	
						}
				}
			 
		}		

	function addValidation()
		{
		 var existingFunction;
		 /* add validation to all forms in the application */
		 for(var i=0;i<document.forms.length;i++)
			{
			 	addEvent(document.forms[i], "submit", validateThisForm);
			 	// have any submit button inform it was the one that 
			 	// submitted the form, when clicked.
			 	for (var j=0;j<document.forms[i].elements.length;j++)
			 		{
			 			if(document.forms[i].elements[j].type.toLowerCase() == "submit")
			 				{
			 					addEvent(document.forms[i].elements[j],"click",informSubmit);
			 				}
			 		}	 	
			}
		}	
		
	function informSubmit()
	{	
		if (typeof disableValidationDependencies == 'undefined')
			{
				//check for any dependencies on which submit was clicked
				resetDependentRules();	
				if(this.getAttribute("name") && this.getAttribute("name") != "")
					{	
						this.form.setAttribute("submittedby",this.name);		
					}
				else
					{
						this.form.setAttribute("submittedby","none");
						//must set this or browser assigns "" to name, causing
						//a server error
						this.name = "_noname";
					}
			}
	}
	
		
	function clearErrorMessages(formReference)
		{
		 //error flags are in a span with a class called autoError...get rid of all of them
		 var nodes=getElementsByClassName(document, "span", "autoError")
		 restoreStyles(formReference);
		 
		 for(var i=0; i<nodes.length; i++)
		 	{
			 nodes[i].parentNode.removeChild(nodes[i]);
			}
		}
		
			
	function insertWarning(formField, level, symbol, suppressDOMAdditions, errorClass)
		{
		  // The level field is currently not used.  Can be used to e.g. print different color warning
		  //  for severe vs warning messages, etc.
		  if(!suppressDOMAdditions) {suppressDOMAdditions = false;}
		  
		  // if it's not a simple form field (e.g. is a radio button or checkbox array), we have to get each
		  // element (checkbox, radio button) and call the function for it.  
		  if(typeof(formField.value)!= "string") 
		     {
			   for(var i=0;i<formField.length;i++)
			   	{			
				 insertWarning(formField[i], level, symbol, suppressDOMAdditions, errorClass);
			   	}
			 }
		  
		  else
		  	{
			  if(suppressDOMAdditions != true)
			  	{
				  // create a nice little span package with the error inside
				  var newSpan = document.createElement("span");
				  newSpan.className="autoError";
				  
				  if(errorClass && errorClass != "")
				  	{
						newSpan.className = newSpan.className + " " + errorClass;
				  	}
				  else
				  	{						
						newSpan.style.color="red";
						newSpan.style.fontFamily="arial";
						newSpan.style.fontWeight="bold";
						newSpan.style.fontSize="8pt";
						newSpan.style.paddingLeft="3px";
						newSpan.style.paddingRight="3px";
						newSpan.style.backgroundColor="#FFFF00";
					}
				  //depending on the type of error, it may be a different character				  
				  if(!symbol) {symbol="!";}
				  var newText = document.createTextNode(symbol);
	
				  newSpan.appendChild(newText);
				  
				  // find the parent container of the form field			 
				  parentNode = formField.parentNode;			
				  			  
				  //insert the span before the next sibling of the form field (e.g. right after the form field) 			  
				  parentNode.insertBefore(newSpan, formField.nextSibling);	
			  	}
				
			  // add a background color
			  if((!formField.type || (formField.type!='checkbox' && formField.type!='radio' && formField.type!='submit' && formField.type!='file' && formField.type!='fileupload')))
			  	{
			  		formField.style.backgroundColor = "#FFFFDD";
			  	}
			  return;
	  		}
		}	
	
	function validationArrayToList(arrayName)
		{
			 // turns a list of array values (such as from a series of checkboxes) into a comma-delimited list.		 	
			valueToReturn="";
			for(var i=0;i<arrayName.length;i++)
				{		 		
					// only add it to the list if checked!
					if(arrayName[i].checked)
						{
							valueToReturn=valueToReturn + arrayName[i].value + ",";
						}
					 //a multi-select box comes in as array of options
					 if(arrayName[i].selected)
						{
							valueToReturn=valueToReturn + arrayName[i].value + ",";
						}
					 //multiple select boxes might also be an issue, have to check their values as well
					 if (arrayName[i].type && arrayName[i].type != "multiple-select" &&
					 		arrayName[i].options && arrayName[i].selectedIndex != -1 && arrayName[i].options[arrayName[i].selectedIndex].value != "")
						{
							valueToReturn = valueToReturn + arrayName[i].options[arrayName[i].selectedIndex].value + ",";
						}			 	 			
					 if(arrayName[i].type && arrayName[i].type=="text" && arrayName[i].value)
						{
							valueToReturn += arrayName[i].value;
						}				  	 	
				}
			// hack off the last comma
			if(valueToReturn.length > 0 && valueToReturn.substr(valueToReturn.length-1,1) == ",")
				{
					valueToReturn=valueToReturn.substring(0,valueToReturn.length-1);	
				}
			 return valueToReturn;
		}	
	

	function validateSingleField(fieldRef)
		{	
			var fieldmsg="";		
			formReference = fieldRef.form;
			var errorclass=fieldRef.getAttribute("errorclass");

			if(fieldRef.value && fieldRef.className)
		  	{	
			  // loop through the different patterns defined above
			  if(fieldRef.className.toLowerCase() == "component")
				{
					fieldmsg += validateWithComponent(fieldRef);					
				}
			  else
			 	{
				  for(var patternNumber=0;patternNumber<patterns.length;patternNumber++)
				  	{
					  // if the pattern matches the one given in the 'required' hidden field...
					  if (patterns[patternNumber][0] == fieldRef.className.toLowerCase())
					  	{		 
						  // if the field doesn't exist, build a system message, but don't prevent submission.
						  if(!formReference.elements[fieldRef.value])
						  	{
							  sysmsg += "System: Field " + fieldRef.value + " not defined (function validateSingleField) \n";
						  	}
						  // then compare the actual field's value with the regexp.  If it doesn't match...
						  else
						  	{
						  	  valueToMatch = validationGetFieldValue(formReference.elements[fieldRef.value]);						 	
						  	  // set the pattern to match; use the user-supplied pattern if RegExp
						  	  var patternToMatch=patterns[patternNumber][1];
							 						
						  	  if (patterns[patternNumber][0].toLowerCase()=="regexp" && fieldRef.lang)
						  	  	{		
						  	  		if (fieldRef.ignorecase && fieldRef.ignorecase == "true")
						  	  			{
						  	  				patternToMatch = new RegExp(fieldRef.lang,"i");
						  	  			}
						  	  		else
						  	  			{								  	 
											patternToMatch = new RegExp();
										 	patternToMatch = fieldRef.lang;										  	 
										}
						  	  	}		
							 				  	  
							  if (valueToMatch.match(patternToMatch) == null)
							  	{
								  // don't add to the message if the field is optional and left blank.
								  if (fieldRef.name.toLowerCase()=="optional" && valueToMatch=="")
								   {}
								  else
								   {								  
								  	// otherwise add to the message											 
								  	fieldmsg += fieldRef.title + "\n";											  
								  	// insert warning symbol, but not if the validation field specifies not to 
									if(fieldRef.getAttribute("messageonly") == false || fieldRef.getAttribute("messageonly") != "true")
								  		{
											insertWarning(formReference.elements[fieldRef.value], "error",null,null,errorclass);
										}
									// otherwise, just pass "true" to suppress DOM additions
									else
										{
											insertWarning(formReference.elements[fieldRef.value], "error",false,true,errorclass);
										}
							   	   }
							  	}
						  	}
					  	}
				  	}
				}
		  	}
		  	 
		  if(fieldRef.value && fieldRef.getAttribute("disallowedclass"))
	  		{	
	  			var errorclass=fieldRef.getAttribute("errorclass");
  				for(var patternNumber=0;patternNumber<disallowedDataTypes.length;patternNumber++)
				  	{
					  // if the pattern matches one given in the disallowed attribute of the hidden field...
					  if (fieldRef.getAttribute("disallowedclass").toLowerCase().match(disallowedDataTypes[patternNumber].name) != null)
					  	{		
						  // if the field doesn't exist, build a system message, but don't prevent submission.
						  if(!formReference.elements[fieldRef.value])
						  	{
							  sysmsg += "System: Field " + fieldRef.value + " not defined (function validateSingleField/disallowed datatypes) \n";
						  	}
						 
						  else
						  	{
						  		
						  	  // this is the value of the field that the user filled in
						  	  valueToMatch = validationGetFieldValue(formReference.elements[fieldRef.value]);	
						  	 						  	 
						  	  for(var singlePattern=0; singlePattern<disallowedDataTypes[patternNumber].patterns.length;singlePattern++)
						  	  	{	
						  	  		var patternToMatch=disallowedDataTypes[patternNumber].patterns[singlePattern];						  	  								  	  								  	  		
						  	  		if (valueToMatch.match(patternToMatch) != null)
						  	  			{	
						  	  				fieldmsg += disallowedDataTypes[patternNumber].messages[singlePattern];
						  	  				symbol = disallowedDataTypes[patternNumber].symbols[singlePattern];
						  	  				if(fieldRef.getAttribute("messageonly") == false || fieldRef.getAttribute("messageonly") != "true")
										  		{
													insertWarning(formReference.elements[fieldRef.value], "error", symbol,null,errorclass);
												}
											// otherwise, just pass "true" to suppress DOM additions
											else
												{
													insertWarning(formReference.elements[fieldRef.value], "error",symbol,true,errorclass);
												}
						  	  			}
						  	  	}					 	
						  	}
					  	}
				  	}
	  		}	
	  		
		if(fieldRef.value && fieldRef.getAttribute("requiredclass"))
	  		{
		  		var errorclass=fieldRef.getAttribute("errorclass");
  				for(var patternNumber=0;patternNumber<mandatoryDataTypes.length;patternNumber++)
				  	{
					  // if the pattern matches one given in the disallowed attribute of the hidden field...
					  if (fieldRef.getAttribute("requiredclass").toLowerCase().match(mandatoryDataTypes[patternNumber].name) != null)
					  	{
						  // if the field doesn't exist, build a system message, but don't prevent submission.
						  // file field values won't exist to javascript unless populated!
						  if(!formReference.elements[fieldRef.value])
						  	{
							  sysmsg += "System: Field " + fieldRef.value + " not defined (function validateSingleField/disallowed datatypes) \n";
							  return "";
						  	}
						  if (fieldRef.name.toLowerCase() == "optional" && (!formReference.elements[fieldRef.value] || formReference.elements[fieldRef.value].value == ""))
						  	{
						  		//if the field is optional and empty, do nothing
						  		return "";
						  	}
						  else
						  	{
						  	  // this is the value of the field that the user filled in
						  	  valueToMatch = validationGetFieldValue(formReference.elements[fieldRef.value]);	
						  	 
						  	 
						  	  for(var singlePattern=0; singlePattern<mandatoryDataTypes[patternNumber].patterns.length;singlePattern++)
						  	  	{						  	  		
						  	  		var patternToMatch=mandatoryDataTypes[patternNumber].patterns[singlePattern];						  	  								  	  								  	  		
						  	  		//alert("matching: --" + valueToMatch + "-- with --" + patternToMatch + "-- Result: " + valueToMatch.match(patternToMatch));
						  	  		if (valueToMatch.match(patternToMatch) == null)
						  	  			{	
						  	  				fieldmsg += mandatoryDataTypes[patternNumber].messages[singlePattern];
						  	  				symbol = mandatoryDataTypes[patternNumber].symbols[singlePattern];
						  	  				if(fieldRef.getAttribute("messageonly") == false || fieldRef.getAttribute("messageonly") != "true")
										  		{
													insertWarning(formReference.elements[fieldRef.value], "error", symbol,null,errorclass);
												}
											// otherwise, just pass "true" to suppress DOM additions
											else
												{
													insertWarning(formReference.elements[fieldRef.value], "error",symbol,true,errorclass);
												}
						  	  			}
						  	  	}					 	
						  	}
					  	}
				  	}
	  		}	  		
			return fieldmsg;
		}	
		
		
	function validateFieldRelationships(fieldRef)
		{	
			var fieldmsg="";		
			formReference = fieldRef.form;
			
			var errorclass=fieldRef.getAttribute("errorclass");

			//make sure both attributes, or give a systems message.
			if(!fieldRef.getAttribute('field1') || !fieldRef.getAttribute('field2'))
				{
					sysmsg += "Systems: comparison operation must specify field1 and field2";
					return "";
				}
			
			var comparisonFieldName1 = fieldRef.getAttribute('field1');
			var comparisonFieldName2 = fieldRef.getAttribute('field2');
			
			// make sure the two specified fields exist on the form
			if(!formReference.elements[comparisonFieldName1] || !formReference.elements[comparisonFieldName2])
				{
					sysmsg += "Systems: comparison operation; specified field(s) do not exist";
					return "";
				}
			
			// make sure the operator is valid
			if (!fieldRef.getAttribute("operator") || 
					(
						fieldRef.getAttribute("operator") != ">" && 
						fieldRef.getAttribute("operator") != "<" && 
						fieldRef.getAttribute("operator") != "==" && 
						fieldRef.getAttribute("operator") != "!=" && 
						fieldRef.getAttribute("operator") != ">=" && 
						fieldRef.getAttribute("operator") != "<=" 
					))
				
				{
					sysmsg += "Systems: comparison operation; operator missing or invalid.  Must be >, <, ==, !=, >=, or <=";
					return "";			
				}
				
			// so now we have two valid field names and a valid operator			
			//now get the two field references
			var comparisonField1 = formReference.elements[comparisonFieldName1];
			var comparisonField2 = formReference.elements[comparisonFieldName2];
			
			// ...and their values
			var comparisonValue1 = validationGetFieldValue(comparisonField1);
			var comparisonValue2 = validationGetFieldValue(comparisonField2);
			
			
			// if the type is optionalcompare, and one of the fields is blank, return
			if (fieldRef.getAttribute("name") == "optionalcompare" && (comparisonValue1 == "" || comparisonValue2 == ""))
				{	
					return "";
				}
			
			// if the type is not a direct string compare, then modify
			// the fields to make it possible to compare directly
			if (fieldRef.className && fieldRef.className=="date")
				{
					try
						{
							comparisonValue1=new Date(comparisonValue1);
							comparisonValue2=new Date(comparisonValue2);
							// to avoid problems with single-digit dates 
							// (e.g. 5/1/2008 vs. 5/10/2008), convert to absolute time.
							comparisonValue1 = comparisonValue1.getTime();
							comparisonValue2 = comparisonValue2.getTime();							
							// if either one is NaN, return.  This means an 
							// invalid date and should be caught by other validation
							if(isNaN(comparisonValue1) || isNaN(comparisonValue2))
								{
									return "";
								}
						}
					catch(err)
						{
							// if you can't make a date out of it, it
							// should not prevent the user from submitting.
							// there should be an additional rule to make sure the 
							// date is in the proper format
							return "";
						}
					
				}
			
			// get the operator
			var operator = fieldRef.getAttribute("operator");
			
			var statement =   (comparisonValue1-0) +  
								operator + 
							  (comparisonValue2-0);
			
			try
				{
					var result=eval(statement);					
				}
			catch(err)
				{
					return "";
				}
			
			
			// now just check the result.  If false, field fails.
			if(!result)
				{
					fieldmsg += fieldRef.title + "\n";
					if(!fieldRef.getAttribute("messageonly") || fieldRef.getAttribute("messageonly") != "true")
				  		{
							insertWarning(comparisonField1, "error",null,null,errorclass);
							insertWarning(comparisonField2, "error",null,null,errorclass);
						}
						// otherwise, just pass "true" to suppress DOM additions
					else
						{	
						
							insertWarning(comparisonField1, "error", false, true, errorclass);
							insertWarning(comparisonField2, "error", false, true, errorclass);
						}				
				}
			// if the basic test (comparison) passes, then check for max diff scenarios
			else
				{
					// if the date comparison includes a maxdays, make sure it doesn't
					// exceed it
					if(fieldRef.getAttribute("maxdays") && !isNaN(fieldRef.getAttribute("maxdays")))
						{
							timeDiffInDays = Math.abs((comparisonValue1-0) - (comparisonValue2-0))/1000/60/60/24;
							maxDiffInDays = fieldRef.getAttribute("maxdays");
							
							if (timeDiffInDays > maxDiffInDays)
								{	
									fieldmsg += fieldRef.title + "\n";
									if(!fieldRef.getAttribute("messageonly") || fieldRef.getAttribute("messageonly") != "true")
								  		{
											insertWarning(comparisonField1, "error",null,null,errorclass);
											insertWarning(comparisonField2, "error",null,null,errorclass);
										}
										// otherwise, just pass "true" to suppress DOM additions
									else
										{	
										
											insertWarning(comparisonField1, "error", false, true, errorclass);
											insertWarning(comparisonField2, "error", false, true, errorclass);
										}	
								}
						}
					
				}

			return fieldmsg;
		}			
		
		
	function validateWithComponent(fieldRef)
		{ 
			formReference = fieldRef.form;			
			var additionalFields;
			
			if(!window.addToAjaxActionsRunNow)
			{
				alert("Systems: Must include Ajax initialization script to run Ajax actions \n");
				return "";
			}
			
	
			if(!fieldRef.getAttribute("componentname") || !fieldRef.getAttribute("componentmethod"))
			{
				alert("Systems: Must define component name and function for ajax validation");
				return "";
			}
			
			if(!formReference.elements[fieldRef.value])
			{
				alert("Systems: Component validation: field " + fieldRef.value + " does not exist");
				return "";
			}
			
			if(fieldRef.getAttribute("additionalfields")!=null)
				{
					additionalFields = new Array();
					var additionalFieldsNames = fieldRef.getAttribute('additionalfields').split(",");
					
					for(k=0;k<additionalFieldsNames.length;k++)
						{
							if(fieldRef.form.elements[additionalFieldsNames[k]])
								{
									additionalFields[additionalFields.length] = fieldRef.form.elements[additionalFieldsNames[k]];																														
								}
						}
				}

			// only continue validation if field is filled in 
			if(fieldRef.name && fieldRef.name.toLowerCase()=="optional" && formReference.elements[fieldRef.value].value == "")
			{
				return "";
			}
			
			else
			{
				aSynchFlag=false;
				currFieldRef=fieldRef;
				var component = fieldRef.getAttribute("componentname");
				var method = fieldRef.getAttribute("componentmethod");
				var errorclass=fieldRef.getAttribute("errorclass");
				var guifunction = "completeSynchValidation";				
				var xmlData = "<fieldvalue><![CDATA[" + escape(encodeURIComponent(validationGetFieldValue(formReference.elements[fieldRef.value]))) + "]]></fieldvalue>";
				if(additionalFields && additionalFields.length > 0)
					{
						xmlData += "<additionalfields>";
						for(var i=0;i<additionalFields.length;i++)
							{
								xmlData = xmlData + 
									"<additionalfield><fieldname>" + 
										escape(encodeURIComponent(getFieldName(additionalFields[i]))) +
									"</fieldname><fieldvalue><![CDATA[" +
										escape(encodeURIComponent(validationGetFieldValue(additionalFields[i]))) +
									"]]></fieldvalue></additionalfield>"
							}
						xmlData += "</additionalfields>";
					}
				addToAjaxActionsRunNow(component, method, guifunction, xmlData);								

				if(componentMessage && componentMessage != "")
				{	
					insertWarning(formReference.elements[fieldRef.value], "error",null,null,errorclass);					
					return componentMessage;											
				}
				else
				{
					return "";
				}
			}	
		}	
		
			
		
		
	function completeSynchValidation()
		{			
			var isValid = functionXML.getElementsByTagName("valid")[0].firstChild.nodeValue;
			if(isValid=="true")
				{
					componentMessage = "";
				}
			else
				{	
					if(functionXML.getElementsByTagName("message").length > 0 && functionXML.getElementsByTagName("message")[0].firstChild && functionXML.getElementsByTagName("message")[0].firstChild.nodeValue != "")
						{
							componentMessage = functionXML.getElementsByTagName("message")[0].firstChild.nodeValue + " \n";
						}
					else
						{
							if (currFieldRef.getAttribute("title"))
								{
									componentMessage = currFieldRef.getAttribute("title") + " \n";
								}
							else
								{
									componentMessage = ""
								}
						}
				}
		}
		
	function setUpVariables()
		{		
			// To add a new type of validator, give it a name here -- this matches the property on the form field....
			dataTypes[0]="anything";
			dataTypes[1]="url"; 
			dataTypes[2]="email";
			dataTypes[3]="integer";  // positive only 
			dataTypes[4]="parmlist"; 
			dataTypes[5]="s1url";
			dataTypes[6]="regexp"; // a regular expression, provide by the user via the lang attribute
			dataTypes[7]="uid";
			dataTypes[8]="dt"; // date in mm/dd/yyyy format
			dataTypes[9]="validdt" // VALID date in mm/dd/yyyy format
			dataTypes[10]="longdt" // date in mmm dd, yyyy format
			
							// now we create a 2-d array of patterns.  First column is the datatype from above...
							// don't touch this...
							 	for(var i=0; i<dataTypes.length;i++)
								{
								 patterns[i]=new Array();
								 patterns[i][0] = dataTypes[i];
								}
							
						
			/* now add your regular expression to correspond to the validation type above */
			patterns[0][1] = /\S/;
			patterns[1][1] = /http[s]?\:[\S]{1,}/;
			patterns[2][1] = /^(([a-zA-Z0-9_\-])+(\.([a-zA-Z0-9_\-])+)*@((\[(((([0-1])?([0-9])?[0-9])|(2[0-4][0-9])|(2[0-5][0-5])))\.(((([0-1])?([0-9])?[0-9])|(2[0-4][0-9])|(2[0-5][0-5])))\.(((([0-1])?([0-9])?[0-9])|(2[0-4][0-9])|(2[0-5][0-5])))\.(((([0-1])?([0-9])?[0-9])|(2[0-4][0-9])|(2[0-5][0-5]))\]))|((([a-zA-Z0-9])+(([\-])+([a-zA-Z0-9])+)*\.)+([a-zA-Z])+(([\-])+([a-zA-Z0-9])+)*)),?){1,}$/;
			patterns[3][1] = /^\d+$/;  // positive only
			patterns[4][1] = /^[a-zA-Z0-9&=_%\.]{1,}$/;
			patterns[5][1] = /^#[a-zA-Z0-9&=_%\.]{1,}#\/?/;	
			patterns[6][1] = / /;      // the user supplies the regExp for this one
			patterns[7][1] = /^[0-9A-Za-z]{2}[0-9]{3}[0-9A-Za-z]{1}$/;
			patterns[8][1] = /^(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.](19|20)\d\d$/;
			patterns[9][1] = /^(?=\d)(?:(?:(?:(?:(?:0?[13578]|1[02])(\/|-|\.)31)\1|(?:(?:0?[1,3-9]|1[0-2])(\/|-|\.)(?:29|30)\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})|(?:0?2(\/|-|\.)29\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))|(?:(?:0?[1-9])|(?:1[0-2]))(\/|-|\.)(?:0?[1-9]|1\d|2[0-8])\4(?:(?:1[6-9]|[2-9]\d)?\d{2}))($|\ (?=\d)))?(((0?[1-9]|1[012])(:[0-5]\d){0,2}(\ [AP]M))|([01]\d|2[0-3])(:[0-5]\d){1,2})?$/;
			patterns[10][1] = /^(Jan|Feb|Mar|May|Apr|Jul|Jun|Aug|Oct|Sep|Nov|Dec) (0[1-9]|[12][0-9]|3[01]), (19|20)\d\d$/;
			
			
			// begin rules with multiple sub-rules and messages for each
			
			// these have multiple sub-rules that need to perform "negative" matching 
			disallowedDataTypes[0] = new Object();
			disallowedDataTypes[0].name="illegalurl";
			disallowedDataTypes[0].patterns=new Array();
				disallowedDataTypes[0].patterns[0]=new RegExp("salesone.sbc.com|proposal.sbc.com|dbsite/|salesone_downloads/ppd/|pop_ppd", "i");
				disallowedDataTypes[0].patterns[1]=new RegExp("salesone_downloads/spd/|salesone_downloads/ppd_nonproduct/|salesone_downloads/esites/", "i");				
				disallowedDataTypes[0].patterns[2]=new RegExp("varpop_for_admin|proposal.web.att.com/salesone_sharedscripts/dwnld_win_pop", "i");				
				disallowedDataTypes[0].patterns[3]=new RegExp("salesone_admins/", "i");
				disallowedDataTypes[0].patterns[4]=new RegExp("pop_spd", "i");
				disallowedDataTypes[0].patterns[5]=new RegExp("salesone_admindwnlds/liquid_content/qa", "i");
			disallowedDataTypes[0].messages=new Array();
				disallowedDataTypes[0].messages[0]="URLs to Legacy SalesOne pages and files are not allowed (see fields marked << LEGACY URL)\n";
				disallowedDataTypes[0].messages[1]="Direct URLs to files which require a WinPop URL are not allowed (see fields marked << DIRECT URL )\n";
				disallowedDataTypes[0].messages[2]="URLs intended for administrative use only are not allowed (see fields marked << ADMIN URL )\n";				
				disallowedDataTypes[0].messages[3]="URLs to the SalesOne Admin Portal and its tools are not allowed (see fields marked << ADMIN PORTAL URL )\n";
				disallowedDataTypes[0].messages[4]="URLs to documents previously uploaded in SPD are not allowed (see fields marked << SPD URL )\n";
				disallowedDataTypes[0].messages[5]="URLs intended for administrative use only are not allowed (see fields marked << ADMIN URL )\n";
			disallowedDataTypes[0].symbols=new Array();	
				disallowedDataTypes[0].symbols[0]="<< LEGACY URL";
				disallowedDataTypes[0].symbols[1]="<< DIRECT URL";				
				disallowedDataTypes[0].symbols[2]="<< ADMIN URL";				
				disallowedDataTypes[0].symbols[3]="<< ADMIN PORTAL URL";
				disallowedDataTypes[0].symbols[4]="<< SPD URL";
				disallowedDataTypes[0].symbols[5]="<< ADMIN URL";
			
			disallowedDataTypes[1] = new Object();
			disallowedDataTypes[1].name="allhtml";
			disallowedDataTypes[1].patterns=new Array();
				disallowedDataTypes[1].patterns[0]=new RegExp();			
				disallowedDataTypes[1].patterns[0]=/<([A-Z][A-Z0-9]*)\b[^>]*>((.*?)<\/\1>){0,1}|(<\/.{1,}>)/i;	
			disallowedDataTypes[1].messages=new Array();
				disallowedDataTypes[1].messages[0]="HTML code is not allowed (see fields marked HTML)\n";			
			disallowedDataTypes[1].symbols=new Array();	
				disallowedDataTypes[1].symbols[0]="HTML";			
			
			// these have multiple sub-rules that require "positive" matching
			mandatoryDataTypes[0] = new Object();
			mandatoryDataTypes[0].name="fileupload";
			mandatoryDataTypes[0].patterns=new Array();				
				mandatoryDataTypes[0].patterns[0]=/^(([a-zA-Z]:\\)|(\\\\))?([\w\s\\_\.\-\`\~\!\@\#\$\%\^\&\(\)\[\]\{\}\-\+\=\;\'\,]{1,}\\)?[\w\d_]{1,}\.[a-zA-Z]{3,4}$/; 
				mandatoryDataTypes[0].patterns[1]=/((csv)|(doc)|(docm)|(docx)|(dot)|(gif)|(jpg)|(mpp)|(oft)|(pdf)|(pot)|(pps)|(ppt)|(pptx)|(rtf)|(swf)|(txt)|(vsd)|(vss)|(vst)|(xla)|(xls)|(xlsx)|(xlsm)|(xlt)|(xlw)|(zip)){1}$/i; 
				//new RegExp("\S{5,}[\.csv|\.doc|\.dot|\.gif|\.jpg|\.mpp|\.pdf|\.pot|\.pps|\.ppt|\.rtf|\.swf|\.txt|\.vsd|\.vss|\.vst|\.xla|\.xls|\.xlt|\.xlw|\.zip]", "i");
			mandatoryDataTypes[0].messages=new Array();
				mandatoryDataTypes[0].messages[0]="Filenames may contain alphanumeric characters, underscores and a file extension ( << FILE NAME )\n";
				mandatoryDataTypes[0].messages[1]="File type is not supported ( << FILE TYPE )\n";				
			mandatoryDataTypes[0].symbols=new Array();	
				mandatoryDataTypes[0].symbols[0]="<< FILE NAME";
				mandatoryDataTypes[0].symbols[1]="<< FILE TYPE";				
				
							
			//now set up all disallowed characters
			//each element of the array contains another array with
			// a) the property on the form field that indicates a character is disallowed.  Also the type of
			//    error passed to the field marker function-- this defaults to "error" in the function, and controls
			//    the symbol placed by the field.
			// b) the value of the property indicating it should be disallowed
			// c) the regexp sequence to disallow (must use the / and / delimiters)
			// d) the message to print if it is encountered
			// e) the symbol to use next to the field.  Defaults to !
			
			disallowedCharacters[0]=new Array();
			disallowedCharacters[0][0] = "crlf";
			disallowedCharacters[0][1] = "disallow";
			disallowedCharacters[0][2] = /\n/;
			disallowedCharacters[0][3] = "Remove line break (CR/LF) characters from fields marked <";
			disallowedCharacters[0][4] = " < "
			
			disallowedCharacters[1]=new Array();
			disallowedCharacters[1][0] = "bullets";
			disallowedCharacters[1][1] = "disallow";
			disallowedCharacters[1][2] = /[\u2022\u2023]/;
			disallowedCharacters[1][3] = "Remove bullets from the fields marked *";
			disallowedCharacters[1][4] = " * ";
		}
		
		
	// so if we change the appearance of a field, we can change it back
	function getCurrentStyle(formReference)
		{
			// for now, saving just the border properties
			for(var i=0;i<formReference.elements.length;i++)
				{	
					// if you exclude a field type here, 
					// you need to also exclude it when
					// restoring the styles and setting them or they won't match up
					if(!formReference.elements[i].type || (formReference.elements[i].type!='checkbox' && formReference.elements[i].type!='radio' && formReference.elements[i].type!='submit' && formReference.elements[i].type!='file' && formReference.elements[i].type!='fileupload'))
						{	
				 			existingStyles[i]= getStyle(formReference.elements[i],"backgroundColor");
				 		}
				}			
		}	
		
	// change it back
	// changed this to apply to all forms, in case a page with multiple
	// forms was used.  If the first form had an error, logic dictates
	// that if the user then went and attempted to submit the second form,
	// only errors from the second form should show, not leftover
	// errors from the first form.
 	function restoreStyles(formReference)
 		{
 			for(var formNum=0;formNum<document.forms.length;formNum++)
 				{
 				 formReference = document.forms[formNum];
			 	 for(var i=0;i<formReference.elements.length;i++)
					{
						if(!formReference.elements[i].type || (formReference.elements[i].type!='checkbox' && formReference.elements[i].type!='radio' && formReference.elements[i].type!='submit' && formReference.elements[i].type!='file' && formReference.elements[i].type!='fileupload'))
							{
					 			if(!existingStyles[i]) existingStyles[i]="";			 
					 			formReference.elements[i].style.backgroundColor = existingStyles[i];				 					
					 		}
					}	
				}	
 		}
		
			
	//not currently being used
	function getStyleObject(objectRef) 
	{
		if(objectRef.currentStyle) return objectRef.currentStyle;
		else return false;
	} 


	function getFieldName(fieldRef)
	{
		var theName;

		// if it's an array of checkboxes or radio buttons
		if (fieldRef.name)
			{
				return fieldRef.name			
			}
		else if (fieldRef.length && fieldRef.length > 0 && fieldRef[0].name)
			{
				return fieldRef[0].name
			}
		return "";
	}	
	


function validationGetFieldValue(fieldRef)
	{
		var theValue;	
		// if it's an array of checkboxes or radio buttons,
		// or a multi-select
		if (fieldRef.type && (fieldRef.type == "select-multiple"))
			{	
				theValue=validationArrayToList(fieldRef.options);				
			}
		else if (!fieldRef.value)
			{
				theValue= validationArrayToList(fieldRef);				
			}
		else if (fieldRef.type && (fieldRef.type == "checkbox" || fieldRef.type == "radio"))
			{
				if(fieldRef.checked)
					{
						theValue = fieldRef.value;
					}
				else
					{
						theValue = "";
					}
			}		
		else
			{
				theValue=fieldRef.value;
			}
		return theValue;
	}
