﻿
//callback signature: function(srcElement, shown, isInit) { this; /*slideTargets*/ }

(function ($) {

	function Test(test, inv, cb, tgts, trueTgts, falseTgts) {
		this.testFunction = test;
		this.inverse = inv;
		this.callbackFunction = cb;
		this.toggleTargets = tgts;
		this.trueTargets = trueTgts;
		this.falseTargets = falseTgts;
	}

	Test.prototype.doTest = function (src) {
		return this.testFunction.apply(src);
	};

	var storeDefaults = function () {
		$("select").each(function () {
			var $this = $(this);
			$this.data("enhancedSlide-defaultValue", $this.find("option:selected").val());
		});
		$("input:checkbox,input:radio").each(function () {
			var $this = $(this);
			$this.data("enhancedSlide-defaultValue", $this.attr("checked"));
		});
	};

	var slideTest = function (tests, isInit) {
		var updateValidators = function ($container, enable) {
			var valIds = [];
			$.each(Page_Validators, function () {
				valIds[valIds.length] = this.id;
			});
			var $spans = $container.find("#" + valIds.join(",#"));
			if ($spans.length > 0) {
				$.each(Page_Validators, function () {
					if ($spans.is("#" + this.id)) {
						if (!enable || typeof (this.enabled) != "undefined") {
							//							if (enable && !$(this).parent().is(":visible")) alert("got one!");
							if (!enable || $(this).parent().is(":visible")) {		//parent container must be visible if enabling
								ValidatorEnable(this, enable);
								var $this = $("#" + this.controltovalidate);
								if (($this.is("select") && $this.find("option:selected").val() == $this.data("enhancedSlide-defaultValue")) || 	//hide validator if field value hasn't been changed to avoid showing errors prematurely
									($this.is("input:checkbox,input:radio") && $this.attr("checked") == $this.data("enhancedSlide-defaultValue")) ||
									$this.val() == ($this.attr("defaultValue") ? $this.attr("defaultValue") : "")) {
									this.isvalid = true;
									ValidatorUpdateDisplay(this);
								};
							};
						};
					};
				});
			};
		};
		var show = function (src, cb) {
			$.each(this, function () {
				var $this = $(this);
				this.slideDown(undefined, function () {
					window.setTimeout(function () {
						$this.hide().show();
					}, 1);
					if (Page_Validators) updateValidators($this, true);
					//					if (!isInit && $(src).is("input:checkbox,input:radio")) {
					//						//						$this.find("input:visible:enabled:first,textarea:visible:enabled:first,select:visible:enabled:first").filter(":first").focus();
					//					};
					if (cb) cb.apply(this, [src, true, isInit]);
				});
				//				if (Page_Validators) updateValidators($this, true);
			});
		};
		var hide = function (src, cb) {
			$.each(this, function () {
				this.slideUp(undefined, function () {
					if (Page_Validators) updateValidators($(this), false);
					//					if (!isInit && $(src).is("input:checkbox,input:radio")) {
					//						//						$(src).nextInDom("input:visible:enabled,textarea:visible:enabled,select:visible:enabled").focus();
					//					};
					if (cb) cb.apply(this, [src, false, isInit]);
				});
				//				if (Page_Validators) updateValidators($(this), false);
			});
		};
		for (var i = 0; i < tests.length; i++) {
			var result = tests[i].doTest(this);
			if ($.isArray(tests[i].toggleTargets)) {
				if (!result != !tests[i].inverse) {
					show.apply(tests[i].toggleTargets, [this, tests[i].callbackFunction]);
				}
				else {
					hide.apply(tests[i].toggleTargets, [this, tests[i].callbackFunction]);
				};
			};
			if (result) {
				if ($.isArray(tests[i].trueTargets)) show.apply(tests[i].trueTargets, [this, tests[i].callbackFunction]);
				if ($.isArray(tests[i].falseTargets)) hide.apply(tests[i].falseTargets, [this, tests[i].callbackFunction]);
				return;
			};
		}
	};

	var prepareTests = function () {
		var argArray = [];
		$.each(arguments, function () {
			argArray[argArray.length] = this;
		});
		if (this.length == 0) return this;
		var internalArguments = argArray.splice(0, 1);
		var inverse = (internalArguments[0] == 1);
		var tests = [];
		var defaultTest = function () {
			return ((this.is("input:checkbox") || this.is("input:radio")) && this.attr("checked")) ||
				(this.is("option") && this.attr("selected")) ||
				(this.is("input:text") && !!this.val());
		};
		var any = function (fn) {
			for (var i = 0; i < this.length; i++) {
				if (fn.apply(this[i])) {
					return true;
				};
			}
			return false;
		};
		var select = function (fn) {
			var out = [];
			for (var i = 0; i < this.length; i++) {
				out[out.length] = fn.apply(this[i]);
			}
		};
		var a = argArray;
		switch (a.length) {
			case 1:
				if ($.isArray(a[0])) {		//e.g. slideTest([{testFn1, ($)target1}, {testFn2, ($)target2}]); or slideTest([{testFn1, ($)trueTgt1, ($)falseTgt1}, {testFn2, ($)trueTgt2, ($)falseTgt2}]);
					if (any.apply(a[0], [function () {
						return this.length > 2;
					} ])) {		//e.g. slideTest([{testFn1, ($)trueTgt1, ($)falseTgt1}, {testFn2, ($)trueTgt2, ($)falseTgt2}]);
						for (var i = 0; i < a[0].length; i++) {
							var test = new Test(a[0][i][0], inverse);
							test.trueTargets = $.isArray(a[0][i][1]) ? select.apply(a[0][i][1], [function () {
								return $(this);
							} ]) : [$(a[0][i][1])];
							if (a[0][i].length > 2) {
								test.falseTargets = $.isArray(a[0][i][2]) ? select.apply(a[0][i][2], [function () {
									return $(this);
								} ]) : [$(a[0][i][2])];
							};
							tests[tests.length] = test;
						}
					}
					else {
						var allTargets = select.apply(select.apply(a[0], [function () {
							return this[1]
						} ]), [function () {
							return $.isArray(this) ? select.apply(this, [function () {
								return $(this);
							} ]) : [$(this)];
						} ]);
						for (var i = 0; i < a[0].length; i++) {
							var test = new Test(a[0][i][0], inverse);
							test.trueTargets = $.isArray(a[0][i][1]) ? select.apply(a[0][i][1], [function () {
								return $(this);
							} ]) : [$(a[0][i][1])];
							test.falseTargets = except.apply(allTargets, [test.trueTargets]);
							tests[tests.length] = test;
						}
					};
				}
				else {	//e.g. slideTest(($)target);
					tests[tests.length] = new Test(defaultTest, inverse, null, [$(a[0])]);
				};
				break;
			case 2:
				if ($.isFunction(a[0])) {	//e.g. slideTest(testFn, ($)target);
					tests[tests.length] = new Test(a[0], inverse, null, [$(a[1])]);
				}
				else if ($.isArray(a[0])) {
					if (any.apply(a[0], [function () {
						return this.length > 2;
					} ])) {		//e.g. slideTest([{testFn1, ($)trueTgt1, ($)falseTgt1}, {testFn2, ($)trueTgt2, ($)falseTgt2}]);
						for (var i = 0; i < a[0].length; i++) {
							var test = new Test(a[0][i][0], inverse, a[1]);
							test.trueTargets = $.isArray(a[0][i][1]) ? select.apply(a[0][i][1], [function () {
								return $(this);
							} ]) : [$(a[0][i][1])];
							if (a[0][i].length > 2) {
								test.falseTargets = $.isArray(a[0][i][2]) ? select.apply(a[0][i][2], [function () {
									return $(this);
								} ]) : [$(a[0][i][2])];
							};
							tests[tests.length] = test;
						}
					}
					else {
						var allTargets = select.apply(select.apply(a[0], [function () {
							return this[1]
						} ]), [function () {
							return $.isArray(this) ? select.apply(this, [function () {
								return $(this);
							} ]) : [$(this)];
						} ]);
						for (var i = 0; i < a[0].length; i++) {
							var test = new Test(a[0][i][0], inverse, a[1]);
							test.trueTargets = $.isArray(a[0][i][1]) ? select.apply(a[0][i][1], [function () {
								return $(this);
							} ]) : [$(a[0][i][1])];
							test.falseTargets = except.apply(allTargets, [test.trueTargets]);
							tests[tests.length] = test;
						}
					};
				}
				else if ($.isFunction(a[1])) {
					tests[tests.length] = new Test(defaultTest, inverse, a[1], [$(a[0])]);
				}
				else {
					tests[tests.length] = new Test(defaultTest, inverse, null, null, [$(a[0])], [$(a[1])]);
				};
				break;
			case 3:
				if ($.isFunction(a[0])) {
					if ($.isFunction(a[2])) {
						tests[tests.length] = new Test(a[0], inverse, a[2], [$(a[1])]);
					}
					else {
						tests[tests.length] = new Test(a[0], inverse, null, null, [$(a[1])], [$(a[2])]);
					};
				}
				else {
					tests[tests.length] = new Test(defaultTest, inverse, a[2], null, [$(a[0])], [$(a[1])]);
				};
				break;
			case 4:
				tests[tests.length] = new Test(a[0], inverse, a[3], null, [$(a[1])], [$(a[2])]);
				break;
		}
		return tests;
	};

	var register = function (tests) {
		var $this = $(this);
		if ($this.is("input:checkbox,input:radio")) {
			$this.change(function () {
				slideTest.apply($(this), [tests]);
			});
		};
		if ($this.is("input:text,textarea")) {
			$this.keyup(function (e) {
				if (e.keyCode != 9) {
					slideTest.apply($(this), [tests]);
				};
			});
		};
		if ($this.is("select")) {
			$this.change(function () {
				slideTest.apply($(this), [tests]);
			});
		};
	};

	jQuery.fn.registerSlideUp = function () {
		var argArray = [1];
		$.each(arguments, function () {
			argArray[argArray.length] = this;
		});
		var tests = prepareTests.apply(this, argArray);
		register.apply(this, [tests]);
		slideTest.apply($(this), [tests, true]);
		return this;
	};

	jQuery.fn.registerSlide = function () {
		var argArray = [0];
		$.each(arguments, function () {
			argArray[argArray.length] = this;
		});
		var tests = prepareTests.apply(this, argArray);
		register.apply(this, [tests]);
		slideTest.apply($(this), [tests, true]);
		return this;
	};

	jQuery.fn.nextInDom = function (filter) {
		var $this = $(this), $target = $this, $result = null, index = -1;
		do {
			$result = $target.find(filter);
			if ($result.length > 0) {
				var i = $result.index($this);
				$result = $result.filter((i == -1 ? ":eq(0)" : ":gt(" + $result.index($this) + ")") + ":first"); 	//if any, find index of $this, then take next item after $this
			};
		} while ($result.length == 0 && ($target = $target.parent()).length > 0);
		return $result;
	};

	jQuery.fn.previousInDom = function (filter) {
		var $this = $(this), $target = $this, $result = null, index = -1;
		do {
			$result = $target.find(filter);
			if ($result.length > 0) {
				var i = $result.index($this);
				$result = $result.filter((i == -1 ? ":eq(0)" : ":lt(" + $result.index($this) + ")") + ":last"); 	//if any, find index of $this, then take next item after $this
			};
		} while ($result.length == 0 && ($target = $target.parent()).length > 0);
		return $result;
	};

	$(document).ready(function () {
		storeDefaults.apply(this);
	});
})(jQuery);


