/* === TIGER VALIDATOR MODULE === */

/* Description:
 * The aim of TIGER.validator is to create as close to a self-validating
 * input element as possible while keeping the element valid xHTML.
 * The validator is designed to be totally self-contained when validating
 * form elements. It accepts an array of inputs of strings, elements or form
 * references. It will intelligently determine the type of element. It will 
 * then pass each element through to your custom callback method so that you 
 * can apply any JS, styling and/or generate alert messages on form elements.
 * Within TIGER, the callback is typically TIGER.message().
 * 
 * Methodology:
 * TIGER does not implement client-side validation as a means of keeping the
 * end-user from submitting bad data, it is merely a messaging system to alert
 * the user they are about to submit bad data. Client-side validation is NOT
 * a replacement for server-side validation.
 * 
 * Configuration:
 * To enable an element to become self-validating, simply add a validation
 * class to the element's class attribute. You can add as many validation
 * classes as necessary or create custom ones using a regular expression.
 * If the field does not have a recognized VAL_ validation class, it will be
 * ignored by the validator.
 * 
 * Building Validation Rules:
 * Keep it simple. Don't attempt to build combo-rules that test for more than
 * one issue unless you really need a special case, like a custom callback method.
 * A test for valid email characters, not an email format, is as complex as 
 * you should get. I've decided to build the validation constants in both long
 * short hand to keep things simple and classes shorter.
 * 
 * Anatomy of a Validation Constant:
 * Validation constants are really JS objects populated with what we need to test
 * the values of their associated form element. Prettry simple acutally. For reference, 
 * this is what the typical test or oVal object looks like:
 * 
 *	{
 *		'element'		: {elment object to be validated}
 *		'testFunction'	: 'TIGER.validate.text',
 *		'regex'			: /^\w+$/,
 *		'message'		: 'Required field.'
 *	}
 *
 * The 'element' portion of the object doesn't actually get a reference until it passes
 * through the TIGER.validate() function. If you're writing a custom object to do a
 * specific kind of validation on a specific object, you can include the object within 
 * your declaration.
 *
 * 
 * Common Validation Constants || Shorthand
 * 
 * COMMON || C				= any alphanumeric characters plus safe punctuation
 * REQUIRED	|| R			= field must contain a text string to be validated
 * ALPHA || A				= any alpha character a-z or A-Z
 * NUMERIC || N				= any numeric character 0-9
 * ALPHANUM || AN 			= any characters a-z, A-Z, 0-9
 * EMAIL || E				= validates an email address
 * REQUIREPUNCT || RP		= require at least 1 punctuation character
 * REQUIREUPPER || RU		= require at least 1 upper-case character
 * REQUIRENUM || RN			= require at least 1 numeric character
 * MINx						= require minimum x characters
 * MAXx						= limit to maximum x characters
 * 
 * The validation constants are defined at the bottom of this page. */


/** 
 * @method validate
 * @description (See below)
 * @author K. Beau Beauchamp
 * @public
 * @static
 * @param {elm}
 * @param {method name}
 * @return 
 */

TIGER.validate = function(elm,callback){
	
	/* Description:
	 * The validate() function is where we do all the heavy lifting. This function
	 * can be called as part of our page Validator() or statically to validate a single
	 * element on the fly. If validating on the fly, use YUI to add the TIGER.val[] class
	 * to the element and then throw the element at the TIGER.validate class for instant
	 * validation. COOL! 
	 * 
	 * Messages:
	 * The aMessage array is a message accumulator or message queue. Multiple tests
	 * failing can generate multiple messages within this queue which gets passed
	 * back to your callback function. Make sure your callback function is capable of
	 * dealing with a message array and not just a string. */

	var sMessage = '', aMessage = [], i;
	
	var aTests = TIGER.validate.getTests(elm);
	
	/* Now iterate through each of the tests (if any) */
	for (i in aTests){

		/* If there is a testFunction then throw the oVal object into its element-specific 
		 * validation method based on the TYPE of element being validated, whether text, 
		 * radio, or checkbox. Otherwise, set sMessage to false. */
		sMessage = (TIGER.util.isFunction(TIGER.val[aTests[i]].testFunction)) ? TIGER.val[aTests[i]].testFunction( TIGER.val[aTests[i]] ) : false;

		/* Add the sMessage to our message queue: 
		 * string = There was an error message generated, validation failed; 
		 * false  = no errors generated, validation passed. */
		aMessage.push(sMessage);
	
		sMessage = '';	// clear the message string
	
	}

	/* Pass the entire result to our custom callback function */

	/* Message Object:
	 * {
	 * 		message		: {string},
	 * 		sourceElm	: {el || string} (usually null except for form messages),
	 * 		targetElm	: {el || string} (defaults to system_messages),
	 * 		class		: {string} (optional, defaults to 'alert')
	 * }
	 */

	callback( { message : aMessage, sourceElm : elm, targetElm : 'form' });

};

TIGER.validate.getTests = function(elm){

	/* The getTests function accepts an element and returns an array of the associated 
	 * oVal validation objects for the element, if any. */
	
	var i, len;
	
	/* Make sure we're dealing with an element and not a string. Don't bother even
	 * testing for a string, just get the element. */
	elm = Dom.get(elm);
	
	/* Collect our validation contants */
	var aTests = elm.className.toString().split(' ');
		
	/* Junk anything in the aTests array that doesn't actually exist in our TIGER.val
	 * array. */
	for (i=0, len=aTests.length; i<len; ++i){
		if(!TIGER.val[aTests[i]]){
			aTests.splice(i,1); 
			// adjust len since there's now one less item in aTests
			len=aTests.length;
		}
	}

	/* Now iterate through each of the tests (if any) */
	for (i in aTests){

		/* Pickup the element and place it into our val object for easy reference */
		TIGER.val[aTests[i]].element = elm;
	
	}

	return aTests;

};


/* CONTROL-SPECIFIC TESTS
 * These are the control-specific test fucntions. To get even more granular,
 * each control specific test is broken out into its own function. */

TIGER.validate.text = function(oVal){

	/* For reference, this is what the oVal object looks like ...
	 *	{
	 *		'element'		: {elment object to be validated}
	 *		'testFunction'	: 'TIGER.validate.text',
	 *		'regex'			: /^\w+$/,
	 *		'message'		: 'Required field.'
	 *	}
	 */

	/* Do a regex test. Return the message if it fails or false if it passes. */
	return ( !oVal.regex.test(oVal.element.value) ) ? oVal.message : false;

};

TIGER.validate.radio = function(oVal){
	return false;
};

TIGER.validate.checkbox = function(oVal){
	return false;
};

TIGER.validate.select = function(oVal){
	// alert(oVal.element.value);
	return ( !oVal.regex.test(oVal.element.value) ) ? oVal.message : false;
};

TIGER.validate.textarea = {

	length : function(oVal){

		/* For reference, this is what the oVal object looks like ...
		 *	{
		 * 		'element'		: {input element},
		 *		'testFunction'	: TIGER.validate.textarea.length,
		 *		'value'			: '140',
		 *		'message'		: 'Maximum length is 140 characters.'
		 *	};
		 */

		return (oVal.element.value.length > oVal.value) ? oVal.message : false;

	}

};


/* DATA-SPECIFIC TESTS
 * The data-specific tests fucntions are custom methods used to validate a
 * particular kind of data, such as usernames, passwords, or anything that
 * requires more than just a simply regex test, such as "required" which does
 * use a simple regex test but then also needs to auto-bold the field labels 
 * of the controls it's attached to. */

TIGER.validate.required = function(oVal,callback){

	/* For reference, this is what the oVal object looks like ...
	 * 	{
	 * 		'element'		: {input element}
	 * 		'message'		: 'Required field.',
	 * 		'init'			: TIGER.validate.required,
	 * 		'testFunction'	: TIGER.validate.text,
	 * 		'regex'			: /^[\w\W]+$/		// Matches anything, including spaces
	 * 	};
	 */

	/* Okay, because the REQUIRED oVal object has an init param, this function
	 * is going to be called on TIGER.validate.init. All we need to do is bold all
	 * field labels that have the R (for REQUIRED) class. We'll use getElementsBy 
	 * to do everything in one call. Cool! */
	var aResult = Dom.getElementsBy(
		function(el){ return (Dom.hasClass(el,'R')); },
		null, 
		null,
		function(el) { Dom.addClass(Dom.getPreviousSibling(el),'required'); }
	);

	// If we have some required fields, show the "bold fields required" div.
	if ( aResult.length > 0 ){ Dom.removeClass(Dom.get('required'),'hide'); }
	
	// Well, that was easy ...
	
	return false;

};

TIGER.validate.minimum = function(oVal)
{
	/* For reference, this is what the oVal object looks like ...
	 * {
	 * 		'element'		: {input element}
	 * 		'message'		: 'Must have at least %s characters.',
	 * 		'testFunction'	: TIGER.validate.minimum,
	 * 		'value'			: 4
	 * }
	 */

	if(oVal.element.value.length < oVal.value) 
	{
		var message = TIGER.i18n(oVal.message);
		return message.replace('%s',oVal.value);
	}
	else
	{
		return false;
	}
};

TIGER.validate.username = function(oVal){

	/* For reference, this is what the oVal object looks like ...
	 *	{
	 *		'element'		: {input elment}
	 *		'testFunction'	: 'TIGER.validate.username',
	 *		'regex'			: '',
	 *		'message'		: 'Username is not available.'
	 *	}
	 */

	/* Check to see if the username is taken */
	var checkUsername = new TIGER.ajax.request(
		'POST',
		'/clients/ajaxdata',
		'action=checkusername&username=' + oVal.element.value,
		null,
		TIGER.validate.checkusername
	);
	
	return false;

};

TIGER.validate.checkusername = function(){
	/* The callback function for the TIGER.validate.username test. */
	var oVal = TIGER.val['CU'];
	var response = TIGER.util.ajax.usernameexists.toString().toLowerCase();
	if ( response === 'true' ){ 
		TIGER.message.show({
			message 	: oVal.message, 
			sourceElm 	: oVal.element,
			targetElm	: 'form',
			sclass		: null
		});
	}
	TIGER.ajax.successEvent.unsubscribe(TIGER.validate.checkusername);
};

TIGER.validate.matchpasswords = function(oVal){

	/* For reference, this is what the oVal object looks like ...
	 *	{
	 *		'element'		: password2
	 *		'testFunction'	: 'TIGER.validate.username',
	 *		'regex'			: '',
	 *		'message'		: 'Passwords do not match.'
	 *		'matchfield'	: Dom.get('password')
	 *	}
	 */

	var password1	= oVal.matchfield;
	var password2 	= oVal.element;
	
	if ( password1.value.length > 0 && password2.value.length > 0){
		return (password1.value !== password2.value) ? oVal.message : false;	
	}
	else
	{
		return false;
	}
	
	return false;

};

TIGER.validate.password = {};

TIGER.validate.password.numeric = function(oVal)
{
	/* For reference, this is what the oVal object looks like ...
	 *	{
	 * 		'element'		: {password element}
	 * 		'message'		: '%s numeric character required.',
	 * 		'messageplural'	: '%s numeric characters required.',
	 * 		'testFunction'	: TIGER.validate.password.numeric,
	 * 		'value'			: n
	 *	}
	 */
	
	// Build our regex
	var regex = new RegExp('^.*(?='+ TIGER.util.str_repeat('.*\\d', oVal.value) +').*$');
	if(!regex.test(oVal.element.value)) 
	{
		var message = (oVal.element.value > 1) ? TIGER.i18n(oVal.messageplural) : TIGER.i18n(oVal.message);
		return message.replace('%s',oVal.value);
	}
	else
	{
		return false;
	}

};

TIGER.validate.password.uppercase = function(oVal)
{
	/* For reference, this is what the oVal object looks like ...
	 *	{
	 * 		'element'		: {password element}
	 * 		'message'		: 'Required uppercase character(s): ',
	 * 		'testFunction'	: TIGER.validate.password.uppercase,
	 * 		'value'			: n
	 *	}
	 */
	
	// Build our regex
	var regex = new RegExp('^.*(?='+ TIGER.util.str_repeat('.*[A-Z]', oVal.value) +').*$');
	if(!regex.test(oVal.element.value)) 
	{
		var message = (oVal.element.value > 1) ? TIGER.i18n(oVal.messageplural) : TIGER.i18n(oVal.message);
		return message.replace('%s',oVal.value);
	}
	else
	{
		return false;
	}

};

TIGER.validate.password.punctuation = function(oVal)
{
	/* For reference, this is what the oVal object looks like ...
	 *	{
	 * 		'element'		: {password element}
	 * 		'message'		: 'Required punctuation character(s): ',
	 * 		'testFunction'	: TIGER.validate.password.punctuation,
	 * 		'value'			: n
	 *	}
	 */
	
	// Build our regex
	var regex = new RegExp('^.*(?='+ TIGER.util.str_repeat('.*\\W', oVal.value) +').*$');
	if(!regex.test(oVal.element.value)) 
	{
		var message = (oVal.element.value > 1) ? TIGER.i18n(oVal.messageplural) : TIGER.i18n(oVal.message);
		return message.replace('%s',oVal.value);
	}
	else
	{
		return false;
	}

};

TIGER.validate.password.strength = function(oVal)
{
	/* For reference, this is what the oVal object looks like ...
	 *	{
	 * 		'element'		: {password element}
	 * 		'message'		: 'Minimm password strength must be %s.',
	 * 		'testFunction'	: TIGER.validate.password.strength,
	 * 		'value'			: n
	 *	}
	 */

	var strengthValue = TIGER.validate.passwordstrength.value(oVal.element.value);

	if (strengthValue < TIGER.page.password.strength)
	{
		var message = TIGER.i18n(oVal.message);
		var minimumStrengthLabel = TIGER.validate.passwordstrength.strengthLabel(oVal.value);
		return message.replace('%s',minimumStrengthLabel);
	}
	else
	{
		return false;
	}	

};

TIGER.validate.password.repeated = function(oVal)
{
	/* For reference, this is what the oVal object looks like ...
	 *	{
	 * 		'element'		: {password element}
	 *		'message'		: 'Characters may not be repeated.',
	 *		'messageplural'	: 'Characters may be repeated no more than %s times.',
	 * 		'testFunction'	: TIGER.validate.password.repeated,
	 * 		'value'			: n
	 *	}
	 */


	// Build our regex
	// (.)\1\1	// e.g. tests for 3 or more repeating characters in a string
	var regex = new RegExp('(.)'+ TIGER.util.str_repeat('\\1', oVal.value));
	if(regex.test(oVal.element.value)) 
	{
		var message = (oVal.value > 1) ? TIGER.i18n(oVal.messageplural) : TIGER.i18n(oVal.message);
		return message.replace('%s',oVal.value);
	}
	else
	{
		return false;
	}

};

/** 
 * @method passwordstrength
 * @description (See below)
 * @author K. Beau Beauchamp
 * @public
 * @static
 * @param {varies}
 * @return nothing
 */
TIGER.validate.passwordstrength = {

	/* Password Strength is a self-contained password strength widget object
	 * that should be attached to the primary password field. It will indicate 
	 * the relative strength of a user's password as they type. A container
	 * formatted as <span id="pwstrength"></span> should immediately follow
	 * the password field. On initialization, passwordstrength will also
	 * add any strength requirments to the password field such as special
	 * character type requirements passed in from the application's settings. */	
	
	value : function(sPassword)
	{
		var pwlength = sPassword.length;
		if( pwlength > 6 ) { pwlength = 6; }
		
		var numnumeric = sPassword.replace(/[0-9]/g,"");
		var numeric = sPassword.length - numnumeric.length;
		if(numeric > 3) { numeric = 3; }

		var symbols = sPassword.replace(/\W/g,"");
		var numsymbols = sPassword.length - symbols.length;
		if (numsymbols > 3) { numsymbols = 3; }
		
		var numupper = sPassword.replace(/[A-Z]/g,"");
		var upper = sPassword.length - numupper.length;
		if(upper > 3) { upper = 3; }
		
		var pwstrength = ((pwlength*10)-40)+(numeric*10)+(numsymbols*15)+(upper*10);

		// normalize pwstrength to between 0 and 100 if necessary
		// if(pwstrength < 0){ pwstrength = 0; }
		// if(pwstrength > 100){ pwstrength = 100; }
		
		return pwstrength;

	},
	
	update : function(elm)
	{
		var passwordStrength = TIGER.validate.passwordstrength.value(elm.value.toString());
		var target = Dom.get('pwstrength');
		var label = this.strengthLabel(passwordStrength);

		if (elm.value.length === 0)
		{
			TIGER.message.containers[target.id].PWNone.animate();
			label = TIGER.i18n('Strength');
		}
		else if (passwordStrength > 100)
		{
			TIGER.message.containers[target.id].PWStrong.animate();
		}
		else if (passwordStrength > 60)
		{
			TIGER.message.containers[target.id].PWGood.animate();
		}
		else if (passwordStrength > 30)
		{
			TIGER.message.containers[target.id].PWModerate.animate();
		}
		else
		{
			TIGER.message.containers[target.id].PWWeak.animate();
		}
		target.innerHTML = label;
	},

	strengthLabel : function(value)
	{
		if (value > 100)
		{
			return TIGER.i18n('Strong');
		}
		else if (value > 60)
		{
			return TIGER.i18n('Good');
		}
		else if (value > 30)
		{
			return TIGER.i18n('Moderate');
		}
		else
		{
			return TIGER.i18n('Weak');
		}
	},

	init : function(oVal)
	{
		var elm = oVal.element;
		var target = Dom.get('pwstrength');
		if (target.innerHTML === '')
		{
			target.innerHTML = TIGER.i18n('Strength');
			Event.addListener(elm,'keyup',function(){ TIGER.validate.passwordstrength.update(this); });

			TIGER.message.containers[target.id] = [];
			
			TIGER.message.containers[target.id].PWNone = new ColorAnim(target);
			TIGER.message.containers[target.id].PWNone.duration = 0.3;
			TIGER.message.containers[target.id].PWNone.attributes.backgroundColor = { to: '#FFFFFF' };

			TIGER.message.containers[target.id].PWStrong = new ColorAnim(target);
			TIGER.message.containers[target.id].PWStrong.duration = 0.3;
			TIGER.message.containers[target.id].PWStrong.attributes.backgroundColor = { to: '#C4DDE3' };

			TIGER.message.containers[target.id].PWGood = new ColorAnim(target);
			TIGER.message.containers[target.id].PWGood.duration = 0.3;
			TIGER.message.containers[target.id].PWGood.attributes.backgroundColor = { to: '#E6EFC2' };

			TIGER.message.containers[target.id].PWModerate = new ColorAnim(target);
			TIGER.message.containers[target.id].PWModerate.duration = 0.3;
			TIGER.message.containers[target.id].PWModerate.attributes.backgroundColor = { to: '#FDF2BA' };

			TIGER.message.containers[target.id].PWWeak = new ColorAnim(target);
			TIGER.message.containers[target.id].PWWeak.duration = 0.3;
			TIGER.message.containers[target.id].PWWeak.attributes.backgroundColor = { to: '#FFCFCF' };

			/* Also initialize password strength requirements. */

			if (parseInt(TIGER.page.password.maximum) > 0)
			{
				Dom.setAttribute(elm, 'maxlength', TIGER.page.password.maximum);
			}
			
			if (parseInt(TIGER.page.password.minimum) > 0)
			{
				Dom.addClass(elm, 'PWMIN');
				TIGER.val['PWMIN'].value = parseInt(TIGER.page.password.minimum);
			}
			
			if (parseInt(TIGER.page.password.numeric) > 0)
			{ 
				Dom.addClass(elm, 'PWRN');
				TIGER.val['PWRN'].value = parseInt(TIGER.page.password.numeric);
			}
			
			if (parseInt(TIGER.page.password.uppercase) > 0)
			{
				Dom.addClass(elm, 'PWRU');
				TIGER.val['PWRU'].value = parseInt(TIGER.page.password.uppercase);
			}
			
			if (parseInt(TIGER.page.password.punctuation) > 0)
			{
				Dom.addClass(elm, 'PWRP');
				TIGER.val['PWRP'].value = parseInt(TIGER.page.password.punctuation);
			}

			if (parseInt(TIGER.page.password.strength) > 0)
			{
				Dom.addClass(elm, 'PWST');
				TIGER.val['PWST'].value = parseInt(TIGER.page.password.strength);
			}

			if (parseInt(TIGER.page.password.repeated) > 0)
			{
				Dom.addClass(elm, 'PWRE');
				TIGER.val['PWRE'].value = parseInt(TIGER.page.password.repeated);
			}
		}
	}
	
};


/** 
 * @method validate.attrubute
 * @description (See below)
 * @author K. Beau Beauchamp
 * @public
 * @static
 * @param {object}
 * @return nothing
 */
TIGER.validate.attribute = function(oVal){

	/* Validate attribute is a method for setting the attributes of a control. */

	/*	{
	 * 		'element'		: {elment object to be validated}
	 * 		'init'			: TIGER.validate.attribute,
	 * 		'attribute'		: 'maxlength',
	 * 		'value'			: '12'
	 * 	} 
	 */

	 Dom.setAttribute(oVal.element, oVal.attribute, oVal.value);
		
};


/** 
 * @method validator
 * @description (See below)
 * @author K. Beau Beauchamp
 * @public
 * @static
 * @param {array (str || elm || form elm) || str || elm || form elm} accepts just
 * about anything and attempts to apply the validation rule(s)
 * @param {method name}
 * @return nothing
 */

TIGER.validate.init = function(vInput,callback){
	
	/* Description:
	 * The validator() is a pre-processor that iterates through each of the
	 * elments within the vInput and attaches an event listener to each element. 
	 * Each element is automatically validated onBlur. onBlur validation is 
	 * much better than on change. If you really want to fire the TIGER.validate
	 * onChange, just add a custom event for the element to fire TIGER.validate()
	 * onChange. */
	var i;
	
	var setupValidation = function(aElms,callback)
	{
		
		// Normalize the input to an array of elements
		var aElms = Dom.get(aElms);

		Dom.batch(
			aElms, 
			function(el)
			{
				// Make sure we don't try to validate a null or non-existant el
				if (el)
				{
					if(Dom.inDocument(el))
					{
						// check to see if we're dealing with a form, if we are
						// get an array of the form nodes and send them back through
						// the setupValidation function.
						if(el.nodeName.toString().toLowerCase() === 'form')
						{
							// getFrom returns an array validatable form elements
							setupValidation(TIGER.html.getForm(el,false,'',''),callback);
						}
						else
						{
							// if there's nothing in the className, don't bother
							// if(el.className.toString().length > 0)
							if(el.className !== '')
							{
								
								// aTests is an array of our test strings
								var aTests = TIGER.validate.getTests(el);
								var oVal = {};
								
								// Check each test for an init
								for(i in aTests)
								{
									oVal = TIGER.val[aTests[i]];

									// some oVal tests are self-initializing, which means
									// they contain an init function. If an oVal has an init, 
									// run it instead of the default onBlur listener
									if (TIGER.util.isFunction(oVal.init))
									{
										oVal.init(oVal,callback);
									}
								}
								
								// If we have valid tests, setup an onblur listener
								if (aTests.length > 0)
								{
									Event.addListener(
										el,
										'blur',
										function(e){ TIGER.validate(this,callback); }
									);
								}
							}
						}
					}
				}
			}
		);

	};

	/* Now that we have setup all of our functions, call setupValidation() */
	setupValidation(vInput,callback);

};

TIGER.val = [];

/* Establish our validation objects. You can easily add to or update these if 
 * you need. Note that there is both a longhand and shorthand version of these 
 * provided. You can also add custom params to each object based on the what 
 * the custom function is expecting. Note that the element value is automatically
 * added to the TIGER.val[] object when it passes through TIGER.validate.init(). */


/* Custom Validators */

//Requires something other than a whitespace character

/* Special validator to check for a unique username */
TIGER.val['CU'] = {
	'message' 		: 'Username is not available.',
	'testFunction'	: TIGER.validate.username,
	'regex'			: ''
};

/* The minimum length validator. */
TIGER.val['MIN4'] = {
	'message'		: 'Must have at least %s characters.',
	'testFunction'	: TIGER.validate.minimum,
	'value'			: 4
};

/* Common Text (regex) Validators */

TIGER.val['R'] = {
	'message'		: 'Required field.',
	'init'			: TIGER.validate.required,
	'testFunction'	: TIGER.validate.text,
	'regex'			: /^[\w\W]+$/		// Matches anything, including spaces
};

/* The common validator. Always validate an input field for unwanted characters. 
 * Allows nothing or common input characters of: alpha-numeric (case insensitive),
 * commas(,), apostrophes('), periods(.), underscores(_) and dashes(-)  */
TIGER.val['C'] = {
	'message'		: 'Disallowed characters entered.',
	'testFunction'	: TIGER.validate.text,
	'regex'			: /^[\w ,'\._-]*?$/
	};

/* No whitespace characters */
TIGER.val['NS'] = {
	'message'		: 'Field may not contain spaces.',
	'testFunction'	: TIGER.validate.text,
	'regex'			: /^[\S]+$/
	};

/* Allows nothing or only upper or lower case alpha characters */
TIGER.val['A'] = {
	'message'		: 'Letter characters (A-Z) only.',
	'testFunction'	: TIGER.validate.text,
	'regex'			: /^[a-zA-Z]*?$/
	};

/* Allows nothing or only numeric characters */
TIGER.val['N'] = {
	'message'		: 'Numeric characters (0-9) only.',
	'testFunction'	: TIGER.validate.text,
	'regex'			: /^\d*?$/
	};

/* Allows nothing or only alpha-numeric characters */
TIGER.val['AN'] = {
	'message'		: 'Alpha-numeric characters (A-Z, 0-9) only.',
	'testFunction'	: TIGER.validate.text,
	'regex'			: /^[a-zA-Z\d]*?$/
	};

/* We don't validate an email address' structure, just the allowed characters.
 * Allows nothing or valid email characters. */
TIGER.val['E'] = {
	'message'		: 'Invalid email address.',
	'testFunction'	: TIGER.validate.text,
	'regex'			: /^[a-zA-Z\d\.\-@_]*?$/
	};

/* We don't validate an email address' structure, just the allowed characters.
 * Allows nothing or valid email characters including comma or semi-colon delimiters. */
TIGER.val['EM'] = {
	'message'		: 'Invalid email address.',
	'testFunction'	: TIGER.validate.text,
	'regex'			: /^[a-zA-Z\d\.\-@_\,\; \n\r]*?$/
	};


/* If we want to validate for phone number characters. */
TIGER.val['PH'] = {
	'message'		: 'Invalid phone number.',
	'testFunction'	: TIGER.validate.text,
	'regex'			: /^[\d \+\.\-]*?$/
	};

/* The MUST CONATAIN patterns
 * Some really nice help for these look-ahead RegEx patters can be found at:
 * http://www.zorched.net/2009/05/08/password-strength-validation-with-regular-expressions/ */

/* If you want to requre at least one allowed punctuation for passwords. */
TIGER.val['RP'] = {
	'message'		: 'Must contain a punctuation character.',
	'testFunction'	: TIGER.validate.text,
	'regex'			: /^.*(?=.*[\W]).*$/
	};

/* If we want to require at least one upper-case character for passwords. */
TIGER.val['RU'] = {
	'message'		: 'Must contain an uppercase character.',
	'testFunction'	: TIGER.validate.text,
	'regex'			: /^.*(?=.*[A-Z]).*$/
	};

/* If we want to require at least one numeric character for passwords. */
TIGER.val['RN'] = {
	'message'		: 'Must contain a numeric character.',
	'testFunction'	: TIGER.validate.text,
	'regex'			: /^.*(?=.*[\d]).*$/
	};


/* The ATTRIBUTE patterns
 * These val objects are used to set the attributes of controls on init. */

/* Special validator to SET the maxlength attrubute of a field. MAX sets the default
 * of 45 characters. */
TIGER.val['MAX'] = {
	'init'			: TIGER.validate.attribute,
	'attribute'		: 'maxlength',
	'value'			: '45'
};

TIGER.val['M36'] = {
	'init'			: TIGER.validate.attribute,
	'attribute'		: 'maxlength',
	'value'			: '36'
};

TIGER.val['M140'] = {
	'testFunction'	: TIGER.validate.textarea.length,
	'value'			: '140',
	'message'		: 'Maximum length is 140 characters.'
};

TIGER.val['M250'] = {
	'init'			: TIGER.validate.attribute,
	'attribute'		: 'maxlength',
	'value'			: '250'
};


/* The PASSWORD patterns
 * These val objects are used specifically for passwords. */

/* Special validator to check for password strength. Note that the PS 
 * requires a special container with the id of pwstrength. */
TIGER.val['PS'] = {
	'message' 		: '',
	'testFunction'	: '',
	'init'			: TIGER.validate.passwordstrength.init,
	'regex'			: ''
};

/* Validate matching password fields. */
TIGER.val['MP'] = {
	'message'		: 'Passwords do not match.',
	'testFunction'	: TIGER.validate.matchpasswords,
	'regex'			: '',
	'matchfield'	: Dom.get('password')
};

/* Requre at least x length for passwords. */
TIGER.val['PWMIN'] = {
	'message'		: 'Must have at least %s characters.',
	'testFunction'	: TIGER.validate.minimum,
	'value'			: ''
};

/* If we want to require at least x numeric character for passwords. */
TIGER.val['PWRN'] = {
	'message'		: '%s numeric character required.',
	'messageplural'	: '%s numeric characters required.',
	'testFunction'	: TIGER.validate.password.numeric,
	'value'			: ''
};

/* If we want to require at least x upper-case character for passwords. */
TIGER.val['PWRU'] = {
	'message'		: '%s uppercase character required.',
	'messageplural'	: '%s uppercase characters required.',
	'testFunction'	: TIGER.validate.password.uppercase,
	'value'			: ''
};

/* If you want to requre at least x allowed punctuation for passwords. */
TIGER.val['PWRP'] = {
	'message'		: '%s punctuation character required.',
	'messageplural'	: '%s punctuation characters required.',
	'testFunction'	: TIGER.validate.password.punctuation,
	'value'			: ''
};

/* If you want to requre a minimum password strength. */
TIGER.val['PWST'] = {
	'message'		: 'Minimm password strength must be %s.',
	'testFunction'	: TIGER.validate.password.strength,
	'value'			: ''
};

/* If you want to set a maximum number of repeated characters. */
TIGER.val['PWRE'] = {
	'message'		: 'Characters may not be repeated.',
	'messageplural'	: 'Characters may be repeated no more than %s times.',
	'testFunction'	: TIGER.validate.password.repeated,
	'value'			: ''
};
