/*******************************************************************************
*
*	Project		:	O3L FNI for WebSec
*
*	File		:	O3L_FNIValidation.js
*
*	Copyright	:	Data Broadcast Services Pty Ltd
*					All rights reserved.
*
*	Purpose		:	Provide a validataion library that allows Front End
*				validation in line with the FNI page def.
*
*	Public Functions: 	ValidatePageDefn(xiPageVersion, xcPageDefn )
*					Validate the FNI Page Def for this page.
*					Called from the <BODY onload=>
*
*				ValidateElement(xiPageVersion, xiElement,xiForm,
*						xcPageDefn, xiWebPage, xiFunction )
*					Validate an individual PageDefelement on the page.
*
*				ValidatePage( xiPageVersion,xiForm, xcPageDefn, 
*						xiWebPage,xiFunction )
*					Validate all PageDef elements on a page.
*				
*	Private Functions: 	AlertOrFn(xiErrorArray, xiFunction ) = 
*					Raise a standard Alert for errors if no page
*					based function is defined. 
*
*				ValidateObject(xiSubObj, xiFormName, xiPageDefnObj, xiWebPage, xcError)
*					Core Validation rules called for
*					each page def object.
*		
*******************************************************************************/


/*******************************************************************************
Globals
*******************************************************************************/
// NO GLOBALS REQUIRED


/*******************************************************************************
Functions
*******************************************************************************/


/*******************************************************************************
*
*	Scope		:	PRIVATE
*	Function	:	AlertOrFn()
*
*	Purpose		:	Calls either the function specified or
*				the standardard alert() with a formatted error message
*
*	Parameters	:	xiErrorArray 	An array of Error message in the form:
*						"ControlName: ErrorMessage"
*				xiFunction	The name of the function to call. 
*						This function will be called for each
*						message in the passed xiErrorArray and
*						will be called as either:
*							function("Error String") 
*						or
*							function("Error String","ControlName");
*						if the ControlName cannot be located in the
*						xiErrorArry[i] string.
*
*
*	Returns		:	boolean:	true	if successfully
*						fail	otherwise
*
*	JavaScript	:	1.3
*
*	Assumptions	:	xiFunction if passed is defined and valid in the page object.
*
*
*******************************************************************************/

function AlertOrFn(xiErrorArray, xiFunction )
{
	var FunctionStr;
	var ErrorInst = new Array();
	

	if (xiFunction)
	{
		for ( i=0 ; i < xiErrorArray.length; i++)
		{
			// Split the string into its component parts
			ErrorInst=xiErrorArray[i].split(":");
			if (ErrorInst.length == 1)
			{
				FunctionStr=xiFunction+'("'+ErrorInst[0]+'")';
			}
			else if (ErrorInst.length == 2)
			{
				FunctionStr=xiFunction+'("'+ErrorInst[1]+'","'+ErrorInst[0]+'")';
			}
			else
			{
				alert("Invalid Error Message in Error Array >"+xiErrorArray[i]+"<");
				return false
			}
			
			// Now process it
			eval(FunctionStr);
		}
	}
	else
	{
		alert("The following VALIDATION errors occured: \n\n\t"+xiErrorArray.join('\n\n\t'));
	}
	
	return true;
}

/*******************************************************************************
*
*	Scope		:	PUBLIC
*	Function	:	ValidatePageDefn()
*
*	Purpose		:	Validates and completes the structure of the 
*				FNI Page Defn for this page/validation
*
*	Parameters	:	xiPageVersion 	The Calling page will pass a version
*						to ensure that the PageDef and the Page
*						are in sync.
*				xcPageDefn	Pointer to the PageDefn structure 
*						supplied by FNI for this page
*
*	Returns		:	boolean:	true	if valid
*						fail	otherwise
*
*	JavaScript	:	1.3
*
*	Assumptions	:	
*
*
*******************************************************************************/
function ValidatePageDefn(xiPageVersion, xcPageDefn )
{
	/*
	 * Run through the xcPageDefn passed. 
	 * This will be the PageDef generated by FNI for the particular web page
	 */

	var ElementControl = new Object();

	var PageDefnObj = new Object()
	var TestRegex = new RegExp()

	// Check the passsed arguments
	if(arguments.length < 2)
	{
		alert("ValidatePageDefn Function expects 2 arguments: ValidatePageDefn(xiPageVersion,xcPageDefn)") ;
		return false;
	}

	// Check the version of the page Def meets the version of the page
	if (xcPageDefn.Version != xiPageVersion)
	{
		alert("The page version ("+xiPageVersion+") and the page definition ("+xcPageDefn.Version+") do not match!");
		return false;
	}	

	xcPageDefn.Valid=false;

	// For each SubObject in the PageDefn
	for ( SubObj in xcPageDefn )
	{
		PageDefnObj=xcPageDefn[SubObj];

		if (PageDefnObj)
		{
			// Set the Type to String if it is not defined for this Object
			if (!PageDefnObj.Type)
				PageDefnObj.Type = "STRING"
			else if (!((PageDefnObj.Type == "INT") || (PageDefnObj.Type == "FLOAT") || (PageDefnObj.Type == "STRING")))
			{
				alert("Invalid Type >"+PageDefnObj.Type+"< passed for object "+SubObj);
				return false 
			}

			// Set the Cardinality to single if it is not defined for this Object
			if (!PageDefnObj.Cardinality)
				PageDefnObj.Cardinality = "SINGLE"
			else if (!((PageDefnObj.Cardinality == "SINGLE") || (PageDefnObj.Cardinality == "LIST")))
			{
				alert("Invalid Cardinality >"+PageDefnObj.Cardinality+"< passed");
				return false 
			}

			// Set the Mandatory to Yes if it is not defined for this Object
			if (!PageDefnObj.Mandatory)
				PageDefnObj.Mandatory = "YES"
			else if (!((PageDefnObj.Mandatory == "YES") || (PageDefnObj.Mandatory == "NO")))
			{
				alert("Invalid Mandatory >"+PageDefnObj.Mandatory+"< passed");
				return false 
			}

			if (PageDefnObj.Cardinality != "SINGLE")
			{
				if (PageDefnObj.Min_elts)
					if (!PageDefnObj.Min_elts.match(/^\d+$/))
					{
						alert("Invalid Min_elts >"+PageDefnObj.Min_elts+"< passed");
						return false 
					}

				if (PageDefnObj.Max_elts)
					if (!PageDefnObj.Max_elts.match(/^\d+$/))
					{
						alert("Invalid Max_elts >"+PageDefnObj.Max_elts+"< passed");
						return false 
					}
	
			}
			// Set the Description for this Object
			if (!PageDefnObj.Description)
				PageDefnObj.Description = SubObj;

			// Set the Suppress to NO if it is not defined for this Object
			if (!PageDefnObj.Suppress)
				PageDefnObj.Suppress = "NO"
			else if (!((PageDefnObj.Suppress == "YES") || (PageDefnObj.Suppress == "NO")))
			{
				alert("Invalid Suppress >"+PageDefnObj.Suppress+"< passed");
				return false 
			}

			// Check and set the NullOK for this Object
			if ((PageDefnObj.NullOK) && !((PageDefnObj.NullOK == "YES") || (PageDefnObj.NullOK == "NO")))
			{
				alert("Invalid NullOK >"+PageDefnObj.NullOK+"< passed");
				return false 
			}

			// Check and set the EmptyOK for this Object
			if ((PageDefnObj.EmptyOK) && !((PageDefnObj.EmptyOK == "YES") || (PageDefnObj.EmptyOK == "NO")))
			{
				alert("Invalid EmptyOK >"+PageDefnObj.EmptyOK+"< passed");
				return false 
			}

			if (PageDefnObj.Validate)
			{
				if (PageDefnObj.Validate == "RANGE")
				{
					if(PageDefnObj.MinVal)
					{
						if ((((PageDefnObj.Type == 'INT') && !(PageDefnObj.MinVal.match(/^-?\d*$/))) ||
							((PageDefnObj.Type == 'FLOAT') && !(PageDefnObj.MinVal.match(/^-?\d*\.?\d*$/)))))
						{
							alert("Invalid MinVal >"+PageDefnObj.MinVal+"< for field "+SubObj) ;
							return false;
						}
					}

					if(PageDefnObj.MaxVal)
					{
						if ((((PageDefnObj.Type == 'INT') && !(PageDefnObj.MaxVal.match(/^-?\d*$/))) ||
							((PageDefnObj.Type == 'FLOAT') && !(PageDefnObj.MaxVal.match(/^-?\d*\.?\d*$/)))))
						{
							alert("Invalid MaxVal >"+PageDefnObj.MaxVal+"< for field "+SubObj) ;
							return false;
						}
					}
				}
				else if(PageDefnObj.Validate == "ENUM")
				{
					if (!PageDefnObj.Values)
					{
						alert("No values supplied for ENUM field "+SubObj) ;
						return false;
					}
				}
				else if(PageDefnObj.Validate == 'REGEX')
				{
					if (!PageDefnObj.Expression)
					{
						alert("No Expression supplied for REGEX field "+SubObj) ;
						return false;
					}
				}
				else
				{
					alert("Invalid validation >"+PageDefn.Validate+"< suppplied for "+SubObj) ;
					return false;
				}
			}
		} // End PageDefn processing
	} // End for LOOP
	
	// All tests have passed and the PageDef is valid.
	xcPageDefn.Valid=true;
	return true;
}

/*******************************************************************************
*
*	Scope		:	PUBLIC
*	Function	:	ValidateElement()
*
*	Purpose		:	Validates the controls on the page that match
*				the PageDef element requested.
*				If the PageDef has not been validated, it will first
*				call the validation routines.
*
*				If a xiFunction has been passed this function will be
*				called when a validation error occurs.
*	
*	Parameters	:	xiPageVersion 	The Calling page will pass a version
*						to ensure that the PageDef and the Page
*						are in sync.
*
*				xiElement	Name of the element to be validated.
*
*				xiForm		Name of the form being submitted
*
*				xcPageDefn	Pointer to the PageDefn structure 
*						supplied by FNI for this page
*
*				xiWebPage	document object for this page.
*
*				xiFunction	OPTIONAL - Function to call when a
*						validation error occurs.
*
*	Returns		:	boolean:	true	if valid
*						fail	otherwise
*
*	JavaScript	:	1.3
*
*	Assumptions	:	xiFunction if passed is defined and valid in the page object.
*
*
*******************************************************************************/

function ValidateElement(xiPageVersion, xiElement, xiForm, xcPageDefn, xiWebPage, xiFunction )
{
	/*
	 * Validate the data on a page
	 */

	var ElementControl = new Object();

	var PageDefnObj = new Object()
	var ErrorArray = new Array()


	if ((!xcPageDefn.Valid) ||  (xcPageDefn.Valid != true))
	{
		if (!ValidatePageDefn(xiPageVersion,xcPageDefn))
		{
			return false;
		}
	}

	PageDefnObj = xcPageDefn[xiElement];

	// Proces the validation for the object on the page
	if (PageDefnObj)
	{
		if (!ValidateObject(xiElement,xiForm,PageDefnObj,xiWebPage,ErrorArray))
		{
			AlertOrFn(ErrorArray, xiFunction)
			return false;
		}
		else
			return true;
	
	}
	else
		return true;
}

/*******************************************************************************
*
*	Scope		:	PUBLIC
*	Function	:	ValidatePage()
*
*	Purpose		:	Validates all the controls on the page that match
*				the PageDef elements. 
*				If the PageDef has not been validated, it will first
*				call the validation routines.
*
*				If a xiFunction has been passed this function will be
*				called when a validation error occurs.
*	
*	Parameters	:	xiPageVersion 	The Calling page will pass a version
*						to ensure that the PageDef and the Page
*						are in sync.
*
*				xiForm		Name of the form being submitted
*
*				xcPageDefn	Pointer to the PageDefn structure 
*						supplied by FNI for this page
*
*				xiWebPage	document object for this page.
*
*				xiFunction	OPTIONAL - Function to call when a
*						validation error occurs.
*
*	Returns		:	boolean:	true	if valid
*						fail	otherwise
*
*	JavaScript	:	1.3
*
*	Assumptions	:	xiFunction if passed is defined and valid in the page object.
*
*
*******************************************************************************/
function ValidatePage( xiPageVersion, xiForm, xcPageDefn, xiWebPage, xiFunction )
{
	/*
	 * Validate the data on a page
	 */

	var ElementControl = new Object();

	var PageDefnObj = new Object()
	var ErrorArray = new Array()
	var ErrorFound = false;
	var FunctionStr;


	// Validate the PageDefn if it has not yet been validated.
	if ((!xcPageDefn.Valid) ||  (xcPageDefn.Valid != true))
		if (!ValidatePageDefn(xiPageVersion,xcPageDefn))
			return false;

	
	// For each object in the page defn
	for ( SubObj in xcPageDefn )
	{
		if ((SubObj == 'Version') || (SubObj == 'Valid'))
			continue;

		PageDefnObj=xcPageDefn[SubObj];
//		alert("About to Validate "+SubObj)
		// Proces the validation for the object on the page
		if (PageDefnObj)
		{
			if (!ValidateObject(SubObj,xiForm,PageDefnObj,xiWebPage,ErrorArray))
				ErrorFound = true;

		}
	}

	if (ErrorFound)
	{

		AlertOrFn(ErrorArray, xiFunction);
		return false;
	}
	else
	{
		return true;
	}

}

/*******************************************************************************
*
*	Scope		:	PRIVATE
*	Function	:	ValidateObject()
*
*	Purpose		:	Validates the controls on the page that match
*				the element requested.
*
*	
*	Parameters	:	xiSubObj	Name of the current object to be 
*						validated.
*
*				xiFormName	Name of the form being submitted
*
*				xiPageDefnObj	Pointer to the PageDefnObj 
*
*				xiWebPage	document object for this page.
*
*				xcError		ErrorArray object
*
*	Returns		:	boolean:	true	if valid
*						fail	otherwise
*
*	JavaScript	:	1.3
*
*	Assumptions	:	
*
*
*******************************************************************************/
function ValidateObject(xiSubObj, xiFormName, xiPageDefnObj, xiWebPage, xcError)
{
		
	var FormObj = new Object();
	var ElementArray = new Array();	
	var ElementFound = false;
	var ErrorsFound = false;
	var ElementControl = new Object();

	if (xiFormName == "")
	{
		xcError[xcError.length]="Form name not supplied.";
		return false;
	}
	
	// Find the Form on the Page
	FormObj= xiWebPage.getElementById(xiFormName)
	if (!FormObj)
	{	
		alert("Could not find FORM >"+xiFormName+"< on page.");
		return false;
	}
	
	

	//alert("Using Form >"+FormObj.Name+"<");
	if (FormObj.elements)
	{
		ElementArray = FormObj.elements;
		
		for ( i=0 ; i < ElementArray.length ; i++)
		{
			// If this is the SubObj we are looking for
			//alert("Found >"+ElementArray[i].name+"< and checking against >"+xiSubObj);
			
			//alert("xiSubObj>"+xiSubObj+"< ElementArray.id>"+ElementArray[i].id+"< Returns>"+xiSubObj.indexOf(ElementArray[i].id)+"<");

			if (!ElementArray[i].id.indexOf(xiSubObj))
			{
//				alert("Processing Element >"+ElementArray[i].id+"<");
				// Find the Object on the page
				ElementControl = ElementArray[i];
				if (ElementControl)
				{
					// If this is a checkbox or radiobutton and its not checked then we've not got output... just continue
					if ((ElementControl.type) && ((ElementControl.type == 'checkbox') || (ElementControl.type == 'radiobutton')))
					{
						// If it is not checked then there is nothing to process.
						if (ElementControl.checked == false )
							continue;
					}

					// Now we are sure we have an element to validate
					ElementFound = true;
					
					// If it has a value then get it
					if (ElementControl.value)
						xiPageDefnObj.Value = ElementControl.value;
					else if(xiPageDefnObj.Value)
						xiPageDefnObj.Value = null;

				}
				
				/*
				 * 	Now that we have the object and its value - Validate it!
				 *
				 * 	If there is a defined value, check it against type and translate
				 *	empty values if an EmptyVal has been specified. Translate empty numerics
				 *	to undef
				 */
				//alert("Object >"+xiSubObj+"< Value >"+xiPageDefnObj.Value+"< Type >"+xiPageDefnObj.Type+"<");
				if(xiPageDefnObj.Value)
				{
				
					if (xiPageDefnObj.Type == 'INT') 
					{
						if  (!xiPageDefnObj.Value.match(/^-?\d*$/))
						{
							xcError[xcError.length]=ElementControl.id+": Invalid INT Value >"+xiPageDefnObj.Value+"< for field "+xiPageDefnObj.Description;
							ErrorsFound=true;
							continue;
						}
					}
					else if (xiPageDefnObj.Type == 'FLOAT') 
					{
						if (!xiPageDefnObj.Value.match(/^-?\d*\.?\d*$/))
						{
							xcError[xcError.length]=ElementControl.id+": Invalid FLOAT Value >"+xiPageDefnObj.Value+"< for field "+xiPageDefnObj.Description;
							ErrorsFound=true;
							continue;
						}
					}
					else if(xiPageDefnObj.Type != 'STRING')
					{
						xiPageDefnObj.Value = undef;
					}
					// NOTE: STRING cleaning and validation will happen at the server.

					//	If it is undefined or empty see if they have specified what to do
					if (xiPageDefnObj.Value.length < 1)
					{
						if(xiPageDefnObj.EmptyOK)
							if(xiPageDefnObj.EmptyOK == 'NO')
							{
								xcError[xcError.length]=ElementControl.id+": Empty Invalid for field "+xiPageDefnObj.Description ;
								ErrorsFound=true;
								continue;
							}
					}
				}
				else
				{
					if(xiPageDefnObj.EmptyOK)
					{
						if(xiPageDefnObj.EmptyOK == 'NO') 
						{
							xcError[xcError.length]=ElementControl.id+": Empty is invalid for field "+xiPageDefnObj.Description;
							ErrorsFound=true;
							continue;
						}
					}

					if(xiPageDefnObj.NullOK)
					{
						if((xiPageDefnObj.NullOK == 'NO') && ((!xiPageDefnObj.Value) || (xiPageDefnObj.Value == null)))
						{
							xcError[xcError.length]=ElementControl.id+": NULL is invalid for field "+xiPageDefnObj.Description;
							ErrorsFound=true;
							continue;
						}
					}
					// Dont return.... contiune
					continue;
				}

				// If a Validation is defined
				if(xiPageDefnObj.Validate)
				{
					if(xiPageDefnObj.Validate == 'RANGE')
					{
						var	compare;

						//	If they have defined a min or max, a null is out of range
						if(((!xiPageDefnObj.Value) || (xiPageDefnObj.Value == null)) && 
							((xiPageDefnObj.MinVal) || (xiPageDefnObj.MaxVal)))
						{
							xcError[xcError.length]= ElementControl.id+": "+xiPageDefnObj.Description+" is NULL and not in range" ;
							ErrorsFound=true;
							continue;
						}
						if(xiPageDefnObj.MinVal)
						{
							if (xiPageDefnObj.Type == 'STRING')
								compare = ( xiPageDefnObj.Value < xiPageDefnObj.MinVal )
							else
								compare = ( parseFloat(xiPageDefnObj.Value) < parseFloat(xiPageDefnObj.MinVal));

							if(compare ==true )
							{
								xcError[xcError.length]= ElementControl.id+": "+xiPageDefnObj.Description+" value >"+xiPageDefnObj.Value+"< is less than the min allowed -"+xiPageDefnObj.MinVal ;
								ErrorsFound=true;
								continue;
							}
						}
						if(xiPageDefnObj.MaxVal)
						{
							if (xiPageDefnObj.Type == 'STRING')
								compare = ( xiPageDefnObj.Value < xiPageDefnObj.MinVal )
							else
								compare = ( parseFloat(xiPageDefnObj.Value) > parseFloat(xiPageDefnObj.MaxVal));
							if(compare ==true )
							{
								xcError[xcError.length]=ElementControl.id+": "+xiPageDefnObj.Description+" value >"+xiPageDefnObj.Value+"< is greater than the max allowed -"+xiPageDefnObj.MaxVal ;
								ErrorsFound=true;
								continue;
							}
						}
					}
					else if(xiPageDefnObj.Validate == 'ENUM')
					{
						//	Check the field value against allowable
						// Convert the Values to an Array of values
						var ValString = new Array();
						ValString = xiPageDefnObj.Values.split(",");

						for ( i=0 ; i < ValString.length ; i++)
						{
							if(xiPageDefnObj.Value == ValString[i])
							{
								//	found a match
								continue;
							}
						}

						xcError[xcError.length]= ElementControl.id+": "+xiPageDefnObj.Description+" value >"+xiPageDefnObj.Value+"< is not a known value" ;
						ErrorsFound=true;
						continue ;
					}
					else if(xiPageDefnObj.Validate =="REGEX" )
					{
						if (xiPageDefnObj.Expression) 
						{
							//	Run the regex over the field value
							if (!xiPageDefnObj.Value.match(xiPageDefnObj.Expression))
							{
								xcError[xcError.length]= ElementControl.id+": "+xiPageDefnObj.Description+" value >"+xiPageDefnObj.Value+"< is not valid for the expression ["+xiPageDefnObj.Expression+"]";
								ErrorsFound=true;
								continue;
							}
						}
					}
					// NOTE: No validation for "FUNCTION" provided at the Front End
				}
			}  // Element found processing
		
		} // End For Elements loop
	
		if (!ElementFound)
			// Couldnt find the Object but it is mandatory... its not going to work!
			if (xiPageDefnObj.Mandatory == "YES")
			{
				xcError[xcError.length]="MANDATORY Object>"+xiPageDefnObj.Description+"< NOT FOUND in Page";
				return false;
			}

	}
	else
	{
		xcError[xcError.length]="Form name supplied not found on page.";
		return false;
	}

	return !ErrorsFound;
}

/*******************************************************************************
*
*	Scope		:	PRIVATE
*	Function	:	ValidateObject()
*
*	Purpose		:	Validates the controls on the page that match
*				the element requested.
*
*	
*	Parameters	:	xiSubObj	Name of the current object to be 
*						validated.
*
*				xiFormName	Name of the form being submitted
*
*				xiPageDefnObj	Pointer to the PageDefnObj 
*
*				xiWebPage	document object for this page.
*
*				xcError		ErrorArray object
*
*	Returns		:	boolean:	true	if valid
*						fail	otherwise
*
*	JavaScript	:	1.3
*
*	Assumptions	:	
*
*
*******************************************************************************/
function PrintElement( xiElement,  xcPageDefn )
{
	/*
	 * Print the validation requirements of the PageDef Object`
	 */

	var PageDefnObj = new Object()
	var ElementStr;


	if (!xcPageDefn)
	{
		document.write("Invalid Object");
		return
	}

	PageDefnObj = xcPageDefn[xiElement];

	// Proces the validation for the object on the page
	if (PageDefnObj)
	{
		if (PageDefnObj.Mandatory)
			ElementStr=" Mandatory: "+PageDefnObj.Mandatory;
		else
			ElementStr=" *Mandatory: NO";

		if (PageDefnObj.Type)
			ElementStr+=" Type: "+PageDefnObj.Type;
		else
			ElementStr+=" *Type: STRING";
	
		if (PageDefnObj.EmptyOk)
			ElementStr+=" EmptyOk: "+PageDefnObj.EmptyOk;
		else
			ElementStr+=" *EmptyOk: YES";
	
		if (PageDefnObj.NullOk)
			ElementStr+=" NullOk: "+PageDefnObj.NullOk;
		else
			ElementStr+=" *NullOk: YES";
	
		if (PageDefnObj.Validate)
		{
			ElementStr+=" Validate: "+PageDefnObj.Validate;
			if (PageDefnObj.Validate == "REGEX")
			{
				if (PageDefnObj.Expression)
					ElementStr+=" Expression: "+PageDefnObj.Expression;
			}
			else if (PageDefnObj.Validate == "RANGE")
			{
				if (PageDefnObj.MinVal)
					ElementStr+=" MinVal: "+PageDefnObj.MinVal;
				else
					ElementStr+=" MinVal: undefined";

				if (PageDefnObj.MaxVal)
					ElementStr+=" MaxVal: "+PageDefnObj.MaxVal;
				else
					ElementStr+=" MaxVal: undefined";
					
			}
					
		}
	
		if (PageDefnObj.Cardinality)
			ElementStr+=" Cardinality: "+PageDefnObj.Cardinality;
		else
			ElementStr+=" *Cardinality: SINGLE";
	
	}
	else
		ElementStr = "<em>Element >"+xiElement+"< not found in PageDef!</em>"
	
	document.write(ElementStr)
}


