/*
var rxpDate = /(^[0-1]?[0-9]\/[0-3]?[0-9]\/[1-2][0-9]{3}$)|(^[0-1][0-9][0-3][0-9][1-2][0-9]{3}$)/; // (mm/dd/yyyy, m/d/yyyy OR mmddyyyy)
var rxpTime = /^[0-1][0-9]:[0-5][0-9]$/; // (hh:mm)
var rxpZip = /(^[0-9]{5}$)/; // Zip
var rxpPhone = /^\([0-9]{3}\)[0-9]{3}\-[0-9]{4}\s?(\w|\.)*$/; // (xxx)xxx-xxxx or (xxx)xxx-xxxx xxxxxxx for extensions
var rxpSSN = /^[0-9]{3}\-[0-9]{2}\-[0-9]{4}$/; // (xxx-xx-xxxx)
var rxpNumeric = /^[0-9]*$/
*/

(function( $ ){
	
	var defaults = {
		singleErrorTemplate:'<span class="error" />',
		errorGroupTemplate:'<ul class="errors" />',
		errorItemTemplate:'<li class="error" />',
		labelErrorClass: 'error',
		errorLabels: true,
		singleErrors: false,
		groupErrors:true,
		groupContainer: null,
		useTitlesForErrors: true,
		realTime: true
	};
	function validateElement( field, settings, actions, undo ){
		if( !field.className ) return true;
		var classes = field.className.split(' '), l = classes.length;
	
		for(var i=0; i < l; i++ ){
			var params = classes[i].split(':'),
				vtor = $.validForm.validators[params.shift()],
				copy = params.concat();
				
			if( !vtor ) continue;
			if( vtor.data )
				params.unshift( vtor.data );
			params.unshift( field );
			if( vtor.validator.apply( vtor, params ) ) continue;
			
			var message = settings.useTitlesForErrors && field.title || vtor.message;
			message = message.replace(/\{(\d+)\}/g, function( a, $1 ){
				return copy[$1];
			});
			$.each( actions, function( i, action ){
				action( field, settings, message );
			});
			return false;
		}
		$.each( undo, function( i, action ){
			action( field, settings );
		});
		return true;
	};
	function getLabel( field ){
		return field.parentNode.nodeName == 'LABEL' && field.parentNode
			|| field.id && $(field.form).find( 'label' ).filter('[@for='+field.id+']').get(0);
	};
	function findTarget( field ){
		var next = field.nextSibling;
		return field.parentNode.nodeName == 'LABEL' && field.parentNode
			|| next && next.nodeName == 'LABEL' && next
			|| field;
	};
	function getGroupMessage( field, message ){
		var label = getLabel( field );
		var prefix =  label && $(label).text() || field.name || field.id || '';
		if( prefix ) prefix += ' ';
		return prefix + message;
	};
	var uniqueClass = 'vf-error-item', uniqueSelector = '.' + uniqueClass;
	var	doActions = {
		singleError:function( field, settings, message ){
			var $target = $(findTarget( field ));
			if( $target.next().is( uniqueSelector ) )
				$target.next().text( message );
			else
				$(settings.singleErrorTemplate).addClass( uniqueClass ).text(message).insertAfter( $target );
		},
		groupError:function( field, settings, message ){
			if( !field.id ) field.id = getID();
			var msgID = field.id + '_msg', msg;
			message = getGroupMessage( field, message );
			if( msg = document.getElementById(msgID) ){
				$(msg).text( message );
			}else{			
				var container = settings.groupContainer && $(settings.groupContainer).get(0) || field.form;
				var $list = $(container.firstChild||[]);
				if( !$list.is( uniqueSelector ) )
					$list = $( settings.errorGroupTemplate ).addClass( uniqueClass ).prependTo( container );
				$(settings.errorItemTemplate).text( message ).attr('id', msgID).appendTo( $list );
			}
		},
		labelError:function( field, settings, message ){
			$(getLabel( field )||[]).addClass( settings.labelErrorClass ).attr( 'title', message );
		}
	};
	var undoActions = {
		singleError:function( field, settings ){
			$(findTarget( field )).next( uniqueSelector ).remove();
		},
		groupError:function( field, settings ){
			var $field = $('#'+ field.id +'_msg');
			if( !$field[0] )
				return;
			var $parent = $field.parent();
			$field.remove();
			if( !$parent.children()[0] )
				$parent.remove();
		},
		labelError:function( field, settings ){
			$(getLabel( field )||[]).removeClass( settings.labelErrorClass ).attr( 'title', '' );
		}
	};
	function getID(){
		return 'vf-uid-' + unique++;
	};
	var unique = 0;
	function getValidable( form ){
		var filtered = [ ], fields = form.elements, field, i=0;
		while( field = fields[i++] ){
			switch( field.className && (field.nodeName == 'INPUT' ? field.type : field.nodeName.toLowerCase()) ){
				case 'text':
				case 'password':
				case 'file':
				//case 'radio'://no need... ?
				case 'checkbox':
				case 'select':
				case 'textarea':filtered.push( field );
				default:break;
			}
		}
		return filtered;
	};
	
	$.validForm = {
		validators:{},
		addValidator:function( v ){//name, data, message, validator
			this.validators[v.name] = v;
		},
		setMessage:function( name, message ){
			if( this.validators[name] )
				this.validators[name].message = message;
		}
	};
	
	$.fn.validForm = function( settings ){
		settings = $.extend( {}, defaults, settings );
		
		var actions = [ ], undo = [ ];
		if( settings.errorLabels ){
			actions.push( doActions.labelError );
			undo.push( undoActions.labelError );
		}
		if( settings.singleErrors ){
			actions.push( doActions.singleError );
			undo.push( undoActions.singleError );
		}
		if( settings.groupErrors ){
			actions.push( doActions.groupError );
			undo.push( undoActions.groupError );
		}
		
		if( settings.realTime ){
			this.each(function(){
				$(getValidable(this)).bind( 'change', function( event ){
					validateElement( event.target, settings, actions, undo );
				});
			});
		}
		
		return this.bind('submit',function( event ){
			var valid = true, i=0, field, first = true;
			var fields = getValidable(this);
			while( field = fields[i++] ){
				if( !validateElement(field, settings, actions, undo) ){
					valid = false;
					if( first ){
						field.focus();
						if( field.select )
							field.select();
						first = false;
					}
				}
			}
			return valid;
		});
	};

})( jQuery );

(function( $ ){

	$.validForm.addValidator({ name:'required', message:'por favor, complete este campo.', validator:function( field ){
		switch(field.nodeName == 'INPUT' ? field.type : field.nodeName.toLowerCase()){
			//case 'radio': // no need... ?
			case 'checkbox': return field.checked;
			case 'select': //empty value will fail, '0' won't.
			default: return !!field.value;
		}
	}});
	
	$.validForm.addValidator({ name:'numeric',message:'enter a numeric value.',validator:function( field ){
		return !isNaN(parseInt(field.value));
	}});
	
	$.validForm.addValidator({ name:'minlen',message:'this must contain, at least, {0} characters.',validator:function( field, min ){
		return field.value.length >= parseInt(min);
	}});
	
	$.validForm.addValidator({ name:'maxlen',message:'this must contain, at most, {0} characters long.',validator:function( field, max ){
		return field.value.length <= parseInt(max);
	}});
	
	$.validForm.addValidator({ name:'email',data:/^[^@]+@[^.]+(\.[\w]{2,6}){1,3}$/,message:'Ingrese una direcci\xF3n de correo v\xE1lida.',validator:function( field, regex ){
		return regex.test( field.value );
	}});

	
	$.validForm.addValidator({ name:'max',message:'enter a number lower or equal to {0}.',validator:function( field, max ){
		return field.value <= parseInt(max);
	}});
	
	$.validForm.addValidator({ name:'min',message:'enter a number higher or equal to {0}.',validator:function( field, min ){
		return field.value >= parseInt(min);
	}});
	
	$.validForm.addValidator({ name:'between',message:'enter a number between {0} and {1}.',validator:function( field, min, max ){
		return field.value >= parseInt(min) && field.value <= parseInt(max);
	}});
	
	$.validForm.addValidator({ name:'repeat',message:'the values don\'t match.',validator:function( field, id ){
		return field.value == document.getElementById(id).value;
	}});
	
	$.validForm.addValidator({ name:'over',message:'you must be over {0}.',validator:function( field, minyear, format ){
		if( !format || format.length != 3 ) format = 'mdy';
		var date = field.value.split(/[-\s.,\\\/]/), limit = new Date();
		limit.setFullYear( limit.getFullYear() - minyear );
		var userdate = new Date( date[format.indexOf('y')], parseInt(date[format.indexOf('m')],10) - 1, parseInt(date[format.indexOf('d')],10) );
		return userdate != 'Invalid Date' && userdate.getTime() < limit.getTime();
	}});
	
	$.validForm.addValidator({ name:'splover',message:'you must be over {0}.',validator:function( field, minyear, monthid, dayid ){
		var date = [ field.value, document.getElementById(monthid).value, document.getElementById(dayid).value ]
		var limit = new Date();
		limit.setFullYear( limit.getFullYear() - minyear );
		var userdate = new Date( date[0], parseInt(date[1],10) - 1, parseInt(date[2],10) );
		return userdate != 'Invalid Date' && userdate.getTime() < limit.getTime();
	}});
		  
})( jQuery );