/**
 *	This is a javascript for automatic validation of form elements
 *	Simply put validator_numeric or validotor_... into the class attribute of your input tag
 *	For a more detailled documentation visit [TODO]
 *	@author		Georg Tavonius <g.tavionius@gmail.com>
 *	@homepage	http://code.jaz-lounge.com/formValidator
 *
 *	@version 0.1 <22-10-2007>
 */
 
//DEBUG STUFF:
var out = function(text, del) {
	if($('#sysOutput') && text)
		$('#sysOutput').html(text + '<br />' + $('#sysOutput').html());
	else return false;
};


Function.prototype.bind = function(obj) {
	var method = this,
		temp = function() {
		return method.apply(obj, arguments);
	};
	return temp;
} 

if(typeof jaz == 'undefined')
	var jaz = {};

if(typeof jaz.form == 'undefined')
	jaz.form = {};

// You may edit these options:
jaz.form.ValidatorOptions = {
	errorTag: 'span'			// tagname where to put in the error messages
,	errorClass: 'validationError'	// classname of error messages
,	errorPosition: 'after'		// 'before' and 'after' inserts before or after that input field and '#someid' appends it to #someid children
,	onBlur:	true				// (boolean) if true when blurring input field it checks if is valid or not
,	errorTemplate: '%msg%'	// How should an error look like? Following vars exist: 
											// %msg% => Error message, %inputid% => ID of input field what produces this error
											// %inputtitle% => Title of that input field
};

jaz.form.Validator = {
	filter: {},
	userMsgs: {},
	failure: false,
	options: jaz.form.ValidatorOptions,
	enhance: function() {
		$('form').submit( this.filterForm.bind(this));
		for(key in this.filter)
			if(this.options.onBlur)
				$('.validate_'+key).blur(this.handleFilter.bind(this));
	},
	addMsg: function(inputid, msg) {
		this.userMsgs[inputid] = msg;
	},
	addFilter: function(key, callback) {
		this.filter[key] = {};
		if(typeof callback != 'undefined') {
			if(typeof callback.method != 'undefined')
				this.filter[key].method = callback.method;
			else
				this.filter[key].method = function(string) { return string.match(callback.regex) ? true : false;};
			this.filter[key].message = callback.message;
		}
		return this;
	},
	filterForm: function(event) {
		this.failure = false;
		this.failures = {};
		for(key in this.filter) {
			$(event.target).children('.validate_'+key).each(function(i, el) {
					if(this.filter[key].method($(el).val()) !== true) {
						this.failure = true;
						var bid = this.showMessage(el, key);
						this.failures[el.name] = true;;
					}
					else if(this.failures[el.name] != true){
						this.hideMessage(el, key);
					}
				}.bind(this));
		};
		if(this.failure) {
			event.stopPropagation();
			return false;
			this.failure = true;
		} else {
			return true;
		};
	},
	showMessage: function(el, key) {
		var boxid = 'jazValidator_'+(el.alt ? '' : key+'_')+(el.name ? el.name : el.id); 
		if(!$('#'+boxid).length)
			this.createMessageContainer(el, boxid, this.filter[key].message);
		$('#'+boxid).fadeIn(400);//animate({display: 'block'}, 400);
		this.highlightMessage($(boxid));
	},
	createMessageContainer: function(el, boxid, msg) {
		if(!$('#'+boxid).length) {
			if(typeof this.userMsgs[el.nid] != 'undefined')
				msg = this.userMsgs[el.id];
			else if(el.alt)
				msg = el.alt;
			// insert this msg...
			msg = this.options.errorTemplate.replace(/%msg%/,msg).replace(/%inputid%/,el.id).replace(/%inputtitle%/,el.title);
			var content = '<'+this.options.errorTag+' id="'+boxid+'" class="'+this.options.errorClass+'">'+msg+'</'+this.options.errorTag+'>';
			if(this.options.errorPosition == 'before')
				$(el).before(content);
			else if(this.options.errorPosition == 'after')
				$(el).after(content);
			else {
				if($(this.options.errorPosition).length)
					$(this.options.errorPosition).slice(0,1).append(content);
				else // fallback if #errorPosition does not exist (better then not showing the errors)
					$(el).after(content);
			}
		}
		$('#jazValidator_'+el.id).hide();//animate({display: 'block'}, 400);
	},
	hideMessage: function(el, key) {
		var boxid = 'jazValidator_'+(el.alt ? '' : key+'_')+(el.name ? el.name : el.id);
		if($('#'+boxid).length) {
			$('#'+boxid).fadeOut(400);
		}
	},
	highlightMessage: function(jEl) {
		jEl.animate({backgroundColor: '#ff44ff'});
	},
	handleFilter: function(event) {
		var ok = true;
		for(key in this.filter)
			if($(event.target).hasClass('validate_'+key)) {
				if(this.filter[key].method($(event.target).val()) !== true) {
					this.showMessage(event.target, key);
					ok = false;
				}
				else if(ok)
					this.hideMessage(event.target, key);
			}
	}
};

jaz.form.Validators = {
	required: { // should contain any value
		method: function(string) { return string != ''; }
	,	message: 'This field is required.'
	}
,	digit: { // only digits
		regex: /^[0-9]*$/
	,	message: 'This field should only contain letters.'
	}
,	number: { // positive or negative decimal value using a dot (.) as separator
		regex: /^(-?[0-9]+(\.[0-9]+)?)?$/
	,	message: 'This field must contain a number.'
	}
,	numberComma: { // positive or negative decimal value using a comma (,) as separator
		regex: /^(-?[0-9]+(,[0-9]+)?)?$/
	,	message: 'This field must contain a number.'
	}
,	currency: { // positive or negative decimal value using a dot (.) as separator with only two fractional digits
		regex: /^(-?[0-9]+(\.[0-9]{0,2})?)?$/
	,	message: 'This field must contain an amount of money.'
	}
,	currencyC: { // positive or negative decimal value using a comma (,) as separator with only two fractional digits
		regex: /^(-?[0-9]+(,[0-9]{0,2})?)?$/
	,	message: 'This field must contain an amount of money.'
	}
,	uscanzip: {
		regex: /^(([0-9]{5}([\- ])[0-9]{4})|([0-9]{5})|([AaBbCcEeGgHhJjKkLlMmNnPpRrSsTtVvXxYy]\d[A-Za-z]\s?\d[A-Za-z]\d))?$/
	,	message: ''
	}
,	germanzip: { // A german postal code
		regex: /^([0-9]{5})?$/
	,	message: 'This field must contain a number.'
	}
,	string: { // a string containing alphanumeric chars and some punctuation or nothing
		regex: /^[a-zA-Z0-9\.,\-_ ]*$/
	,	message: 'This field must not contain any special characters.'
	}
,	alpha: { // alphanumeric chars
		regex: /^[a-zA-Z]*$/
	,	message: 'This field should only contain letters.'
	}
,	alphanum: { // alphanumeric chars and digits
		regex: /^[a-zA-Z0-9]*$/
	,	message: 'This field should only contain letters and digits.'
	}
,	alphaDE: { // alphanumeric chars
		regex: /^[a-zA-ZäöüÄÖÜ]*$/
	,	message: 'This field should only contain letters.'
	}
,	alphanumDE: { // alphanumeric chars and digits
		regex: /^[a-zA-ZäöüÄÖÜ0-9]*$/
	,	message: 'This field should only contain letters and digits.'
	}
,	email: { // an email address
		regex: /^([a-zA-Z0-9\-\.\_]+\@[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,4})?$/
	,	message: 'This field should contain a valid email adress.'
	}
,	url: { // an web adress of some kind
		regex: /^((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)?$/
	,	message: 'This field should contain a web adress.'
	}
,	isbn: {
	}
,	creditcard: {
	}
};

jaz.form.Validator.addFilter('number', jaz.form.Validators.number)
		.addFilter('numberC', jaz.form.Validators.numberComma)
		.addFilter('digit', jaz.form.Validators.digit)
		.addFilter('currency', jaz.form.Validators.currency)
		.addFilter('currencyC', jaz.form.Validators.currency)
		.addFilter('required', jaz.form.Validators.required)
		.addFilter('string', jaz.form.Validators.string)
		.addFilter('alpha', jaz.form.Validators.alpha)
		.addFilter('alphanum', jaz.form.Validators.alphanum)
		.addFilter('alphaDE', jaz.form.Validators.alphaDE)
		.addFilter('alphanumDE', jaz.form.Validators.alphanumDE)
		.addFilter('mail', jaz.form.Validators.email)
		.addFilter('url', jaz.form.Validators.url)
		.addFilter('germanzip', jaz.form.Validators.germanzip)
		.addFilter('uscanzip', jaz.form.Validators.uscanzip);

jaz.form.Validator.addMsg('opt', 'Select one!!!');

$(document).ready(function() {
	jaz.form.Validator.enhance();
});
