$.fn.copyTo = function(to) {
	var to = $(to);
	for ( var i = 1; i < arguments.length; i++ )
		to.set( arguments[i], this.get(0)[ arguments[i] ] );
	return this;
};

var validateErrorCount = 0;

new function() {
	$.fn.validate = {
		init: function(o) {
			if ($(o).hasClass('required')) { this.required(o); };
			if ($(o).hasClass('email')) { this.email(o) };
			if ($(o).hasClass('phone')) { this.phone(o) };
			if ($(o).hasClass('integer')) { this.integer(o) };
			if ($(o).hasClass('float')) { this.float(o) };
			if ($(o).hasClass('ipv4')) { this.ipv4(o) };
			if ($(o).hasClass('url')) { this.url(o) };
		},
		required: function(o) {
			if (jQuery.trim(o.value) == ''){
				doError(o,'This field is required');
			}
			else {
				doSuccess(o);
			}
		},
		email: function(o) {
			var regex = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
			compareRegex(o, regex, 'not a valid email');
		},
		phone: function(o) {
			var regex = /^([\+][0-9]{1,3}[ \.\-])?([\(]{1}[0-9]{2,6}[\)])?([0-9 \.\-\/]{3,20})((x|ext|extension)[ ]?[0-9]{1,4})?$/;
			compareRegex(o, regex, 'not a valid phone number');
		},
		integer: function(o) {
			var regex = /^[\-\+]?\d+$/;
			compareRegex(o, regex, 'not a valid integer');
		},
		float: function(o) {
			var regex = /^[\-\+]?(([0-9]+)([\.,]([0-9]+))?|([\.,]([0-9]+))?)$/;
			compareRegex(o, regex, 'not a valid floating number');
		},
		ipv4: function(o) {
			var regex = /^((([01]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))[.]){3}(([0-1]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))$/;
			compareRegex(o, regex, 'not a valid ip address');
		},
		url: function(o) {
			var regex = /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/;
			compareRegex(o, regex, 'not a valid web address');
		}		
	};
	
	function compareRegex(o, regex, errorMessage)
	{
		if (o.value.match(regex)) {
			doSuccess(o);
		}
		else {
			doError(o, errorMessage);
		}
	}

	function doSuccess(o) {
		$(o).parent().find('.validateError').remove();
	}

	function doError(o,m) {
		validateErrorCount = validateErrorCount + 1;
		$(o).parent().find('.validateError').remove();
		$(o).parent().append("<div class=\"validateError\">" + m + "</div>");
	}
};
$(document).ready(function()
{
	// handle single element blur validation
	$(".validated").blur(function() {
		validateErrorCount = 0;
		$(this).validate.init(this);
	});
	
	// handle form submission
	$("form:first").submit(function(e) {
		validateErrorCount = 0;
		
		$(":input").each(function() {
			$(this).validate.init(this);
		});
		
		if (validateErrorCount > 0){
			e.preventDefault();
		}
	});
});
