// A cache for all the validations
var validators = [];

function validate_all(){
	var all_valid = true;
	for(var i = 0; i < validators.length; i++){
		var validator = validators[i];
		if(validate(validator[0], validator[1])) continue;
		all_valid = false;
	}
	return all_valid;
}

// Takes a target and a validator
// it both validates and displays errors 
function validate($target, validator){
	var valid = validator($target);
	if(valid === true){
		$target.hideError();
		return true;
	} else {
		$target.addError(valid);
		return false;
	};
}

// Simple validator for required fields
function validate_required(val){
	return val != "";
}

var validate_email_email_reg = /^[\w\.%\+\-]+@(?:[A-Z0-9\-]+\.)+(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|jobs|museum)$/i;
// Simple validator for email
function validate_email(val){
	return validate_email_email_reg.test(val);
}


// Will validate a range. If you don't supply high,
// Then it just makes sure its larger than the "low"
function validate_range(val, low, high){
	if(typeof(high) === "undefined"){
		return val >= low;
	} else {
		return val >= low && val <= high;
	}
}

// Will validate a length range. If you don't supply high,
// Then it just makes sure its larger than the "low"
function validate_length(val, low, high){
	if(typeof(high) === "undefined"){
		return val.length >= low;
	} else {
		return val.length >= low && val.length <= high;
	}
}

(function($){
	$.fn.addValidation = function(events, validation_function, message){
		if(typeof(events) == "string") events = [events];
		
		return this.each(function(){
			
			var $target = $(this);

			jQuery.each(events, function(i, el){
				if(typeof(validation_function) == "string"){
					if(validation_function == "required"){
						validation_function = function($target){
							if(!validate_required($target.val())) return message;
							return true;
						}
					}
				}
				
				$target.bind(el, function(){
					validate($target, validation_function);
				});					

			});

			validators.push([$target, validation_function]);
		});
	}
	
	$.fn.addError = function(msg){
		return this.each(function(){
			var $a = $(this).add($(this).parent()).next('span.error');
			if($a.length == 0){
				$a = $("<span class='error'></span>").insertAfter($(this));
			}
			$a.html(msg);
		});
	};
	
	$.fn.hideError = function(){
		return this.each(function(){
			$(this).add($(this).parent()).next('span.error').remove();
		});
	};
	
	$.AjaxUnique = function(el, url, options){
		var base = this;
		base.$el = $(el);
		base.el = el;
		
		base.$el.data('AjaxUnique', base);
		
		base.min = 3;
		base.max = 40;
		base.timer = null;
		base.valid = true;
		base.not_run = true;
		base.inprogress = false;
		base.url = url;
	
		
		base.init =function(){
			base.options = $.extend({},$.AjaxUnique.defaultOptions, options);
			base.delay = base.options.delay;
			
			base.$el.change(function(){
				base.clearTimer();
				base.startRequest();
			});
			
			if(base.options.autoTrigger){
			
				base.$el.keyup(function(e){
					var k = String.fromCharCode(e.keyCode);
					if("abcdefghijklmnopqrstuvwxyz -_1234567890".indexOf(k.toLowerCase()) > -1){
						base.resetTimer();
					}
				});
			}
			
			if(base.$el.val() != ""){
				base.startRequest();
			}
			
			validators.push([base.$el, function($target){
				return base.validate();
			}])
		}
		
		base.validate = function(force){
			if(!base.options.test(base.$el.val())){
				base.valid = true;
				base.not_run = true;
				return true;
			}
			if(base.not_run || force === true){
				base.startRequest();
				return base.options.in_progress;
			}
			if(base.inprogress) return base.options.in_progress;
			if(base.valid == false) return base.options.invalid;
			
			return true;
		}
		
		base.startRequest = function(){

			var val = base.$el.val();			
			if(!base.options.test(val)){
				base.valid = true;
				base.not_run = true;
				return;
			}

			base.inprogress = true;			
			base.not_run = false;
			base.$el.addClass(base.options.loadingClass);
			base.$el.trigger('checking_started.unique');
			
			// 	 base.endRequest('no',true);
			// 	 return;
			// }
			// 
			$.post(base.url, {
				validation_check: val,
				validation_type: base.options.type
			}, function(data, text_success){
				base.endRequest(data);
			}, 'text');
		}
		
		base.endRequest = function(data, skipped){
			base.inprogress = false;
			base.$el.removeClass(base.options.loadingClass);
			base.$el.trigger('checking_ended.unique');
			
			if(/no/i.test(data)){
				base.valid = true;
				if(skipped !== true) base.$el.hideError();
			} else {
				base.valid = false;
				base.$el.addError(base.options.invalid);
			}
		}
		
		base.resetTimer = function(){
			base.clearTimer();
			base.timer = window.setTimeout(function(){
				base.startRequest();
				base.timer = null;
			}, base.delay);
		}
		
		base.clearTimer = function(){
			if(base.timer) window.clearTimeout(base.timer);
		}
		
		base.init();
		
	}
	$.AjaxUnique.defaultOptions = {
		in_progress: "",
		invalid: "",
		type: "",
		loadingClass: "loading",
		delay: 300,
		autoTrigger: true
	}
	
	$.fn.ajaxUnique = function(url, options){
		return this.each(function(){
			(new $.AjaxUnique(this, url, options));
		});
	};
	
	$.fn.ajaxUniqueValid = function(force){
		if(this.length == 0) return 'Object not found';
		if(force !== true) force = false;
		
		var data = $(this[0]).data('AjaxUnique');
		
		if(data){
			return data.validate(force);
		} else {
			return 'Validator not found';
		}
	}
})(jQuery);