(function($){
	var _masks = {
		number: { mask:/^(-)?(\d*)(\.?)(\d*)$/ },
		date: { mask:/^\d{1,2}\/\d{1,2}\/\d{4}/ },
		time: { mask:/^\d{1,2}:\d{2}[ ]?(am|pm)?$/i },
		datetime: { mast:/^\d{1,2}\/\d{1,2}\/\d{4} \d{1,2}:\d{2}[ ]?(am|pm)?$/i }
	};

	function _require(el) {
		var $el = $(el);
		
		var valid = true;
		
		if(($el.is(':checkbox') && $el.is(':checked') === false) || 
			($el.is('input, select, textarea') && !$el.val())) {
			valid = false;
		}
		
		return valid;
	}
	
	function _mask(val, v) {
		var el = this, valid = true;
		
		if(v.mask && v.mask.test && val) {
			var test = v.mask.test(val);
			if((!test && !v.validIfFalse) || (test && v.validIfFalse)) {
				valid = false;
			}
		}
		
		return valid;
	}
	
	function _checkValidators(el) {
		var that = this, $el = $(el), options = this.options;
		var valid = true;
		
		var validators = this._getData('_validators');
		
		$.each(validators, function(key, v) {
			if($el.hasClass('ui-simplevalidator-validator-' + key)) {
			    var val;
			    try { val = $el[0].value; }
			    catch(err) { }
				if(!v.validate.apply(el, [val, v])) {
					valid = false;
					return false;
				}
			}
		});
		
		return valid;
	}
	
	function _validate(el) {
		var that = this, options = this.options, $el = $(el);
		
		var valid = true;
		if(options.ignoreHidden && $el.is(':hidden')) {
		    return;
		}
		
		if(($el.hasClass('ui-simplevalidator-required') && !_require.call(that, el)) || (
			$el.hasClass('ui-simplevalidator-validator') && !_checkValidators.call(that, el))) {
			valid = false;
		}
		
		if(valid) {
			$el.removeClass(options.errorClass);
		} else {
			$el.addClass(options.errorClass);
		}
	}
	
	function _validateAll() {
		var that = this, $ui = $(this.element[0]);
		
		$ui.find('input, select, textarea, .ui-simplevalidator-validator').each(function() {
			_validate.call(that, this);
		});
	}
	
	function _setValidators() {
		var self = this, options = this.options;
		
		var validators = {};

		$.each(options.validators, function(i, v) {
			if(v.mask && typeof v.mask === 'string' && _masks[v.mask]) {
				v.validIfFalse = _masks[v.mask].validIfFalse;
				v.mask = _masks[v.mask].mask;
				v.validate = _mask;
			} else if(v.mask && typeof v.mask === 'object' && v.test) {
				v.validate = _mask;
			}
			
			validators['v'+i] = v;
		});
		
		self._setData('_validators', validators);
	}

	function _bindEvents() {
		var that = this, options = this.options, $ui = $(this.element[0]);
		
		var validate = function() {
			_validate.call(that, this);
		};
		
		var $els = $ui.find('input, select, textarea');
		$.each(options.events, function(i, event) {
			$els[event](validate);
		});
		
		if(options.requiredSelector) {
			$ui.find(options.requiredSelector).addClass('ui-simplevalidator-required');
		}
		
		var validators = that._getData('_validators');
		$.each(validators, function(key, v) {
			if(v.selector) {
				$ui.find(v.selector).addClass('ui-simplevalidator-validator').addClass('ui-simplevalidator-validator-' + key);
			}
		});
		
		if(options.submitButton) {
			$(options.submitButton).click(function(evt) {
				_validateAll.call(that);
				if($ui.find('.' + options.errorClass).length) {
					evt.stopImmediatePropagation();
				}
			});
		}
	}

	$.widget('ui.simpleValidator', {
		_init: function() {
			var self = this, options = this.options;
			
			_setValidators.call(self);
			
			_bindEvents.call(self);
			
			if(options.validateOnInit) {
				_validateAll.call(self);
			}
		},
		
		validate: function() {
			_validateAll.call(this);
		},
		
		valid: function() {
			_validateAll.call(this);
			return $(this.element[0]).find('.' + this.options.errorClass).length === 0;
		},
		
		reset: function() {
		    $(this.element[0]).find('.' + this.options.errorClass).removeClass(this.options.errorClass);
		}
	});
})(jQuery);

$.extend($.ui.simpleValidator, {
	version: '1.5',
	getter: 'valid',
	defaults: {
		validators: [],
		events: ['blur','change'],
		errorClass: 'ui-state-error',
		submitButton: '',
		requiredSelector: '[rel=required]',
		validateOnInit: false,
		ignoreHidden: true
	}
});