(
	function($)
	{
		$.fn.validateForm =
			function(options)
			{
				var defaults =
					{
						/** @type {string} селектор, который выбирает поля из формы, являющиеся обязательными */
						requiredFieldSelector: '.required',
						/** @type {string} селектор, который выбирает элемент, отправляющий форму */
						submitSelector: 'input[type=submit]',

						/** @type {bool} ставить ли класс label-элементу, который привязан к required-полю ввода */
						markAssociatedLabel: false,
						/** @type {string} класс, который добавляется к label-элементу, который привязан к required-полю ввода, если поле не заполнено */
						unfilledClass: 'unfilled',

						/** @type {string} html-код, который вставляется после к элемента, найденному по submitSelector. Если null, то не вставляется */
//						helpText: '<span style="display:block;width:20em;padding:0.2em 1em 1em"><small>Чтобы нажать кнопку отправки формы, заполните все обязательные поля (они отмечены символом «*» и <span style="color:#FF0000">красным цветом</span>)</small></span>',
						helpText: null,

						/** @type {object} хэш типа [идентификатор поля ввода] -> регулярное выражение, используется для проверки значения поля */
						valueRegexp:
							{},

						/** @type {object} хэш типа [идентификатор поля ввода] -> строка (идентификатор поля ввода), используется для проверки значения поля по эквивалентности */
						valueEquals:
							{},

						/** @type {function} вызывается при прохождении валидации */
						passedHandler:
							function ( submit, helpText )
							{
								submit.removeAttr('disabled')
								if ( helpText != null )
								{
									helpText.hide()
								}
							},
						/** @type {function} вызывается при провале валидации */
						failedHandler:
							function ( submit, helpText )
							{
								submit.attr('disabled', 'disabled')
								if ( helpText != null )
								{
									helpText.show()
								}
							},
						/** @type {function} */
						initHandler: null
					}
				var options = $.extend(defaults, options)

				/**
				 * возвращает привязанный к полю ввода элемент label
				 * @param {jQuery} self поле ввода, для которого надо найти привязанный к нему элемент label
				 * @returns {jQuery} привязанный к полю ввода элемент label
				 */
				function associatedLabel( self )
				{
					return $('label[for=' + self.attr('id') + ']', self.parents('form') )
				}

				/**
				 * @param {jQuery} self поле ввода
				 * @returns {bool} устаивает ли нас то, что введено в элемент
				 */
				function validateField( self )
				{
					/** @type {String} то, что введено в текущее поле ввода */
					var value = self.val()
					/** @type {String} идентификатор текущего поля ввода */
					var id = self.attr('id')

					var result

					// сначала выполним проверку того, что введено
					if ( options.valueRegexp[id] )
					{
						result = options.valueRegexp[id].test(value)
					}
					else
					{
						result = (value != '')
					}

					// если нужно проверить на соответствие со значением другого поля ввода, то проверим тоже
					if ( result && options.valueEquals[id] )
					{
						/** @type {jQuery} поле ввода, которое должно иметь тоже самое значение, что и текущее */
						var equalsInput = $('#' + options.valueEquals[id])
						if ( equalsInput.length == 1 )
						{
							result = (value == equalsInput.val() )
						}
					}

					return result
				}

				return this.each(
					function()
					{
						var requiredFields = $(options.requiredFieldSelector, this)
						if ( requiredFields.length > 0 )
						{
							/** @type jQuery элемент, отправляющий форму */
							var submit = $(options.submitSelector, this)

							/** @type {jQuery} элемент, который показывается после submit, если форма не прошла валидацию */
							var helpText = options.helpText
							if ( helpText != null )
							{
								helpText = $(options.helpText)
								helpText.appendTo( submit.parent() )
							}

							var validate =
								function ()
								{
									/** @type {bool} пойдена ли валидация всей формой */
									var validationPassed = true
									requiredFields.each(
										function ()
										{
											var self = $(this)
											if ( validateField(self) )
											{
												self.removeClass(options.unfilledClass)
												if ( options.markAssociatedLabel )
												{
													associatedLabel(self).removeClass(options.unfilledClass)
												}
											}
											else
											{
												validationPassed = false

												self.addClass(options.unfilledClass)
												if ( options.markAssociatedLabel )
												{
													associatedLabel(self).addClass(options.unfilledClass)
												}
											}
										}
									)

									if ( validationPassed )
									{
										options.passedHandler(submit, helpText)
									}
									else
									{
										options.failedHandler(submit, helpText)
									}
								}
							// если браузер уже подставил значения в поля, то мы их проверим
							validate()
							
							if( typeof(options.initHandler) == 'function' ){
								options.initHandler(validate);
							}

							// назначим обработчики событий для полей ввода
							requiredFields.each(
								function ()
								{
									$(this).keyup(validate)
									$(this).blur(validate)
									$(this).focus(validate)
								}
							)
						}

					}
				)
			}
	}
)(jQuery)