(function($){
	$.fn.validate = function(template){

		var $form = this;

		$form.bind('submit', function(e){

			var submit = true,
				$first_error_element = false;

			$form.find('[data-validation-rules]').each(function(){

				var $this	= $(this),
					$next	= $this.next(),
					rules	= $this.attr('data-validation-rules').split(' '),
					val		= $this.val(),
					error	= '';

				for(var i in rules)
				{
					if(typeof $.fn.validate[rules[i]] == 'function')
					{
						error = $.fn.validate[rules[i]](val);

						if(error !== true)
						{
							error = template.replace('{=error=}', $this.attr('data-error-message') || error);

							if($next.hasClass('error'))
							{
								$next.replaceWith(error);
							}
							else
							{
								$this.after(error);
							}

							submit = false;

							if(! $first_error_element)
							{
								$first_error_element = $this;
							}

							break;
						}
					}
				}

				if(error == true && $next.hasClass('error'))
				{
					$next.remove();
				}

			});

			if(! submit)
			{
				e.preventDefault();

				$first_error_element.focus();

				return false;
			}

		});
	};


	$.fn.validate.required = function(val)
	{
		return val != '' || 'Required';
	}

	$.fn.validate.validZip = function(val)
	{
		return /^([0-9]{5}([-][0-9]{4})?)?$/.test(val) || "Invalid ZIP code";
	}

	$.fn.validate.validAddress = function(val)
	{
		return /^[0-9a-zA-Z- .\']*$/.test(val) || "Invalid character(s) in address";
	}

	$.fn.validate.email = function(val)
	{
		return /^(([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6})?$/i.test(val) || "Invalid email address";
	}

	$.fn.validate.phoneUS = function(val)
	{
		val = val.replace(/[^0-9]/g, "");
		return /^([1]?[2-9][0-9]{2}[2-9][0-9]{6})?$/.test(val) || "Invalid phone number";
	}

	$.fn.validate.noPoBox = function(val)
	{
		if(/^([pP]{1}(.*?)[oO]{1}(.*?))?([bB][oO]?[xX])(\s+)([0-9]+)/i.test(val)){
			return "No PO Box allowed";
		}
		return true;
	}

	$.fn.validate.validName = function(val)
	{
		return /^[a-zA-Z- .\']*$/.test(val) || "Invalid character(s) in name";
	}

	$.fn.validate.numeric = function(val)
	{
		return /^[0-9]*$/.test(val) || "Numbers only";
	}

	$.fn.validate.decimal = function(val)
	{
		return /^[0-9]*([.][0-9]*)?$/.test(val) || "Decimal numbers only";
	}

	$.fn.validate.alpha = function(val)
	{
		return /^[a-zA-Z]*$/.test(val) || "Letters only";
	}

	$.fn.validate.alphanumeric = function(val)
	{
		return /^[0-9a-zA-Z]*$/.test(val) || "Letters or numbers only";
	}

	$.fn.validate.validCC = function(val){
		if(val == "")
		{
			return true;
		}
		var valid_format = false,
			valid_number = false,
			card_number = val.split("").reverse(),
			sum = 0;

		if(/^5[1-5][0-9]{14}$/.test(val) || /^4[0-9]{12}([0-9]{3})?$/.test(val) || /^3[47][0-9]{13}$/.test(val) || /^6011[0-9]{12}$/.test(val)){
			valid_format = true;
		}

		for(i = 0; i < card_number.length; i++){
			var num = card_number[i];

			if(i % 2 == 1){num *= 2;}      
			if(num > 9){num -= 9;}      

			sum += parseInt(num);
		}
		
		valid_number = (sum % 10 == 0);

		if(valid_number && valid_format){
			return true;
		}
		return "Invalid Credit Card";
	}


})(jQuery);
