/**
 * Цэ ж градусник! Он же тэрмомитэр.
 */
nulljs.load("com.nulljs.(dom|array|event|random|css|context|ajax)").module("modules.permissions.pickers", function (api) {

	// some useful shortcuts for nulljs API
	var _ = api.com.nulljs,
		$ = _.dom(), $append = $.append,
		A = _.array, addEventListener = _.event.addEventListener, CSS = _.css(),
		context = _.context;

	var stopEvent = function (f) {
		return function (event) {
			return (f.call(this, event), _.event.stopEvent(event));
		};
	};

	var $parent = function (element) {
		return element.parentNode;
	};

	var $insertBefore = function (where, what) {
		return ($parent(where).insertBefore(what, where), what);
	};

	var $id = function (element_or_id) {
		return (typeof element_or_id == "object") ? element_or_id : $.id(element_or_id);
	};

	var $style = function (element, styles) {
		for(var i in styles) {
			element.style[i] = styles[i];
		}
		return element;
	};

	var findPermissionByIndex = function (list, index) {
		return A(list).filter(function (p) { return p.index == index })[0] || undefined;
	};

	var findPermissionById = function (list, id) {
		return A(list).filter(function (p) { return p.id == id})[0] || undefined;
	};

	var last = function (list) {
		return list[list.length - 1];
	};

	var first = function (list) {
		return list[0];
	};

	var Picker = function (container_id, input_id, default_value, blue_group, red_group) {
		var controls = {}, red, blue, permissions, current, slaves = [], active_range = [-Infinity, Infinity];

		var makeOption = function (permission) {
			return addEventListener(
				addEventListener(
				addEventListener(
					$append($("a", "", {href: "#"}), $("i"), $.text(permission.title || "")),
					"mouseover", stopEvent(function () { onMouseOver(permission.index); })),
					"mouseout", function () { onMouseOut(permission.index); }),
					"click", stopEvent(function () { onClick(permission); }));
		};

		var inRange = function (index) {
			return (active_range[0] <= index) && (active_range[1] >= index);
		};

		var onMouseOver = function (index) {
			var crossZero = false,
				diff = index > 0 ? -1 : 1,
				i = index,
				k = index + diff;

			while(!!controls.flat[k]) {
				controls.flat[k].className = inRange(k) ? "" : "blocked";
				k -= diff;
			}

			while(!!controls.flat[i]) {
				controls.flat[i].className = crossZero ? ( inRange(i) ? "" : "blocked") : inRange(i) ? "highlight" : "blocked";
				i += diff;
				if(i == 0) {
					crossZero = true;
				}
			}

			controls.flat[current.index].className += " current";
		};

		var onMouseOut = function (index) {
			CSS.removeClass(controls.flat[index], "highlight");
		};

		var onClick = function (permission) {
			if(inRange(permission.index)) {
				current && CSS.removeClass(controls.flat[current.index], "current");
				current = permission;
				controls.flat[permission.index].className += " current";
				controls.input.value = permission.id;

				CSS.removeClass(current.index < 0 ? controls.blue_group : controls.red_group, "rg-current");
				CSS.addClass(current.index > 0 ? controls.blue_group : controls.red_group, "rg-current");

				A(slaves).forEach(function (slave) {
					slave.onMasterChange(current.id);
				});
			}
		};

		var restoreDefault = function () {
			onMouseOver(current.index);
		};

		var onMasterChange = function (id) {
			setIdRange(-Infinity, id);
		};

		var setRange = function (min, max) {
			active_range = [min, max];
			var new_index = current.index > max ? max : current.index < min ? min : current.index;
			if(new_index != current.index) {
				onClick(findPermissionByIndex(permissions, new_index));
			}
			restoreDefault();
		};

		var setIdRange = function (min, max) {
			var findPermissionAroundId = function (permissions, f_cmp, f_taker, f_else) {
				return f_taker(A(permissions).filter(f_cmp)) || f_else(permissions);
			};

			var min_index = (findPermissionAroundId(permissions, function (p) { return p.id >= min; }, last, first)).index,
				max_index = (findPermissionAroundId(permissions, function (p) { return p.id <= max; }, first, last)).index;
				
//			var min_index = (findPermissionById(permissions, min) || last(permissions)).index,
//				max_index = (findPermissionById(permissions, max) || permissions[0].max <= max ? permissions[0] : {index:0} ).index;
			setRange(min_index, max_index);
		}

		var addSlave = function (slave) {
			return (slaves.push(slave), this);
		};

		controls.flat = { 0: { stub: null }};

		blue = A(blue_group).map(function (option, index) {
			option.index = blue_group.length - index;
			return (controls.flat[option.index] = makeOption(option));
		});

		red = A(red_group).map(function (option, index) {
			option.index = -(index+1);
			return (controls.flat[option.index] = makeOption(option));
		});

		permissions = A([]).append(blue_group, red_group);

		current = A(permissions).filter(function (p) { return p.id == default_value})[0] || permissions[permissions.length-1];

		(controls.input = (input_id && $id(input_id)) || {value: ""}).value = current.id;

		controls.container = $insertBefore($style($id(container_id), {display: "none"}),
			addEventListener(
				$append($("div", "rights"),
					controls.blue_group = $append(
						$style($("div", "rights-group rg-yes rg-current"), {display: blue.length ? "" : "none"}), blue),
					controls.red_group =  $append(
						$style($("div", "rights-group rg-no"), {display: red.length ? "" : "none"}), red)),
				"mouseout", stopEvent(restoreDefault)));

		restoreDefault();

		return {
			setRange: setRange,
			setIdRange: setIdRange,
			addSlave: addSlave,
			onMasterChange: onMasterChange,
			currentIndex: function () { return current.index; },
			currentId: function () { return current.id; },
			input: controls.input,
			container: controls.container,
			setCurrentId: function (id) { onClick(findPermissionById(permissions, id)) }
		};
	};

	var popup_instances = [];

	var Popup = function (id, input_id, default_value, blue, red, master) {
		var picker;

		var onLinkClicked = stopEvent(function () {
			A(popup_instances).forEach(function (p) {
				p != picker && p.hide();
			});

			jQuery(controls.popup).is(":visible") ?
				onClose() :
				jQuery(controls.popup).css({top: this.offset().top + 16, left: this.offset().left}).slideDown(200);
		});

		var onClose = function () {
			jQuery(controls.popup).slideUp(200);
		};

		var onSelectOption = function (id) {
			var p = findPermissionById(permissions, id),
				updateLink = function () {
					onClose();
					controls.link.innerHTML = p.title;
				};

			!input_id ?
				_.ajax(updateLink).url('/contacts/ajax_set_contact_perm').method("POST").data({group_id: p.id }).run() : updateLink();
		};

		var controls = { link: $id(id) },
			permissions = A([]).append(blue, red),
			current = findPermissionById(permissions, default_value) || permissions[permissions.length - 1];

		addEventListener(
			$append(controls.link, $.text(
				(current || {title: "No value"}).title)),
			"click", context(jQuery(controls.link), onLinkClicked));

		$append($.body(),
			$append(controls.popup = $("div", "popup", {id: _.random.randomId()}),
				$append($("h4"), $.text(perm_title),
					addEventListener(controls.close = $("a", "", {href: "#"}), "click", stopEvent(onClose))),
				controls.anchor = $("a")));

		picker = Picker(controls.anchor, input_id, default_value, blue, red).addSlave({onMasterChange: onSelectOption});
		picker.hide = onClose;
		return popup_instances.push(picker), picker;
	};

	return { picker: Picker, popup: Popup };
});

(function () {
	var r = function () { return (Math.random()*10000000000 >>> 0).toString(32); };
	var randomId = function () {
		return ["_", r(), r(), r()].join("");
	};

	var instances = {};

	var writeMarker = function (input_name) {
		var id = randomId(), input_id = input_name && randomId();
		document.write([
			"<a id=\"", id, "\" href=\"#\"></a>",
			input_name && ("<input id=\"" + input_id + "\" type=\"hidden\" name=\"" + input_name + "\">")
		].join(""));
		return [id, input_id];
	};

	var makePicker = function (constructor, input_name, master, on_ready_cb) {
		return function () {
			instances[input_name] = constructor.apply(this, arguments);
			master && (
				instances[master].addSlave(instances[input_name]),
				instances[input_name].onMasterChange(instances[master].currentId()));
			on_ready_cb && on_ready_cb(instances[input_name]);
		};
	};

	var onDomReady = (function (hooks) {
		var onload_raised = false;
		
		nulljs.load("com.nulljs.(event|array)").run(function (api) {
			api.com.nulljs.event.addEventListener(window, "load", function () {
				onload_raised = true;
				api.com.nulljs.array(hooks).forEach(function (call) {
					call[0].apply(window, call[1]);
				});
			});
		});
		
		return function (f) {
			return onload_raised ? f : function () { hooks.push([f, arguments]) };
		};

	})([]);

	window.PermissionPicker = function (input_name, default_value, blue, red, master, on_ready_cb) {
		var ids = writeMarker(input_name);

		nulljs.load("modules.permissions.pickers").run(onDomReady(function (api) {
			makePicker(api.modules.permissions.pickers.picker, input_name, master, on_ready_cb)(ids[0], ids[1], default_value, blue, red);
		}));
	};

	window.PermissionPicker.dynamic = function (root_element, input_name, default_value, blue, red, master, on_ready_cb) {
		nulljs.load("modules.permissions.pickers", "com.nulljs.dom").run(onDomReady(function (api) {
			var $ = api.com.nulljs.dom(), a_element, input_element;
			$.append(root_element, a_element = $("a"), input_element = $("input", "", {name: input_name, type: "hidden"}));
			makePicker(api.modules.permissions.pickers.picker, input_name, master, on_ready_cb)(a_element, input_element, default_value, blue, red);
		}));
	};

	window.PermissionPopup = function (input_name, default_value, blue, red, master, on_ready_cb) {
		var ids = writeMarker(input_name);

		nulljs.load("modules.permissions.pickers").run(onDomReady(function (api) {
			makePicker(api.modules.permissions.pickers.popup, input_name, master, on_ready_cb)(ids[0], ids[1], default_value, blue, red);
		}));
	};

	window.PermissionPopup.dynamic = function (root_element, input_name, default_value, blue, red, master, on_ready_cb) {
		nulljs.load("modules.permissions.pickers", "com.nulljs.dom").run(onDomReady(function (api) {
			var $ = api.com.nulljs.dom(), a_element, input_element;
			$.append(root_element, a_element = $("a"), input_element = $("input", "", {name: input_name, type: "hidden"}));
			makePicker(api.modules.permissions.pickers.popup, input_name, master, on_ready_cb)(a_element, input_element, default_value, blue, red);
		}));
	};

})();
