var global_close = {
	register_callback: function(callback, ignored_tag) {
		return function(callback, ignored_tag) {
			$(document).bind('mousedown', callback);
			return function() {
				$(document).unbind('mousedown', callback);
			}
		}(callback, ignored_tag);
	}
};

var cloud_manager = {
	currently_opened: false,
	add_cloud_after: function(node, content, params) {
		var local_params = {
			css: {display: 'block'},
			close_on_click: true,
			close_on_outer_click: true,
			cloudClass: 'cloud'
		};
		if (typeof(params) != 'object') {
			params = {};
		}
		$.extend(true, local_params, params);
		
		// prevent from opening more than one cloud at once.
		if (cloud_manager.currently_opened !== false) {
			cloud_manager.currently_opened.data('close_function')();
			cloud_manager.currently_opened = false;
		}

		var top = $('<div class="top" />');
		var content_node = $('<div class="content" />');
		var bottom = $('<div class="bottom" />');
		var cloud = $('<div class="' + local_params.cloudClass +'" />');
		if (typeof(content) == 'string') {
			content_node.html(content);
		}
		else {
			content_node.append(content);
		}

		cloud.append(top).append(content_node).append(bottom);

		// prepare closing function
		cloud.data('close_function', function() {
			// detach close_on_outer_click event listener if set
			var close = cloud.data('close_on_outer_click');
			if (typeof(close) == 'function') {
				$(document).unbind('click', close);
			}
			cloud.fadeOut(500, function() {
				$(this).remove();
			});
		});

		// bind close function on click inside the cloud
		if (local_params.close_on_click) {
			cloud.bind('click', function(event) {
				cloud_manager.currently_opened = false;
				$(this).data('close_function')();
			});
		}

		// bind close function on click outside the cloud
		if (local_params.close_on_outer_click) {
			var close_on_outer_click = function(event) {
				var cloud_tag = cloud.get(0);
				var clicked_inside = false;
				$(event.target).parents().each(function(index, element) {
					if (element == cloud_tag) {
						clicked_inside = true;
						return false;
					}
				});
				if (clicked_inside) {
					return;
				}
				cloud_manager.currently_opened = false;
				cloud.data('close_function')();
			}
			cloud.data('close_on_outer_click', close_on_outer_click);
			$(document).bind('click', close_on_outer_click);
		}

		// set the element as opened, insert into html document and display.
		cloud_manager.currently_opened = cloud;
		node.after(cloud);
		cloud.css(local_params.css);

		return cloud;
	}
};


var hints_cloud = {
	init: function(data) {
		for (selector in data) {
			(function(selector, content) {
				var params = {
					desc: '',
					css: {},
					hintClass: 'hint_cloud'
				};
				$.extend(true, params, content);

				var cloud = false;
				$(selector).bind('mouseenter', function(e) {
					cloud = cloud_manager.add_cloud_after( $(this), params.desc, {close_on_click: false, close_on_outer_click: true, cloudClass: params.hintClass, css: params.css } );
				}).bind('mouseleave', function(e) {
//					var close_fn = cloud.data('close_function')
//					if (typeof(close_fn) == 'function') {
//						cloud_manager.currently_opened = false;
//						close_fn();
//					}
				});
			})(selector, data[selector]);
		}
	},
	/* TODO: this should be more specific, as it removes all handlers */
	remove_handlers: function(selector) {
		$(selector).unbind('mouseenter').unbind('mouseleave');
	}
};
