/*
 * Form validator
 * Validates text inputs and textareas. Parameters could be passed in "validator" attribute
 * or in ValidatorObjects array, where is the element identified by id.
 * 
 * Parameters must be in javascript object format and could include this keys:
 * 		allowBlank (true/false, default to true)
 * 		maskRe - allow only matched chars
 * 		regex - test value against the pattern
 * 		size - maximum size
 * 		minSize - minimum size
 * 		type ('numeric'/'email') - automatic settings packages
 * 		invalidMessage
 * 		invalidClass (default to 'invalid')
 * 
 * Example: <input type="text" validator="{allowBlank:false,regex:/^[abc]*$/,invalidMessage:'You can fill only one or more abc characters!'}" />
 * 
 * 
 * 
 * 2008 © Zuzana Burešová (zety@pilsfree.net), all rights reserved.
 */

var Validator = {
	
	/*
	 * Initialisation: register events on objects and forms, validates objects
	 */
	init: function() {
		/* inputs, buttons and textareas with "validator" attribute */
		var jobj = $("input[validator],textarea[validator]");
		Validator.registerEvents(jobj);
		jobj.map(function() {
			eval("var obj = "+$(this).attr("validator")+";");
			$(this).data("validator",obj);
			Validator.checkClass($(this));
		});
		
		/* objects defined diretly in javascript */
		if(typeof(ValidatorObjects) != "undefined") {
			jQuery.map(ValidatorObjects,function(item){
				var jobj = $("#" + item.id);
				jobj.data("validator",item)
				if(jobj.is("button")) {
					jobj.bind("click",Validator.formSubmit);
				} else {
					Validator.registerEvents(jobj);
					Validator.checkClass(jobj);
				}
			});
		}
		
		/* form submit */
		$("*[type=submit]").filter("*[validator]").map(function(){
			var jqthis = $(this);
			var butname = jqthis.attr("name");
			if($.browser.msie || jqthis.is("input")) {
				var content = jqthis.html();
				if(content == "") content = jqthis.val();
				var nbut = $("<button type='button'>"+content+"</button>");
				var atr = jqthis.attr("id");
				if(typeof(atr)!="undefined") nbut.attr("id",atr);
				var atr = jqthis.attr("validator");
				if(typeof(atr)!="undefined") nbut.attr("validator",atr);
				var atr = jqthis.attr("style");
				if(typeof(atr)!="undefined") nbut.attr("style",atr);
				var atr = jqthis.attr("class");
				if(typeof(atr)!="undefined") nbut.attr("class",atr);
				jqthis.after(nbut);
				jqthis.remove();
				jqthis = nbut;
			}
			else jqthis.attr("type","button");  // nefunguje v IE, ve firefox nefunguje na input!!!
			jqthis.click(function(e){
				jqthis = $(this);
				var form = jqthis.parents("form");
				if(Validator.formSubmit(form)) {
					var callback = form.data("callback");
					if(typeof(callback)!="undefined") {
						if(!callback(e)) return;
					}
					if(typeof(butname) != "undefined") {
						var val = jqthis.val();
						if(typeof(val) == "undefined" || val == "") val = jqthis.text();
						var butinfo = $("<input type='hidden' name='"+butname+"' value='"+val+"' />");
						butinfo.appendTo(form);
					}
					form.submit();
					if(typeof(btname) != "undefined") butinfo.remove(); // pokud by byla událost stornována
				} else Validator.showFormInvalidMessage();
			});
		});
	},
	
	/**
	 * add validation callback function on form submit
	 */
	addCallback: function(form,callback,check) {
		if(check==true) form.data("checkcallback",callback);
		else form.data("callback",callback);
	},
	
	/*
	 * called by init method
	 */
	registerEvents: function(jobj) {
		jobj.bind("blur",Validator.validate);
		jobj.bind("focus",Validator.editStartEvent);
	},
	
	/*
	 * focus handler - register keypress event
	 */
	editStartEvent: function(e) {
		Validator.active = $(this);
		Validator.oldValue = Validator.active.val();
		Validator.active.bind("keypress",Validator.keyPress);
	},
	
	/*
	 * key press handler - filter masked chars (maskRe) and call class checking function
	 */
	keyPress: function(e) {
		var jqthis = $(this);
		var params = jqthis.data("validator");
		if(typeof(params.maskRe) != "undefined" || (typeof(params.type) != "undefined" && params.type == "numeric")) {
			Validator.maskObject = jqthis;
			setTimeout("Validator.maskReCall()",10);
		}
		setTimeout("Validator.checkClass(Validator.active)",30);
	},
	maskObject: null,
	maskReCall: function() {
		var jqthis = Validator.maskObject;
		var oldvalue = jqthis.val();
		var params = jqthis.data("validator");
		var value = "";
		var maskRe;
		var zmena = 0;
		if(typeof(params.maskRe) != "undefined") {
			maskRe = params.maskRe;
			for(var i=0;i<oldvalue.length;i++) 
				if(maskRe.test(oldvalue.charAt(i))) value += oldvalue.charAt(i);
			if(value != oldvalue) zmena = 1;
			oldvalue = value;
		}
		if(typeof(params.type) != "undefined" && params.type == "numeric") {
			maskRe = /[\d]/;
			value = "";
			for(var i=0;i<oldvalue.length;i++) 
				if(maskRe.test(oldvalue.charAt(i))) value += oldvalue.charAt(i);
		}
		if(value != oldvalue || zmena == 1) jqthis.val(value);
	},
	
	/*
	 * add or remove invalid class acording to validation result
	 */
	checkClass: function(jqthis) {
		if(jqthis==null) return;
		var value = jqthis.val();
		var params = jqthis.data("validator");
		var invalidClass = (typeof(params.invalidClass) == "undefined") ? "invalid" : params.invalidClass;
		if(!Validator.isValid(params,value)) {
			if(!jqthis.hasClass(invalidClass)) jqthis.addClass(invalidClass);
		} else {
			if(jqthis.hasClass(invalidClass)) jqthis.removeClass(invalidClass);
		}
	},
	
	/*
	 * validate object on blur event - if invalid, show message and focus again
	 */
	validate: function(e) {
		var jqthis = $(this);
		var value = jqthis.val();
		var params = jqthis.data("validator");
		var invalidClass = (typeof(params.invalidClass) == "undefined") ? "invalid" : params.invalidClass;
		if(!Validator.isValid(params,value)) {
			e.stopPropagation();
			e.preventDefault();
			if(!jqthis.is("."+invalidClass)) jqthis.addClass(invalidClass);
			Validator.active = null;
			if(value != Validator.oldValue) {
				Validator.showInvalidMessage(params,value);		 
				jqthis.focus();
				if($.browser.mozilla) {
					Validator.firefoxBug_element = this;
					setTimeout("Validator.firefoxBug_element.focus()",100);
				}
			}
		} else {
			jqthis.removeClass(invalidClass);
			if(typeof(params.blurCallback) != "undefined") {
				params.blurCallback(value);
			}
			Validator.active = null;
		}
	},
	
	/*
	 * Validate given elements again (check class)
	 */
	revalidate: function(jq) {
		jq.each(function(){
			var jqthis = $(this);
			var params = jqthis.data("validator");
			if(typeof(params) != "undefined") Validator.checkClass(jqthis);
		});
	},
	
	/*
	 * check if the object is valid
	 */
	isValid: function(params,value) {
		var allowBlank = true;
		var regex;
		if (typeof(params.allowBlank) != "undefined") allowBlank = params.allowBlank;
		var size = value.length;
		if(size == 0 && allowBlank) return true;
		if(size == 0 && !allowBlank) return false;
		if(typeof(params.size) != "undefined" && params.size < size) return false;
		if(typeof(params.minSize) != "undefined" && params.minSize > size) return false;
		
		if(typeof(params.regex) != "undefined" && !params.regex.test(value)) return false;
		if(typeof(params.type) != "undefined") {
			if(params.type == "numeric") {
				regex = /^\d*$/;
				if(!regex.test(value)) return false;
			} else if(params.type == "email") {
				regex = /^([-.\w]+@[-.\w]+\.[-\w]+,\s*)*([-.\w]+@[-.\w]+\.[-\w]+)?$/;
				if(!regex.test(value)) return false;
				regex = /,\s*$/;
				if(regex.test(value)) return false;
			}
		}
		
		if(typeof(params.callback) != "undefined") {
			return params.callback(value);
		}
		
		return true;
	},
	
	/*
	 * message when blur is aborted
	 */
	showInvalidMessage: function(params,value) {
		if(typeof(params.invalidMessage) != "undefined") {
			window.alert(params.invalidMessage);
		} else {
			window.alert("Formulářové pole není vyplněno správně.");
		}
	},
	
	/*
	 * message when form submission is aborted
	 */
	showFormInvalidMessage: function() {
		window.alert("Formulář nelze odeslat - některá pole nejsou správně vyplněna.");
	},
	
	/*
	 * validate all validator objects in the form 
	 */
	formSubmit: function(form) {
		var valid = true;
		$("textarea, input[type=text], input[type=password]",form).each(function(){
			var params = $(this).data("validator");
			if(typeof(params) == "undefined") return;
			if(!Validator.isValid(params,$(this).val())) valid = false;
		});
		var callback = form.data("checkcallback");
		if(typeof(callback)!="undefined") {
			if(!callback()) return false;
		}
		return valid;
	},
	
	/*
	 * focused jquery object
	 */
	active: null,
	
	/*
	 * jquery object, which has last focus event
	 */
	active0: null,
	
	/*
	 * In Firefox doesn't work focus properly, it must be called with timeout from blur event
	 */
	firefoxBug_element: null,
	
	/*
	 * value on focus
	 */
	oldValue: null
};

$(document).ready(Validator.init);
