Validator = {};

Validator.fields = [];

/**
 * Validator functions return true if a value is valid, false othervise
 */
Validator.validators = {
		notempty:	function (field){return typeof field.val() != 'undefined' && !!$.trim(field.val());},
		positive:	function (field){return typeof field.val() != 'undefined' && !isNaN(parseFloat(field.val())) && parseFloat(field.val()) > 0;},
		nonegative:	function (field){return typeof field.val() != 'undefined' && !isNaN(parseFloat(field.val())) && parseFloat(field.val()) >= 0;},
		integer:	function (field){return typeof field.val() != 'undefined' && !isNaN(parseInt(field.val())) && parseInt(field.val()) == field.val();},
		number:		function (field){return typeof field.val() != 'undefined' && !isNaN(parseInt(field.val()));},
		email:		function (field){return typeof field.val() != 'undefined' && field.val().test(/^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/);},
		external:	function (field){
							var caller = $.post;
							
							if (Validator.options.method == 'get')
							{
								caller = $.get;
							}
							
							// Sending a request
							var flds = Validator.options.addfields;
							flds.f = field.attr('name');
							flds.v = field.val();
							caller(
									Validator.options.url,
									flds,
									function(data) {
										if (data.toLowerCase() != Validator.options.okstring)
										{
											Validator.BuildErrorBlock(field,Validator.options.usetext?data:Validator.GetErrorMessage('external'));
										}
										else
										{
											Validator.BuildOKBlock(field);
										}
									},
									'plain'
								);
							
							return true;
						}
	};

Validator.errors = {
		// Default error message
		'######':	'Неверное значение!',
		notempty:	'Неверное значение! Вы должны запомнить это поле!',
		positive:	'Неверное значение! Вы должны ввести положительное число!',
		nonegative:	'Неверное значение! Вы должны ввести неотрицательное число!',
		integer:	'Неверное значение! Вы должны ввести целое число!',
		number:		'Неверное значение! Вы должны ввести число!',
		email:		'Неверное значение! Некорректный адрес email!'
	};

Validator.options = {
		url:		'',		// URL to send AJAX request
		method:		'post',	// AJAX request method
		usetext:	true,	// Use response text (other than "true" as error message)
		addfields:	{},		// Additional fields to send alongside AJAX request
		okstring:	'true',	// String that indicates that check is OK on server side
		timer:		1500	// Time in milliseconds of check timer
	};

Validator.Log = function (arg)
{
	if ( !window['console'] || !window.console['log'] ) return;
	
	console.log(arg);
};

Validator.log = function(arg)
{
	this.Log(arg);
};

Validator.Init = function(options)
{
	// Foreaching options
	for (var i in options)
	{
		if (typeof this.options[i] != 'undefined')
		{
			this.options[i] = options[i];
		}
	}
	
	// Foreaching containers
	for (var i = 0; i < options.forms.length; i++)
	{
		var flds = $(options.forms[i]).find('input[v_validate=\'yes\'], textarea[v_validate=\'yes\'], select[v_validate=\'yes\']');
		
		for (var j = 0; j < flds.length; j++ )
		{
			var fld = $(flds[j]);
			
			// Filtering:
			if (
				fld[0].tagName.toLowerCase() == 'input' &&
				fld.attr('type').toLowerCase() != 'text' &&
				fld.attr('type').toLowerCase() != 'password'
			)
			{
				continue;
			}
			
			var tmpchecks = fld.attr('v_validate_type').split(',');
			var checks = [];
			for(var k = 0; k < tmpchecks.length; k++)
			{
				tmpchecks[k] = $.trim(tmpchecks[k]);
				if ('' != tmpchecks[k])
				{
					checks.push(tmpchecks[k]);
				}
			}
			
			if (!checks.length)
			{
				continue;
			}
			
			this.fields.push({
					fld:fld,
					chex:checks,
					timer:false
				});
			fld.attr('v_validate_id',this.fields.length-1);
			
			function InitCheck()
			{
				var object = $(this);
				var val_id = object.attr('v_validate_id');
				
				clearTimeout(Validator.fields[val_id].timer);
				Validator.fields[val_id].timer = setTimeout(function(){
						// Looking for check options
						var ok = true;
						for (var l = 0; l < Validator.fields[val_id].chex.length; l++)
						{
							if (typeof Validator.validators[Validator.fields[val_id].chex[l]] == 'function' && Validator.fields[val_id].chex[l] == 'external' && object.val())
							{
								if (!Validator.validators[Validator.fields[val_id].chex[l]](object) && Validator.fields[val_id].chex[l] != 'external')
								{
									ok = false;
//									var message = typeof Validator.errors[Validator.fields[val_id].chex[l]] != 'undefined'?Validator.errors[Validator.fields[val_id].chex[l]]:Validator.errors['######'];
									Validator.BuildErrorBlock(object, Validator.GetErrorMessage(Validator.fields[val_id].chex[l]));
									break;
								}
							}
							if(Validator.fields[val_id].chex[l] == 'external')
							{
								ok = false;
							}
						}
						if (ok)
						{
							Validator.BuildOKBlock(object);
						}
						
					},Validator.options.timer);
			}
			
			// Binding events
			fld.bind('blur',InitCheck);
			fld.bind('keyup',InitCheck);
			
			this.log('Bound to :');
			this.log(fld[0]);
		}
	}
	
	// Foreaching additional validator functions
	for (var i in options.validators)
	{
		if (typeof options.validators[i] == 'function' && typeof this.validators[i] == 'undefined')
		{
			this.validators[i] = options.validators[i];
		}
	}
	
	// Foreaching additional validator error messages
	for (var i in options.errors)
	{
		if (typeof options.errors[i] == 'string')
		{
			this.errors[i] = options.errors[i];
		}
	}
};

Validator.GetErrorMessage = function (check)
{
	return typeof this.errors[check] != 'undefined'?this.errors[check]:this.errors['######'];
};

Validator.BuildErrorBlock = function (object, message)
{
	Validator.RemoveValidatorBlocks(object);
	object.parent().append($('<div class="validator_error" id="validator_error_'+object.attr('v_validate_id')+'">'+message+'</div>'));
};

Validator.BuildOKBlock = function (object)
{
	Validator.RemoveValidatorBlocks(object);
	object.parent().append($('<div class="validator_ok" id="validator_ok_'+object.attr('v_validate_id')+'"></div>'));
};

Validator.RemoveValidatorBlocks = function (object)
{
	$('#validator_error_'+object.attr('v_validate_id')+'').remove();
	$('#validator_ok_'+object.attr('v_validate_id')+'').remove();
};
