(function($)
{
	$.fn.formValidator = function(options)
	{
	    $.formValidator.mergedOptions = $.extend(true, $.formValidator.defaults, options);
		$(this).click(function()
		{
			var result = $.formValidator();

			if (result && jQuery.isFunction(options.onSuccess))
			{
				options.onSuccess();
				return false;
			}
			else if (!result && jQuery.isFunction(options.onError))
			{
				options.onError();
				return false;
			}
			else
				return result;
		});
	};

	$.formValidator = function()
	{

		// merge options with defaults
		var mergedOptions = $.formValidator.mergedOptions;

		// result boolean
		var boolValid = true;

		// result error message
		var errorMsg = '';

		// clean errors
		$(mergedOptions.scope + ' .error-both, ' + mergedOptions.scope + ' .error-same, ' + mergedOptions.scope + ' .error-any' + mergedOptions.scope + ' .error-input, ' + mergedOptions.scope + ' .error-row').removeClass('error-both').removeClass('error-same').removeClass('error-any').removeClass('error-input');

		// gather inputs & check is valid
		$(mergedOptions.scope + ' .req-email, ' + mergedOptions.scope + ' .req-string, ' + mergedOptions.scope + ' .req-same, ' + mergedOptions.scope + ' .req-both, ' + mergedOptions.scope + ' .req-any, ' + mergedOptions.scope + ' .req-numeric, ' + mergedOptions.scope + ' .req-date, ' + mergedOptions.scope + ' .req-min, ' + mergedOptions.scope + ' .req-sortCode, ' + mergedOptions.scope + ' .req-nino, ' + mergedOptions.scope + ' .req-integer').each(function()
		{
			thisValid = $.formValidator.validate($(this), mergedOptions);
			boolValid = boolValid && thisValid.error;
			if (!thisValid.error)
				errorMsg = thisValid.message;
		});

		// check extra bool
		if (!mergedOptions.extraBool() && boolValid)
		{
			boolValid = false;
			errorMsg = mergedOptions.extraBoolMsg;
		}

		// submit form if there is and valid
		if ((mergedOptions.scope != '') && boolValid)
		{
			$(mergedOptions.errorDiv).fadeOut();
		}

		// if there is errorMsg print it if it is not valid
		if (!boolValid && errorMsg != '')
		{

			var tempErr = (mergedOptions.customErrMsg != '') ? mergedOptions.customErrMsg : errorMsg;
			$(mergedOptions.errorDiv).hide().html(tempErr).fadeIn();
		}

		return boolValid;
	};

	$.formValidator.validateInput = function(obj)
	{
		var mergedOptions = $.formValidator.mergedOptions;

		// result error message
		var errorMsg = '';

		// clean errors
		obj.removeClass('error-both').removeClass('error-same').removeClass('error-input').removeClass('error-any');

		// check is valid
		var thisValid = $.formValidator.validate(obj, mergedOptions);
		if (!thisValid.error)
			errorMsg = thisValid.message;
		return thisValid.error;
	}

	$.formValidator.validate = function(obj, opts)
	{
		var valAttr = obj.val();
		var css = opts.errorClass;
		var mail_filter = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
		var numeric_filter = /(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)|(^-?\d*$)/;
		var tmpresult = true;
		var result = true;
		var errorTxt = '';
		var group;

		// REQUIRED FIELD VALIDATION
		if (obj.hasClass('req-string'))
		{
			tmpresult = (valAttr != '');
			if (!tmpresult)
				errorTxt = opts.errorMsg.reqString;
			result = result && tmpresult;
		}

		// SAME FIELD VALIDATION
		if (obj.hasClass('req-same'))
		{
			tmpresult = true;
			group = obj.attr('rel');
			$(opts.scope + ' .req-same[rel="' + group + '"]').each(function()
			{
				if ($(this).val() != valAttr || valAttr == '')
					tmpresult = false;
			});
			if (!tmpresult)
			{
				$(opts.scope + ' .req-same[rel="' + group + '"]').parent().parent().addClass('error-same');
				errorTxt = opts.errorMsg.reqSame;
			}
			else
				$(opts.scope + ' .req-same[rel="' + group + '"]').parent().parent().removeClass('error-same');

			result = result && tmpresult;
		}

		// BOTH INPUT CHECKING
		// if one field entered, the others should too.
		if (obj.hasClass('req-both'))
		{
			tmpresult = true;

			if (valAttr != '')
			{
				group = obj.attr('rel');
				$(opts.scope + ' .req-both[rel="' + group + '"]').each(function()
				{
					if ($(this).val() == '')
						tmpresult = false;
				});

				if (!tmpresult)
				{
					$(opts.scope + ' .req-both[rel="' + group + '"]').parent().parent().addClass('error-both');
					errorTxt = opts.errorMsg.reqBoth;
				}
				else
					$(opts.scope + ' .req-both[rel="' + group + '"]').parent().parent().removeClass('error-both');
			}
			result = result && tmpresult;
		}

		// ANY INPUT CHECKING
		// only one of the inputs needs to be entered
		if (obj.hasClass('req-any'))
		{
			tmpresult = false;

			group = obj.attr("rel");
			$(opts.scope + ' .req-any[rel="' + group + '"]').each(function()
			{
				if ($(this).val() != '')
					tmpresult = true;
			});

			if (!tmpresult)
			{
				$(opts.scope + ' .req-any[rel="' + group + '"]').parent().parent().each(function()
				{
					$(this).addClass('error-any');
					$(this).animate({ height: opts.errorRowHeight }, "normal");
				});

				errorTxt = opts.errorMsg.reqAny;
			}
			else
			{
				$(opts.scope + ' .req-any[rel="' + group + '"]').parent().parent().each(function()
				{
					$(this).removeClass('error-any');
					$(this).animate({ height: opts.defaultRowHeight }, "normal");
				});
			}

			result = result && tmpresult;
		}

		// E-MAIL VALIDATION
		if (obj.hasClass('req-email'))
		{
			tmpresult = mail_filter.test(valAttr);
			if (!tmpresult) errorTxt = (valAttr == '') ? opts.errorMsg.reqMailEmpty : opts.errorMsg.reqMailNotValid;
			result = result && tmpresult;
		}

		// SORT CODE VALIDATION
		if (obj.hasClass('req-sortCode'))
		{
			var args = { Value: valAttr, IsValid: true };
			Validation.SortCode($("#ctl00_body_cusSortCode"), args);
			tmpresult = args.IsValid;
			if (!tmpresult)
				errorTxt = (valAttr == '') ? opts.errorMsg.reqMailEmpty : opts.errorMsg.reqMailNotValid;
			result = result && tmpresult;
		}

		// NINO VALIDATION
		if (obj.hasClass('req-nino'))
		{
			var args = { Value: valAttr, IsValid: true };
			Validation.NationalInsuranceNumber($("#ctl00_body_cusNationalInsuranceNumber"), args);
			tmpresult = args.IsValid;
			if (!tmpresult)
				errorTxt = (valAttr == '') ? opts.errorMsg.reqMailEmpty : opts.errorMsg.reqMailNotValid;
			result = result && tmpresult;
		}

		// DATE VALIDATION
		if (obj.hasClass('req-date'))
		{
			tmpresult = true;

			if (valAttr == "")
				tmpresult = false;
			else
			{
				var yearLastExp = new RegExp("^\\s*(\\d{1,2})([-/]|\\. ?)(\\d{1,2})(?:\\s|\\2)((\\d{4})|(\\d{2}))(?:\\s\u0433\\.)?\\s*$");
				var m = valAttr.match(yearLastExp);
				if (m == null)
					tmpresult = false;
				else
				{
					day = m[1];
					month = m[3];
					year = (m[5].length == 4) ? m[5] : GetFullYear(parseInt(m[6], 10))

					month -= 1;
					var date = new Date(year, month, day);
					if (year < 100)
						date.setFullYear(year);

					var tmpresult = (typeof (date) == "object" && year == date.getFullYear() && month == date.getMonth() && day == date.getDate()) ? date.valueOf() : null;
					if (!tmpresult)
						errorTxt = opts.errorMsg.reqDate;
				}
			}
			result = result && tmpresult;

		}

		// MINIMUM REQUIRED FIELD VALIDATION
		if (obj.hasClass('req-min'))
		{
			tmpresult = (valAttr.length >= obj.attr('minlength'));
			if (!tmpresult)
				errorTxt = opts.errorMsg.reqMin.replace('%1', obj.attr('minlength'));
			result = result && tmpresult;
		}

		// NUMERIC FIELD VALIDATION
		if (obj.hasClass('req-numeric'))
		{
			tmpresult = numeric_filter.test(valAttr);
			if (!tmpresult)
				errorTxt = opts.errorMsg.reqNum;
			result = result && tmpresult;
		}
		
		//INTEGER FIELD VALIDATION
        if (obj.hasClass('req-integer'))
        {
            if (valAttr == '')
                tmpresult = false;
            else
                tmpresult = !isNaN(valAttr);
            if (!tmpresult)
                errorTxt = opts.errorMsg.reqNum;
            result = result && tmpresult;
        }
        
        
        

//		if (obj.attr('rel'))
//		{
//			if (result)
//				$('#' + obj.attr('rel')).removeClass(css);
//			else
//				$('#' + obj.attr('rel')).addClass(css);
//		}
//		else
//		{
			if (result)
			{
				obj.removeClass(css);
				obj.parent().parent().removeClass('error-row');
				obj.parent().parent().animate({ height: opts.defaultRowHeight }, "normal");
			}
			else
			{
				obj.addClass(css);
				obj.parent().parent().addClass('error-row');
				obj.parent().parent().animate({ height: opts.errorRowHeight }, "normal");
			}
//		}

		return {
			error: result,
			message: ""
		};
	};

	// CUSTOMIZE HERE or overwrite by sending option parameter
	$.formValidator.defaults = {
		onSuccess: null,
		onError: null,
		scope: '',
		errorClass: 'error-input',
		errorDiv: '#warn',
		errorMsg: {
			reqString: 'Please complete the required fields',
			reqDate: 'Date entered is invalid',
			reqNum: 'Only numbers allowed',
			reqMailNotValid: 'E-mail is <b>not</b> valid',
			reqMailEmpty: 'Please complete e-mail',
			reqSame: 'Repeating inputs are not same',
			reqBoth: 'Related field(s) required',
			reqMin: 'Minimum %1 characters required',
			reqAny: 'At least one field required'
		},
		customErrMsg: '',
		extraBoolMsg: 'Please check the form for errors',
		extraBool: function() { return true; },
		defaultRowHeight: "24px",
		errorRowHeight: "45px"
	};
})(jQuery);