(function($){
	$.fn.validate = function(options) {
		
		var callbacks = {
			error: function($field, error_type){
				$field.addClass('field-error');
				
				setTimeout(function(){
					$field.removeClass('field-error');
				}, 5000);
			},
			before: function(){},
			validate: function(){
				
				var valid = true;
				var $form = $(this);
				$form.removeClass('xv-valid');
				var email_regex = new RegExp(settings.email_re);
				
				settings['before']($form);
				
				$form.find(':input[required]').each(function(){
					
					var local_valid = true;
					if ($(this).is(':checkbox') && !$(this).is(':checked'))
						local_valid = false;
					else if ($(this).is(':radio') && !$form.find(':radio[name="'+$(this).attr('name')+'"]:checked').length)
						local_valid = false;
					else if ($(this).val() == '')
						local_valid = false;
					
					if (!local_valid) {
						settings['error']($(this), 'required');
						valid = false;
					}
				});
				
				$form.find(':input[type="email"]').each(function(){
					if ($(this).val() != '' && !email_regex.test($(this).val())) {
						settings['error']($(this), 'email');
						valid = false;
					}
				});
				
				$form.find(':input[pattern]').each(function(){
					
					var regex = new RegExp($(this).attr('pattern'));
					if ($(this).val() != '' && !regex.test($(this).val())) {
						settings['error']($(this), 'pattern');
						valid = false;
					}
				});
				
				$form.find(':input[xv\\:sameas]').each(function(){
					
					var $rel = $form.find($(this).attr('xv:sameas'));
					if ($(this).val() != $rel.val()) {
						settings['error']($(this), 'sameas');
						valid = false;
					}
				});
				
				$form.find(':input[xv\\:ajax]').each(function(){
					
					if ($(this).val() == '')
						return;
					
					var $input = $(this);
					$.ajax({
						async: false,
						url: $input.attr('xv:ajax'),
						type: 'POST',
						data: { value: $input.val() },
						dataType: 'json'
					}).success(function(data){
						if (data.success)
							return;
						
						settings['error']($input, 'ajax');
						valid = false;
					});
				});
				
				if (valid)
					$form.addClass('xv-valid');
				
				return valid;
			}
		};
		
		var settings = {
			error: callbacks['error'],
			before: callbacks['before'],
			email_re: '^[_\\.0-9a-zA-Z-]+@([0-9a-zA-Z][0-9a-zA-Z_-]+\\.)+[a-z]{2,4}$'
		};
		
		if (options) { 
			$.extend(settings, options);
		}
		  
		return this.each(function() {
			$(this).attr("novalidate", "true");
			$(this).submit(callbacks.validate);
		});
	};
})( jQuery );
