/**
*	CBC.CA - Canada Writes '07 - Form Validation
*	@author	gordongroup marketing + communications (www.gordongroup.com)
*	@package	CBC-CanadaWrites
*/
 
 
/**
*	Initialise the forms on window load
*	@access	public
*	@return	void
*/
window.onload = function(){
	if( document.getElementById ){
		Validation.init( 'entryForm', notValidCallback, validCallback );
		Validation.init( 'faqForm', notValidCallback, validCallback );
		
		// Set up text limiter for submission
/*		if( document.getElementById('submission') ){
			var totalChars = 1500;
			var sub = document.getElementById('submission');
			var theEvent = function(){ textCounter( 'submission', 'counter', totalChars ); };
			var theBlurEvent = function(){
				textCounter( 'submission', 'counter', totalChars );
				document.getElementById('counter').innerHTML = '(200 words max.,<br />'+totalChars+' characters left)';
			};
			sub.onblur = theBlurEvent;
			sub.onfocus = theEvent;
			sub.onkeypress = theEvent;
			sub.onkeyup = theEvent;
		}
*/
	}
	
	//document.getElementById( 'submit' ).onclick = function(){ Validation.validate( 'entryForm', notValidCallback, validCallback ); };
}
 
 
/**
*	Callback function for setting fields invalid
*	@access	public
*	@param	object	p_obj	the object containing the values of the form data
*	@return	void
*/
function notValidCallback( p_obj ){
	var node = document.getElementById( p_obj.id ).parentNode;
	
	if( node.className.indexOf( 'invalid' ) == -1 ){
		node.className += ' invalid';	
	}
	
	var formInfo = document.getElementById( 'formInfo' );
	formInfo.className = 'validationError';
	formInfo.innerHTML = 'Please complete <strong>ALL</strong> form fields below.';
	
}
 
 
/**
*	Callback function for setting fields valid
*	@access	public
*	@param	object	p_obj	the object containing the values of the form data
*	@return	void
*/
function validCallback( p_obj ){
	var className = document.getElementById( p_obj.id ).parentNode.className;
	document.getElementById( p_obj.id ).parentNode.className = className.replace( /invalid/, '' );
	
//	var formInfo = document.getElementById( 'formInfo' );
//	formInfo.className = 'mandatory';
//	formInfo.innerHTML = 'All fields are mandatory.';
}
 
 
/**
*	An object-class for validating the entry form.
*	@package	CBC-CanadaWrites
*	@subpackage	common
*	@todo 	make some sort of check so radio buttons are looped over so many times
*	@todo 	clean up the default values code
*/
var Validation = function(){
 
	// PROPERTIES
	
	/**
	*	Holds all the values of the inputs prior to the form being filled out
	*	@access	private
	*	@var	object
	*/
	var formValues = new Object();
	
	
	
	// PUBLIC METHODS
 
	var publicMethods = {
		
		/**
		*	Initialises the form, by adding an onsubmit action
		*	Tracks all the starting values to compare
		*	@access	public
		*	@param	string	p_form	the form to attach the function to
		*	@return	false
		*/
		init:function( p_form, p_inValidCallback, p_ivalidCallback ){
			if( document.getElementById( p_form ) ){
				/*document.getElementById( p_form ).onsubmit = function(){
					return Validation.validate( p_form, p_inValidCallback, p_validCallback );
				};*/
 
				var form = document.getElementById( p_form );
				var inputs = collectionToArray( form.getElementsByTagName( 'input' ) );
				var textAreas = collectionToArray( form.getElementsByTagName( 'textarea' ) );
			
				var totalTextAreas = textAreas.length;
				if( totalTextAreas == 1 ){
					inputs.push( textAreas[0] );
				}else{
					inputs.concat( textAreas );
				}
			
				var totalFields = inputs.length;
			
				if( totalFields <= 0 ) {
					return true;
				}
 
				for( var i=0; i<totalFields; i++ ){
 
					var theType = inputs[i].type;
					if( theType.trim() == '' || theType == null ){ theType = 'text'; }
 
					var element = inputs[i].id;				
					var theValue = inputs[i].value;
				
					if( theType != 'button' && theType != 'submit' ){
						formValues[ element ] = theValue;
					}
				
				}
 
 
			}
		}, // END METHOD: init
		
		
		/**
		*	Validates the form
		*	@access	public
		*	@param	string	p_form	the form to validate
		*	@param	string	p_inValidCallback	the function to call if an element is invalid
		*	@param	string	p_validCallback	the function to call if an element is valid
		*	@return bool
		*/
		validate:function( p_form, p_inValidCallback, p_validCallback ){
			var form = document.getElementById( p_form );
			var inputs = collectionToArray( form.getElementsByTagName( 'input' ) );
			var textAreas = collectionToArray( form.getElementsByTagName( 'textarea' ) );
			
			var totalTextAreas = textAreas.length;
			if( totalTextAreas == 1 ){
				inputs.push( textAreas[0] );
			}else{
				inputs.concat( textAreas );
			}
			
			var totalFields = inputs.length;
			
			if( totalFields <= 0 ) {
				return true;
			}
 
			var valid = true;
			
			for( var i=0; i<totalFields; i++ ){
 
				var theClassName = inputs[i].className;
				if( theClassName.indexOf('optional') > -1 ){ continue; }
				if( theClassName.trim() == '' ){ theClassName = 'full'; }
 
				var theType = inputs[i].type;
				if( theType.trim() == '' || theType == null ){ theType = 'text'; }
 
				var element = inputs[i].id;				
				var theValue = inputs[i].value;
				
				if( theType != 'button' && theType != 'submit' ){
					var formField = { id:element, type:theType, className:theClassName, value:theValue };
					if( !Validation.validateType( p_form, formField ) ){
						Validation.markInvalid( formField, p_inValidCallback );
						valid = false;
					}else{
						Validation.markValid( formField, p_validCallback );
					}
				}
				
			}
 
			return valid;
		}, // END METHOD: validate
		
		
		/**
		*	Switches through the different validation types and validates them based on their type
		*	@access	private
		*	@param	string	p_form	the form to validate
		*	@param	object	p_obj	the object containing the values of the form data
		*	@return	
		*/
		validateType:function( p_form, p_obj ){
			switch( p_obj.type ){
				case 'text':
				case 'textarea':
					return Validation.validateText( p_form, p_obj );
					break;
				case 'radio':
					return Validation.validateRadio( p_form, p_obj );
					break;
				case 'checkbox':
					return document.getElementById( p_obj.id ).checked;
					break;
			}
			return false;
		}, // END METHOD: validateType
	
	
		/**
		*	Validates a text-based input
		*	@access	private
		*	@param	string	p_form	the form to validate
		*	@param	object	p_obj	the object containing the values of the form data
		*	@return	
		*/
		validateText:function( p_form, p_obj ){
			if( p_obj.value == formValues[ p_obj.id ] ){
				return false;
			}
			
			switch( p_obj.className ){
				case 'full':
					if( p_obj.value.trim().length > 0 ){ return true; }
					return false;
					break;
				case 'email':
					var emailRegEx = /^[A-Z0-9\!\#\$\%\&\'\*\+\-\/\=\?\\^\_\`\.\{\|\}\~]{1,64}@([A-Z0-9-]{1,63}\.){1,}[A-Z0-9]{2,6}$/i;
					if( p_obj.value.trim().length > 0 && emailRegEx.exec( p_obj.value.trim() ) ){
						return true;
					}
					return false;
					break;
				case 'name':
					var nameRegEx = /^[^\~\!\@\#\$\%\^\&\*\(\)\_\+\=\|\}\{\[\]\:\"\;\?\/\>\<\,0-9]{1,256}$/i;
					if( p_obj.value.trim().length > 0 && nameRegEx.exec( p_obj.value.trim() ) ){
						return true;
					}
					return false;
					break;
				case 'phone':
					var phoneRegEx = /^1?[\.\-\/ ]?\(?(\d{3})\)?[\.\-\/ ]?(\d{3})[\.\-\/ ]?(\d{4})$/i;
					if( p_obj.value.trim().length > 0 && phoneRegEx.exec( p_obj.value.trim() ) ){
						return true;
					}
					return false;
					break;
				case 'postcode-ca':
					var postRegEx = /^([ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTVWXYZ])\ {0,1}(\d[ABCEGHJKLMNPRSTVWXYZ]\d)$/i;
					if( p_obj.value.trim().length > 0 && postRegEx.exec( p_obj.value.trim() ) ){
						return true;
					}
					return false;
					break;
			}
			return false;
		}, // END METHOD: validateText
		
		
		/**
		*	Validates a radio group, and tracks that the group has been completed
		*	@access	public
		*	@param	string	p_form	the form to validate
		*	@param	object	p_obj	the object containing the values of the form data
		*	@return	
		*/
		validateRadio:function( p_form, p_obj ){
			var radioGroup = document.getElementsByName( document.getElementById( p_obj.id ).name );
			
			var totalGroup = radioGroup.length;
			if( totalGroup <= 0 ){ return true; }
			
			for( var i=0; i<totalGroup; i++ ){
				if( radioGroup[i].checked ){
					return true;
				}
			}
			
			return false;
		},	// END METHOD: validateRadio
	
	
		/**
		*	Marks the field invalid, using the callback function
		*	@access	private
		*	@param	object	p_obj	the object containing the values of the form data
		*	@param	string	p_callback	the function to callback when invalid
		*	@return	void
		*/
		markInvalid:function( p_obj, p_callback ){
			p_callback( p_obj );
			return true;
		}, // END METHOD: markInvalid
		
		
		/**
		*	Marks the field valid, using the callback function
		*	@access	private
		*	@param	object	p_obj	the object containing the values of the form data
		*	@param	string	p_callback	the function to callback when valid
		*	@return	void
		*/
		markValid:function( p_obj, p_callback ){
			p_callback( p_obj );
			return true;
		} // END MEHTHOD: markValid
		
		
	};
 
 
	// Open the public methods to...um... the public
	return publicMethods;
}();  // run immediately
 
 
/**
*	Adds methods to the String class for trimming
*	@access	public
*	@return	string	the trimmed string
*/
String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g,"");
}
String.prototype.ltrim = function() {
	return this.replace(/^\s+/,"");
}
String.prototype.rtrim = function() {
	return this.replace(/\s+$/,"");
}
 
 
/**
*	Mimics target="_blank"
*	@access	public
*	@return	void|false
*/
var newWindow = function( p_item ){ window.open( p_item.href ); return false; }
 
 
/**
*	Takes and HTML Collection and reformats it as an array
*	@access	public
*	@param	object	p_collection	the collection to reformat
*	@return	array
*/
function collectionToArray( p_collection ){
	var a = new Array();
	for( var i=0; i<p_collection.length; i++ ){
		a[ a.length ] = p_collection[i];
	}
	return a;
}
 
 
/**
*	Checks if a value exists in an array
*	Matches identical (===), not just similar (==)
*	@access	public
*	@param	string	p_value	the value to compare in an array
*	@return	bool
*/
Array.prototype.inArray = function( p_value ){
	for ( var i=0; i<this.length; i++ ) {
		if( this[i] === p_value ){ return true; }
	}
	return false;
};
 
 
/**
*	Limits a field to a certain number of characters
*	Outputs the number of characters left
*	@access	public
*	@param	string	p_field	id of the field to limit
*	@param	string	p_countfield	id of the field that will display how many characters remain
*	@param	int	p_limit	the total amount of characters allowed in the box
*	@return	bool
*/
function textCounter( p_field, p_countfield, p_limit ){
	var field = document.getElementById( p_field );
	var countfield = document.getElementById( p_countfield );
	
	if( field.value.length > p_limit ){
		field.value = field.value.substring( 0, p_limit );
		return false;
	}else{
		var theLength = p_limit - field.value.length;
		countfield.innerHTML = '(200 words max.,<br />'+theLength+' characters left)';
		return true;
	}
}
