/***************************************************************
  jQuery.validate 1.6.0b    3/11/2010
  Author: John Norton - jukebox42@gmail.com
  This version works best with jquery 1.4.1
 ***************************************************************/
(function($) {
	var jvalidate = function($f, opts) {
		var self = this;
		var opt = {
			useSummary:		false,
			useStyles:		true,
			useTitles:		false,
			summaryStyle:	'validation-summary',
			messageStyle:	'validation-message',
			watermarkStyle:	'validation-watermark',
			styleParent:    false,
			summaryId:		'vsummary-',
			messageId:		'vmessage-',
			validationTag:	'ul',
			showValidation: true,
			itemCallback:	function(){return true;},
			formCallback:	function(){return true;},
			onCall:         function() {return true;},
			onBlur:         false,
			watermark:      true,
			attach:         'top'
		};
		
		$.extend(opt, opts ? opts : {});
		
		var doValidation = function(){
			if(!opt.onCall)
				return false;
			var r = true;
			var n = $f.attr('jvalidate');
			$('#'+opt.summaryId+n).remove();
			$.each($('input[validate], textarea[validate], select[validate]', $f), function(){
				var vo = validateItem($(this));
				if(!vo)
					r = false;
			});
			if(r)
				r = opt.formCallback();
			return r;
		};
		var validateItem = function($o){
			var f = $f.attr('jvalidate');
			var vo = true;
			if(opt.styleParent)
				$o.parent().removeClass('validation-passed validation-failed');
			else
				$o.removeClass('validation-passed validation-failed');
			if(opt.watermark && $o.attr('watermark') && $o.val() == $o.attr('watermark')){
				if(opt.styleParent)
					$o.val('').parent().removeClass(opt.watermarkStyle);
				else
					$o.val('').removeClass(opt.watermarkStyle);
			}
			$('#'+opt.messageId+f+'-'+escN($o.attr('name'))).remove();
			var validators = [['empty', function($o){return $o.val()=='';}, 'Please enter some text in this field.'],
							  ['checked', function($o){return !$o.is(':checked');}, 'It is required that you check this check box.'],
							  ['alpha', function($o){return !$o.val().match(/^[a-zA-Z]+$/);}, 'Please use letter only. For example Sketchy.'],
							  ['decimal', function($o){return !$o.val().match(/^[0-9]+$/);}, 'Please use decimal numbers only. For example 42.'],
							  ['number', function($o){return !$o.val().match(/^[-]?([1-9]{1}[0-9]{0,}(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|\.[0-9]{1,2})$/);}, 'Please use numbers only. For example -4.2.'],
							  ['email', function($o){return !$o.val().match(/^\w+([&\-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/);}, 'Please enter a valid email address. For example john@somedomain.com.'],
							  ['phone', function($o){return !$o.val().match(/^[01]?[- .]?\(?(?!\d[1]{2})[2-9]\d{2}\)?[- .]?(?!\d[1]{2})\d{3}[- .]?\d{4}$/);}, 'Please enter a valid US/Canada phone number. For example (603) 555-5555.'],
							  ['postal', function($o){return !$o.val().match(/^\d{5}-\d{4}|\d{5}|[A-Z]\d[A-Z] \d[A-Z]\d$/);}, 'Please enter a valid US/Canada postal code. For example 03102.'],
							  ['date', function($o){return !$o.val().match(/^([0-1][0-9])\/([0-3][0-9])\/(\d{4})$/);}, 'Please enter a valid date. For example 07/03/1987.']];
			var l = validators.length;
			if($o.is(':checkbox') && $o.attr('validate') != 'checked' ){ //validate multiple selections on checkbox/radiobutton groups
				var a = $o.attr('validate');
				var n = a.match(/.*min\[([\d]*)\].*/) ? a.match(/.*min\[([\d]*)\].*/)[1] : 0;
				var m = a.match(/.*max\[([\d]*)\].*/) ? a.match(/.*max\[([\d]*)\].*/)[1] : 99999;
				var t = $('input[name="'+escN($o.attr('name'))+'"]:checked', $f).size();
				vo = (t >= n && t <= m) ? vo : false;
				if(!vo)
					doReport($o, 'You have not met the selection requirements.');
			}else if($o.attr('validate').match(/regex\[([^\s]*)\]/)){ //create your own validator!!! regex[REGEX]
				var x = $o.val().match($o.attr('validate').match(/regex\[([^\s]*)\]/)[1]);
				if(x==null){
					doReport($o, 'Please match the information specified.');
					vo = false;
				}
			}else{
				for(i=0;i<l;i++){
					if(hasValidator($o, validators[i][0])&&validators[i][1]($o)){
						doReport($o, validators[i][2]);
						vo = false;
					}
				}
			}
			if(opt.useStyles){
				if(opt.styleParent)
					$o.parent().addClass((vo ? 'validation-passed' : 'validation-failed'));
				else
					$o.addClass((vo ? 'validation-passed' : 'validation-failed'));
			}
			if(vo)
				vo = opt.itemCallback();
			if(opt.watermark && $o.attr('watermark') && $o.val() == ''){
				if(opt.styleParent)
					$o.val($o.attr('watermark')).parent().addClass(opt.watermarkStyle);
				else
					$o.val($o.attr('watermark')).addClass(opt.watermarkStyle);
			}
			return vo;
		};
		var doReport = function($o, m){
			if($o.is(':checkbox') || $o.is(':radio')){
				var $c = $('input[name="'+escN($o.attr('name'))+'"]', $f);
				switch(opt.attach){
					case 'top': case 'custom': $o = $c.first(); break;
					case 'bottom': $o = $c.last(); break;
					default: $o = $c.first(); break;
				}
			}
			if(!opt.useSummary && opt.showValidation)
				writeMessage($o, m, $f);
			else if(opt.showValidation)
				writeSummary($o, m, $f);
		};
		var writeMessage = function($o, m){	
			var o = '<'+opt.validationTag+' class="'+opt.messageStyle+'" id="'+opt.messageId+$f.attr('jvalidate')+'-'+$o.attr('name')+'">'+(opt.validationTag=='ul' ? '<li>' : '')+(opt.useTitles==true&&$o.attr('title') ? $o.attr('title') : m)+(opt.validationTag=='ul' ? '</li>' : '')+'</'+opt.validationTag+'>';
			switch(opt.attach){
				case 'top': return $o.before(o); break;
				case 'bottom': return $o.after(o); break;
				case 'custom': return $o.attr('attach') ? $($o.attr('attach')).first().prepend(o) : $o.before(o); break;
				default: return $(opt.attach).first().prepend(o); break;
			}
		};
		var writeSummary = function($o, m){
			var f = opt.summaryId+$f.attr('jvalidate');
			if($('#'+f).size() < 1) { //if summary dosnt exist
				s = '<'+opt.validationTag+' class="'+opt.summaryStyle+'" id="'+f+'"></'+opt.validationTag+'>';
				switch(opt.attach){
					case 'top': $f.prepend(s); break;
					case 'bottom': $f.append(s); break;
					case 'custom': $f.attr('attach') ? $($f.attr('attach')).first().prepend(s) : $f.prepend(s); break;
					default: $(opt.attach).first().prepend(s); break;
				}
			}
			return $('#'+f).append('<'+(opt.validationTag=='ul' ? 'li' : opt.validationTag)+' id="'+opt.messageId+$f.attr('jvalidate')+'-'+$o.attr('name')+'">'+(opt.useTitles==true&&$o.attr('title') ? $o.attr('title') : m)+'</'+(opt.validationTag=='ul' ? 'li' : opt.validationTag)+'>');
		};
		var hasValidator = function($o, s){
			var s = ' '+s+' ';
			var v = ' '+$o.attr('validate')+' ';
			return (v.match(s) == null) ? false : v.match(s);
		};
		var escN = function(n){
			var a = new Array('#', ';', '&', ',', '.', '+', '*', '~', '\'', ':', '"', '!', '^', '$', '[', ']', '(', ')', '=', '>', '|', '/');
			var l = a.length;
			for(i=0;i<l;i++){
				n = n.replace(a[i], '\\'+a[i]);
			}
			return n;
		};
		//=======================================
		//init function
		var r = Math.floor(Math.random()*200);
		$f.attr('jvalidate', r);
		$f.bind('submit', function(){return doValidation();});
		if(opt.watermark){
			$('input[watermark], textarea[watermark]', $f).each(function() {
				var $t = $(this);
				if($t.val() == ''){
					if(opt.styleParent)
						$t.val($t.attr('watermark')).parent().addClass(opt.watermarkStyle);
					else
						$t.val($t.attr('watermark')).addClass(opt.watermarkStyle);
				}
				$t.bind('focus', function() {
						var $o = $(this);
						if($o.val() == $o.attr('watermark')){
							if(opt.styleParent)
								$o.val('').parent().removeClass(opt.watermarkStyle);
							else
								$o.val('').removeClass(opt.watermarkStyle);
						}
					}).bind('blur', function() {
						var $o = $(this);
						if($o.val() == ''){
							if(opt.styleParent)
								$o.val($o.attr('watermark')).parent().addClass(opt.watermarkStyle);
							else
								$o.val($o.attr('watermark')).addClass(opt.watermarkStyle);
						}
					});
			});
		}
		if(opt.onBlur){
			$.each($('input[validate]:checkbox, input[validate]:radio', $f), function() {
				var $c = $(this);
				var n = $c.attr('name');
				var v = $c.attr('validate');
				var t = $c.attr('title');
				$('input[name="'+escN(n)+'"]', $f).attr({validate: v, title: t});
			});
			$('input[validate], textarea[validate], select[validate]', $f).bind('blur', function(){return validateItem($(this));});
		}
		$f.data('jvalidate', self);
		//=======================================
	};
	
	$.fn.jvalidate = function(opt) {
		return this.each(function() {
			(new jvalidate($(this), opt));
		});
	};
})(jQuery);
