// <![CDATA[

// Master function that validates form
// Parameters
// - validate - Array of form feilds to validate
// - parentID - Parent element ID of form fields ( Defaults to document )
// - type - Error display type <HTML, alert> ( Defaults to HTML )
// - prefix - Prefix for error list ( Defaults to <li> )
// - suffix - Suffix for error list ( Defaults to </li> )
// - linkError - Specify errors should be linked or not <true/false>

function GetFormErrors( validate, parentId, type, prefix, suffix, linkError ) {

	// Array which will holds the list of generated errors
	var errors = new Array();

	// Array which will holds the default configuration
	var defaults = new Array();

	// Set default TYPE
	if ( !type )
		defaults['type'] = 'HTML';
	else
		defaults['type'] = type;

	// Set default PREFIX
	if ( defaults['type'] == 'HTML' && !prefix )
		defaults['prefix'] = '<li>';
	else if ( !prefix )
		defaults['prefix'] = '- ';
	else
		defaults['prefix'] = prefix;

	// Set default SUFFIX
	if ( defaults['type'] == 'HTML' && !suffix )
		defaults['suffix'] = '</li>';
	else if ( !suffix )
		defaults['suffix'] = '';
	else
		defaults['suffix'] = suffix;

	// Set default LINKERROR
	if ( defaults['type'] == 'HTML' && !linkError )
		defaults['linkError'] = true;
	else
		defaults['linkError'] = false;

	// Get all the <elements> in parentId; sorted as they exist in HTML
	var elementsList = GetSortedElements( 'input,textarea,select,button', parentId );

	// Loop through each <element> found in parentId
	for( var i = 0; i < elementsList.length; i++ ){

		// Get the current <element> in loop
		var element = elementsList[i];

		// Check if the current <element> exists in validate array
		if( validate[element.name] ) {

			// Set <element> name in default
			defaults['fieldName'] = element.name;

			// Validate <Text/Textarea> elements
			if( element.type == 'text' || element.type == 'textarea' || element.type == 'password' ) {
				
				// Trim <element> value
				element.value = Trim( element.value );

				// If <element> is REQUIRED
				if( validate[element.name]['required'] && !IsEmpty( element.value ) ) {
					errors[errors.length] = FormatError( validate[element.name]['required'], defaults );
					continue;	
				}

				// If <element> has valid EMAIL ADDRESS
				if( validate[element.name]['email'] && !IsEmail( element.value ) ) {
					errors[errors.length] = FormatError( validate[element.name]['email'], defaults );
					continue;
				}

				// If <element> has valid USER ID
				if( validate[element.name]['userId'] && !IsUserId( element.value ) ) {
					errors[errors.length] = FormatError( validate[element.name]['userId'], defaults );
					continue;
				}

				// If <element> has valid NUMERIC LENGTH
				if( ( validate[element.name]['number'] || validate[element.name]['float'] || validate[element.name]['negNumber'] ) && validate[element.name]['len'] && ( ( validate[element.name]['min'] && element.value < validate[element.name]['min'] ) || ( validate[element.name]['max'] && element.value > validate[element.name]['max'] ) ) ) {
					errors[errors.length] = FormatError( validate[element.name]['len'], defaults );

				// If <element> has valid STRING LENGTH
				} else if ( ( !validate[element.name]['number'] && !validate[element.name]['float'] && !validate[element.name]['negNumber'] ) && validate[element.name]['len'] && ( ( validate[element.name]['min'] && !IsValidLength( element.value, validate[element.name]['min'], 0 ) ) || ( validate[element.name]['max'] && !IsValidLength( element.value, 0, validate[element.name]['max'] ) ) ) ) {
					errors[errors.length] = FormatError( validate[element.name]['len'], defaults );
				}

				// If <element> has valid NUMERIC VALUE
				if( validate[element.name]['number'] && !IsNumeric( element.value ) )
					errors[errors.length] = FormatError( validate[element.name]['number'], defaults );

				// If <element> has valid FLOAT VALUE
				if( validate[element.name]['float'] && !IsNumeric( element.value, 'float' ) )
					errors[errors.length] = FormatError( validate[element.name]['float'], defaults );

				// If <element> has valid -ve INTEGER/FLOAT VALUE
				if( validate[element.name]['negNumber'] && !IsNumeric( element.value, 'negNumber' ) )
					errors[errors.length] = FormatError( validate[element.name]['negNumber'], defaults );

				// If <element> has valid ALPHABETIC
				if( validate[element.name]['alpha'] && !IsAlphabetic( element.value ) )
					errors[errors.length] = FormatError( validate[element.name]['alpha'], defaults );

				// If <element> has valid ALPHANUMERIC
				if( validate[element.name]['alphaNum'] && !IsAlphaNumeric( element.value ) )
					errors[errors.length] = FormatError( validate[element.name]['alphaNum'], defaults );

			}

			// Validate <Select/select-one> elements
			else if ( element.type == 'select' || element.type == 'select-one' ) {

				// Trim <element> value
				element.options[element.selectedIndex].value = Trim( element.options[element.selectedIndex].value );

				// If <element> is REQUIRED
				if ( validate[element.name]['required'] && !IsEmpty( element.options[element.selectedIndex].value ) )
					errors[errors.length] = FormatError( validate[element.name]['required'], defaults );
			}

			// Validate <Select-Multiple> elements
			else if ( element.type == 'select-multiple' ) {

				// No. of <option> selected
				selectedLength = 0;

				// Loop through each <option>
				for ( var j = 0; j < element.options.length; j++ ) {
					if ( element.options[j].selected )
						selectedLength++;
				}

				// If <element> is REQUIRED
				if ( validate[element.name]['required'] && selectedLength < 1 ) {
					errors[errors.length] = FormatError( validate[element.name]['required'], defaults );
					continue;
				}

				// If <element> has valid SELECTED LENGTH
				if( validate[element.name]['len'] && ( ( validate[element.name]['min'] && selectedLength < validate[element.name]['min'] ) || ( validate[element.name]['max'] && selectedLength > validate[element.name]['max'] ) ) )
					errors[errors.length] = FormatError( validate[element.name]['len'], defaults );
			}

			// Validate <Checkbox> elements
			else if ( element.type == 'checkbox' ) {

				// If <element> is REQUIRED
				if ( validate[element.name]['required'] && !validate[element.name]['min'] && !element.checked )
					errors[errors.length] = FormatError( validate[element.name]['required'], defaults );
					
				// If multile <checkbox>
				if( validate[element.name]['required'] && validate[element.name]['min'] ) {

					// Get the checkboxGroup
					var checkboxGroup = document.getElementsByName(element.name);
				
					var checkedCheckbox = 0;
		
					for (var checkboxIndex = 0; checkboxIndex < checkboxGroup.length; checkboxIndex++ ) {
						if ( checkboxGroup[checkboxIndex].checked == true ) {
							checkedCheckbox++;
							break;
						}
					}

					// show error if flag group as having been tested
					if ( checkedCheckbox < validate[element.name]['min'] && !validate[element.name]['tested'] ) {
						errors[errors.length] = FormatError( validate[element.name]['required'], defaults );
						validate[element.name]['tested'] = true;
					}
				}					
			}

			// Validate <radio> elements
			else if ( element.type == "radio" ) {
				
				// Get the RadioGroup
				var radioGroup = document.getElementsByName(element.name);
				
				if( validate[element.name]['required'] ) {
				
					var checkedRadioButton = -1;
		
					for (var radioIndex = 0; radioIndex < radioGroup.length; radioIndex++ ) {
						if ( radioGroup[radioIndex].checked == true ) {
							checkedRadioButton = radioIndex;
							break;
						}
					}

					// show error if flag group as having been tested
					if ( checkedRadioButton == -1 && !validate[element.name]['tested'] ) {
						errors[errors.length] = FormatError( validate[element.name]['required'], defaults );
						validate[element.name]['tested'] = true;
					}
				}
			}

			// Validate <Checkbox> elements
			else if ( element.type == 'file' ) {

				// If <element> is REQUIRED
				if ( validate[element.name]['required'] && !IsEmpty( element.value ) )
					errors[errors.length] = FormatError( validate[element.name]['required'], defaults );
			}

		}
	}

	return DispFormErrors( errors, defaults['type'] );
}

// Function to display error messages
function DispFormErrors( errors, type ) {

	var errorMessage = '';

	if( errors.length > 0 && type == 'HTML' ) {

		for ( var errorIndex = 0; errorIndex < errors.length; errorIndex++ ) {
			errorMessage += errors[errorIndex] + '\n';
		}
		
		errorMessage = '<legend>Error!</legend><ul>' + errorMessage + '</ul>';

		var errorDiv = document.getElementById( 'error' );
		errorDiv.style.display = 'block';
		errorDiv.innerHTML = '';
		errorDiv.innerHTML = errorMessage;
		window.location.hash = 'content';

		return false;
	}
	
	else if ( errors.length > 0 && type == 'alert'  ) {

		for ( var errorIndex = 0; errorIndex < errors.length; errorIndex++ ) {
			errorMessage += errors[errorIndex] + '\n';
		}

		alert( errorMessage );

		return false;
	}

	return true;
}

// Function to format the error messages
function FormatError( errorMessage, defaults ){
	if( defaults['type'] == 'HTML' )
		return defaults['prefix'] + '<a href=\'#' + defaults['fieldName'] + '\' title=\'Error!\'>' + errorMessage + '</a>' + defaults['suffix'];
	else
		return defaults['prefix'] + errorMessage + defaults['suffix'];
}

// Function to get all elements specified in tagList under parentId in the order as they exist in HTML page
// tagList - Comma-seperated list of tag names
// parentId - Parent element ID to search for specified tags ( defaults to document )

function GetSortedElements( tagList, parentId ) {

	// Get the parent element
	if( !parentId )
		parentId = document;
	else
		parentId = document.getElementById( parentId );

	// Get array of tags to sort
	var tagNames = tagList.split( ',' );
	var elementsArray = new Array();

	// Loop through each tag
	for ( var i = 0; i < tagNames.length; i++ ) {
		var tags = parentId.getElementsByTagName( tagNames[i] );

		// If specified tag exist, get all elements of that tag in elementsArray
		for ( var j=0; j < tags.length; j++ ) {
			elementsArray.push( tags[j] );
		}
	}

	// Return if no element found
	var testNode = elementsArray[0];
	if ( !testNode )
		return [];

	// Checking if browser supports sourceIndex
	if ( testNode.sourceIndex ) {
		elementsArray.sort(function (a,b) {
				return a.sourceIndex - b.sourceIndex;
		});
	}

	// Checking if browser supports compareDocumentPosition
	else if ( testNode.compareDocumentPosition ) {
		elementsArray.sort(function (a,b) {
				return 3 - (a.compareDocumentPosition(b) & 6);
		});
	}

	return elementsArray;
}

// Function to check that the supplied string is EMPTY
function IsEmpty( elementValue ) {

	// Trim value
	elementValue = Trim( elementValue );

	if( elementValue.length == 0 || elementValue == null || elementValue == '' )
		return false;
	else
		return true;
}

// Function to check that the supplied string contains only NUMBERS
function IsNumeric( elementValue, type ) {

	if( !IsEmpty( elementValue ) )
		return true;

	// Trim value
	elementValue = Trim( elementValue );
	
	if ( type == 'negNumber' && !elementValue.toString().match(/^[-]?\d*$/) )
		return false;
	
	if ( type == 'float' && !elementValue.toString().match(/^[-]?\d*\.?\d*$/) )
		return false;
	
	if ( !type && !elementValue.toString().match(/^\d*$/) )
		return false;
		
	return true;
}

// Function to check that the supplied string contains only ALPHABETS
function IsAlphabetic( elementValue ) {

	if( !IsEmpty( elementValue ) )
		return true;

	// Trim value
	elementValue = Trim( elementValue );

	return ( elementValue.toString().match(/^([a-zA-Z\s]+)$/) )
}

// Function to check that the supplied string contains only ALPHABETS & NUMBERS
function IsAlphaNumeric( elementValue ) {

	if( !IsEmpty( elementValue ) )
		return true;

	// Trim value
	elementValue = Trim( elementValue );

	return ( elementValue.toString().match(/^([a-zA-Z0-9\s]+)$/) )
}

// Function to check that the supplied string is a valid EMAIL ID
function IsEmail( elementValue ) {

	if( !IsEmpty( elementValue ) )
		return true;

	// Trim value
	elementValue = Trim( elementValue.toLowerCase() );
	return ( elementValue.indexOf( '.' ) > 0 && elementValue.indexOf( '@' ) > 0  );
}

// Function to check that the supplied string is a valid USER ID
function IsUserId( elementValue ) {

	if( !IsEmpty( elementValue ) )
		return true;

	// Trim value
	elementValue = Trim( elementValue );

	return ( elementValue.toString().match(/^([\.a-zA-Z0-9_-]+)$/) )
}

// Function to check that the supplied string has valid MIN & MAX LENGTH
function IsValidLength( elementValue, minlen, maxlen ) {

	// Trim <element> value
	// Convert to STRING
	elementValue = Trim( elementValue.toString() );

	if( minlen && elementValue.length < minlen )
		return false;

	if ( maxlen && elementValue.length > maxlen )
		return false;

	return true;
}

// Function to TRIM the supplied string
function Trim( elementValue ) {
	return elementValue.replace(/^\s+|\s+$/g,'');
}

// Function to LEFT TRIM the supplied string
function LTrim( elementValue ) {
	return elementValue.replace(/^\s+/,'');
}

// Function to RIGHT TRIM the supplied string
function RTrim( elementValue ) {
	return elementValue.replace(/\s+$/,'');
}

//]]>
