(function($){
	$.fn.extend({ 
		monitor: function(options, errors) {
			var defaultOptions = {
				regex: false,
				minlength: false,
				maxlength: false,
				required: false,
				blankValue: false,
				rbParentSelector: false,
				displayError: true,
				keepDisplay: false,
				errorTarget: false,
				errorAttribute: false,
				errorElementCreatedCallback: false,
				errorCallback: false,
				validCallback: false,
				animationDuration: false,
				initialValidation: false,
				validateOnChange: true,
				validateOnBlur: true,
				validateOnFocus: false,
				preValidationFunction: false,
				customValidationFunction: false,
				customValidationFunctionArgs: false
			};
			options = $.extend(defaultOptions, options);
			if (options.maxlength == -1) {
				options.maxlength = this.maxlength ? parseInt(this.maxlength) : false;
			}
			if (options.animationDuration === false) {
				options.animationDuration = 0;
			}
			var defaultErrors = {
				regex: "Bitte korrigieren Sie das Format Ihrer Eingabe.",
				minlength: "Bitte geben Sie mindestens " + options.minlength + " Zeichen ein.",
				maxlength: "Bitte geben Sie höchstens " + options.maxlength + " Zeichen ein.",
				required: "Dies ist ein Pflichtfeld."
			};
			errors = $.extend(defaultErrors, errors);
			
			
			return this.each(function() {
				var that = this;
				var isCheckbox = this.tagName.toLowerCase() == "input" && this.type.toLowerCase() == "checkbox";
				var isRadioButton = this.tagName.toLowerCase() == "input" && this.type.toLowerCase() == "radio";
				var isSelect = this.tagName.toLowerCase() == "select";
				
				var errorElm = false;
				if (options.displayError) {
					if (options.errorTarget !== false) {
						errorElm = $(options.errorTarget);
					} else if (!$(this).next() || $(this).next().attr('class') != 'error') {
						$(this).after('<label class="error" for="' + this.id + '"></label>');
						errorElm = $(this).next('label.error');
					} 
					if (options.errorElementCreatedCallback !== false) {
						options.errorElementCreatedCallback(errorElm);
					}
				}
				
				var setError = function(message) {
					if (options.errorAttribute !== false) {
						errorElm.attr(options.errorAttribute, message);
					} else {
						errorElm.html(message);
					}
				};
				this.handleError = function(errorType, message) {
					if (errorElm !== false) {
						setError(message);
						if (!options.keepDisplay) errorElm.fadeIn(options.animationDuration);
					}
					if (options.errorCallback !== false && typeof options.errorCallback == "function") {
						options.errorCallback(errorType, message, errorElm, $(this));
					}
				};
				
				var hideErrorElement = function() {
					if (errorElm !== false) {
						if (!options.keepDisplay) {
							errorElm.fadeOut(options.animationDuration, function() {setError("");});
						} else {
							setError("");
						}
					}
					if (options.validCallback !== false && typeof options.validCallback == "function") {
						options.validCallback(errorElm, $(that));
					}
				};

				if (options.customValidationFunction !== false) {
					this.validateIt = function(reactOnError) {
						reactOnError = reactOnError == undefined ? true : reactOnError;
						var result;
						if (options.customValidationFunctionArgs !== false) {
							result = options.customValidationFunction(that, options.customValidationFunctionArgs);
						} else {
							result = options.customValidationFunction(that);
						}
						if (result !== true) {
							if (reactOnError) that.handleError("custom", result);
							return false;
						} else {
							if (reactOnError) hideErrorElement();
							return true;
						}
					};
				} else if (isCheckbox) {
					this.validateIt = function(reactOnError) {
						reactOnError = reactOnError == undefined ? true : reactOnError;
						if (options.required && !that.checked) {
							if (reactOnError) that.handleError("required", errors.required);
							return false;
						} else {
							if (reactOnError) hideErrorElement();
							return true;
						}
					};
				} else if (isRadioButton) {
					this.validateIt = function(reactOnError) {
						reactOnError = reactOnError == undefined ? true : reactOnError;
						var parSel = options.rbParentSelector !== false ? options.rbParentSelector + " " : "";
						rbElms = $(parSel + "input[name='" + this.name + "']:checked");
						if (options.required && rbElms.val() == undefined) {
							if (reactOnError) that.handleError("required", errors.required);
							return false;
						} else {
							if (reactOnError) hideErrorElement();
							return true;
						}
					};
				} else if (isSelect) {
					this.validateIt = function(reactOnError) {
						reactOnError = reactOnError == undefined ? true : reactOnError;
						if (options.blankValue !== false && options.required && $(that).val() == options.blankValue) {
							if (reactOnError) that.handleError("required", errors.required);
							return false;
						} else {
							if (reactOnError) hideErrorElement();
							return true;
						}
					};
				} else {
					this.validateIt = function(reactOnError) {
						reactOnError = reactOnError == undefined ? true : reactOnError;
						var val;
						if (options.preValidationFunction === false) {
							val = that.value;
						} else {
							val = options.preValidationFunction(that.value);
						}
						if (options.required && val.length == 0) {
							if (reactOnError) that.handleError("required", errors.required);
							return false;
						} else if (options.minlength !== false && val.length < options.minlength && (options.required || val.length > 0)) {
							if (reactOnError) that.handleError("minlength", errors.minlength);
							return false;
						} else if (options.maxlength !== false && val.length > options.maxlength) {
							if (reactOnError) that.handleError("maxlength", errors.maxlength);
							return false;
						} else if (options.regex !== false && !options.regex.test(val) && (options.required || val.length > 0)) {
							if (reactOnError) that.handleError("regex", errors.regex);
							return false;
						} else {
							if (reactOnError) hideErrorElement();
							return true;
						}
					};
				}
				
				if (options.validateOnChange) {
					$(this).keyup(function(e) {
						if (e.which != 9) this.validateIt();
					}).change(function() {
						this.validateIt();
					});
				}
				if (options.validateOnBlur) {
					$(this).blur(function() {
						this.validateIt();
					});
				}
				if (options.validateOnFocus) {
					$(this).focus(function() {
						this.validateIt();
					});
				}
				if (options.initialValidation) {
					this.validateIt();
				}
			});
		}
	});
})(jQuery);

(function($){
	$.fn.extend({ 
		validateAll: function(reactOnError) {
			reactOnError = reactOnError == undefined ? true : reactOnError; 
			var elms = $(this).find("input, textarea, select");
			var isValid = true;
			for (var i = 0; i < elms.length; i++) {
				if (typeof(elms[i].validateIt) !== 'undefined' && !elms[i].validateIt(reactOnError)) {
					isValid = false;
				}
			}
			if (!isValid) {
				alert("Bitte prüfen Sie Ihre Eingaben und beachten Sie die markierten Felder.");
			}
			return isValid;
		}
	});
})(jQuery);
