/*
	Validator v2.0 2010-03-27

	Made in Imperavi. All rights reserved.

	http://www.imperavi.com

	Code is released under a GNU General Public Licens http://www.opensource.org/licenses/gpl-license.php
*/
var Validator = Class.extend({
	init: function(element, options)
	{
		/*
			Options
		*/
		this.options = {
			callback: false,
			trigger: false,
			box: false,
			errorClassName: 'error_ins',
			tooltip: false
		}
		
		jQuery.extend(this.options, options);
		
		this.collection = [];		
		
		this.element = jQuery('#' + element);
		this.element.submit(function() { return false });
		
		
		if (!this.options.trigger) this.options.trigger = jQuery('#' + element + ' INPUT[type="submit"]');
		else this.options.trigger = jQuery('#' + this.options.trigger);
		
		this.options.trigger.click(function()
		{
			this.validate();
		}.bind(this));
		
	},
	add: function(element, method, options)
	{
		if (typeof(options) == 'undefined') var options = {};
		
		options.name = element;
		options.element = jQuery(document.getElementsByName(element));
		options.method = method;
		options.error = true;
		
		this.collection.push(options);	
	},
	remove: function(element, method)
	{
		jQuery.each(this.collection, 
			function(i, s)
			{
				if (s.element.name == element && s.method == method)
				{
                    this.collection.splice(i, 1);
					this.hideError(s);
				}
			}.bind(this)
		);	
	},
	destroy: function()
	{
		this.collection = [];
		this.hideAllError();
	},
	showError: function(object)
	{
		if (object.method != 'isCheckAny') object.element.addClass(this.options.errorClassName);
		
		if (this.options.tooltip && typeof(object.text) != 'undefined')
		{
			if (!$('#span_validate_' + object.name).length)
			{
				var pos = object.element.offset();
				var height = object.element.height();
				var top = pos.top + 20;
				var span = $('<div id="span_validate_' + object.name + '">' + object.text + '</div>');
				span.css({zIndex: 1000, width: '120px', display: 'none', opacity: 0.8, top: top + 'px', left: pos.left + 'px', fontSize: '11px', 'position': 'absolute', 'background-color': '#842323', 'color': '#fff', 'padding': '5px 10px'});
				$(document.body).append(span);
				$(span).fadeIn();
			}
			else
			{
				$('#span_validate_' + object.name).text(object.text);
			}
			
			
			object.element.click(function(){ $('#span_validate_' + object.name).fadeOut(); });			
		}
		else if (!this.options.box && typeof(object.text) != 'undefined')
		{
			if (typeof(object.show) != 'undefined') jQuery('#' + object.show).text(object.text);
			else jQuery('#' + object.name + '_error').text(object.text);
		}
	},
	hideError: function(object)
	{
		object.element.removeClass(this.options.errorClassName);
		
		if (this.options.tooltip && typeof(object.text) != 'undefined')
		{
			$('#span_validate_' + object.name).remove();
		}
		else if (!this.options.box && typeof(object.text) != 'undefined')
		{
			if (typeof(object.show) != 'undefined') jQuery('#' + object.show).text('');
			else jQuery('#' + object.name + '_error').text('');
		}		
	},
	hideAllError: function()
	{
		jQuery.each(this.collection, 
			function(i, s)
			{
				this.hideError(s);
			}.bind(this)
		);
	},	
	validate: function()
	{
		this.wait = [];
		
		jQuery.each(this.collection, 
			function(i, s)
			{
				if (s.method != 'Ajax') $.extend(this.collection[i], { error: this.validator(s, i)} );
				else
				{
					this.validator(s, i);
					this.wait[i] = false;
				}
			}.bind(this)
		);
		
		if (!this.wait) this.process();
		else
		{
		  var re = setInterval(function()
		  {

		  	var wait = 0;
			jQuery.each(this.wait, 
				function (s)
				{
					if (s != 'undefined' && s === false) wait++;
				}
			);

   			if (wait == 0)
			{

				this.process();
				clearInterval(re);
	  		}

		  }.bind(this), 300);
		}
		

		return false;
			
	},
	process: function()
	{
		var errors = 0;
		var errors_obj = [];
		
		if (this.options.box)
		{
			var box = jQuery('<ul>');
			jQuery('#' + this.options.box).html('').hide();
		}
		
		jQuery.each(this.collection, 
			function(i, s)
			{
				if (!s.error)
				{

					errors_obj.push(s);
				
					errors++;
				
				}
				else this.hideError(s);
				
			}.bind(this)
		);
		

		if (errors != 0)
		{		
			jQuery.each(errors_obj, function(i, s)
			{
				if (this.options.box)
				{
					var li = jQuery('<li>').text(s.text);
					jQuery(li).appendTo(box);
					this.showError(s);
				}
				else this.showError(s);
			}.bind(this));
		}

		if (this.options.box && errors != 0)
		{
			jQuery(box).appendTo(jQuery('#' + this.options.box));
			jQuery('#' + this.options.box).show();
			this.scrollTo(this.options.box);
		}

		if (errors == 0)
		{
			if (this.options.callback)
			{
				this.hideAllError();
				this.options.callback();
			}
			else
			{
				var el = jQuery('<input type="hidden" name="' + this.options.trigger.get(0).name + '" value="' + this.options.trigger.get(0).name + '" />');
				jQuery(el).appendTo(this.element);

				this.element.unbind('submit');
				this.element.submit();				
			}
		}
	
	},		
	validator: function(object, iterator)
	{
		var element = object.element;
		var method = object.method;
		var val = element.val();

		switch(method)
		{
			case 'isNotEmpty':
				return !this.blank(val);
			break;
			case 'isNotNull':
				if (val == 0) return false;
				else return true;
			break;			
			case 'isString':
				return !!val.match(/^[\-\w\W]+$/gi);
			break;
			case 'isLatinString':
				return !!val.match(/^[\-\w]+$/gi);
			break;
			case 'isNumber':			
				return !!val.match(/(^-?\d+$)/);
			break;
			case 'isMax':
				return val.length <= object.max;
			break;
			case 'isMin':
				return val.length >= object.min;
			break;
			case 'isEqual':
				return val.length == object.equal;
			break;
			case 'isDate':
				if (typeof(object.date) == 'undefined') // d.m.Y
				{
					d = val.match(/^(\d{2})\.(\d{2})\.(\d{4})$/);
				  	return d && !!(d[1]<=31 && d[2]<=12 && d[3]<=9999) || false;
				}
				else if (object.date = 'Y-m-d')
				{
					d = val.match(/^(\d{4})-(\d{2})-(\d{2})$/);
				  	return d && !!(d[1]<=9999 && d[2]<=12 && d[3]<=31) || false;
				}
			break;
			case 'isDatetime':
				if (typeof(object.datetime) == 'undefined') // d.m.Y H:i:s
				{
				  	dt = val.match(/^(\d{2})\.(\d{2})\.(\d{4})\s(\d{2}):(\d{2}):(\d{2})$/);
				  	return dt && !!(dt[1]<=31 && dt[2]<=12 && dt[3]<=9999 && dt[4]<=59 && dt[5]<=59 && dt[6]<=59) || false;
				}
				else if (object.datetime = 'Y-m-d H:i:s')
				{
				  	dt = val.match(/^(\d{4})-(\d{2})-(\d{2})\s(\d{2}):(\d{2}):(\d{2})$/);
				  	return dt && !!(dt[1]<=9999 && dt[2]<=12 && dt[3]<=31 && dt[4]<=59 && dt[5]<=59 && dt[6]<=59) || false;
				}
			break;
			case 'isTime':
			  	dt = val.match(/^(\d{2}):(\d{2}):(\d{2})$/);
			  	return dt && !!(dt[1]<=59 && dt[2]<=59 && dt[3]<=59) || false;
			break;
			case 'isEmail':
			  	return !!val.match(/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i);
			break;
			case 'isRange':
				return val.length >= object.min && val.length <= object.max;;
			break;
			case 'isMatch':
				var value =  jQuery(document.getElementsByName(object.target)).val();
				if (this.blank(value))return false;
				return val == value;
			break;
			case 'isCheck':
				return element.get(0).checked;
			break;
			case 'isCheckAny':
					
				var count = 0;	
				var cl = object.className;
				
				jQuery.each(jQuery('.' + cl),
					function (i, s)
					{
						if (jQuery(s).get(0).checked) count++;
					}
				);
				
				if (count == 0) return false;			
				else return true;
				
			break;
			case 'Ajax':
				if (typeof(object.params) != 'undefined')
				{
					if (typeof(object.params) == 'function') var add_params = object.params();
					else var add_params = object.params;
				}
				else var add_params = '';

				if (element !== false) var params = 'value=' + escape(encodeURIComponent(val));
				else var params = '';
			
				$.ajax({url: object.url, type:'POST', data: params + add_params, success: function(data)
					{
						this.processAjax(element, method, iterator, data);
					}.bind(this)
				});
				
			break;
		
		}		
	},
	processAjax: function(element, method, iterator, data)
	{

		if(data != 'error') this.collection[iterator].error = true;
		else this.collection[iterator].error = false;

		this.wait[iterator] = true;
	},
	blank: function(text)
	{
       return !text || !/\S/.test(text);
	},
	scrollTo: function(element)
  	{
	    element = jQuery('#' + element);
    	var pos = element.offset();
	    window.scrollTo(pos['left'], pos['top']);
	}
});


