(function($) {

	/**
	 * hoverIntent r6 // 2011.02.26 // jQuery 1.5.1+
	 * <http://cherne.net/brian/resources/jquery.hoverIntent.html>
	 *
	 * @param  f  onMouseOver function || An object with configuration options
	 * @param  g  onMouseOut function  || Nothing (use configuration options object)
	 * @author    Brian Cherne brian(at)cherne(dot)net
	 */
	$.fn.hoverIntent=function(f,g){var cfg={sensitivity:7,interval:100,timeout:0};cfg=$.extend(cfg,g?{over:f,out:g}:f);var cX,cY,pX,pY;var track=function(ev){cX=ev.pageX;cY=ev.pageY};var compare=function(ev,ob){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);if((Math.abs(pX-cX)+Math.abs(pY-cY))<cfg.sensitivity){$(ob).unbind("mousemove",track);ob.hoverIntent_s=1;return cfg.over.apply(ob,[ev])}else{pX=cX;pY=cY;ob.hoverIntent_t=setTimeout(function(){compare(ev,ob)},cfg.interval)}};var delay=function(ev,ob){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);ob.hoverIntent_s=0;return cfg.out.apply(ob,[ev])};var handleHover=function(e){var ev=jQuery.extend({},e);var ob=this;if(ob.hoverIntent_t){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t)}if(e.type=="mouseenter"){pX=ev.pageX;pY=ev.pageY;$(ob).bind("mousemove",track);if(ob.hoverIntent_s!=1){ob.hoverIntent_t=setTimeout(function(){compare(ev,ob)},cfg.interval)}}else{$(ob).unbind("mousemove",track);if(ob.hoverIntent_s==1){ob.hoverIntent_t=setTimeout(function(){delay(ev,ob)},cfg.timeout)}}};return this.bind('mouseenter',handleHover).bind('mouseleave',handleHover)}

	/**
	 * Highlighter plugin. Wraps terms in special containers. For each of these containers displays a pop-up with term
	 * definition when hovered.
	 *
	 * @author David Čepelík <david@cepelik.eu>
	 */
	$.fn.highlighter = function() {
		var popUp;
		var loadedPopUps = [];


		var matchedElements = this;
		$.getJSON('/lexicon/ajaxList', null, function(terms) {
			// escape each term so it can be used in a regular expression
			var escaped = $.map(terms, function(term, id) {
				return term.replace(/[.*+?]/, '\\$&');
			});

			// replace all terms in the text nodes of each matched element (global, case-insensitive)
			//var sep = "[\\(\\) \\.,\\?!\\n;\\t$^]";
			var sep = "(\\b|$)";
			var regExp = new RegExp('(' + sep + escaped.join(sep + '|' + sep) + sep + ')', 'gi');
			matchedElements.each(function() {
				replaceRecursive(this, regExp);
			});

			$('strong.h').hoverIntent(displayPopUp, function() {
				popUp.fadeOut();
				$('body').remove(popUp);
			});
		});

		var replaceRecursive = function(node, regExp) {
			for(var i = 0; i < node.childNodes.length; i++) {
				if(node.childNodes[i].nodeType == 1 && node.childNodes[i].localName != "a") {
					replaceRecursive(node.childNodes[i], regExp);
				}
				
				if(node.childNodes[i].nodeType == 3) {
					var text = node.childNodes[i].wholeText;
					var position;
					while((position = text.search(regExp)) >= 0) { 
						var pre = text.slice(0, position) ;
						text = text.slice(position);
						var match = text.match(regExp)[0];
						text = text.slice(match.length);
						var newNode = document.createTextNode(pre);
						node.insertBefore(newNode, node.childNodes[i++]);
						newNode = document.createElement('strong');
						node.insertBefore(newNode, node.childNodes[i++]);
						$(newNode).addClass('h').html(match);
						newNode = document.createTextNode(text);
						node.replaceChild(newNode, node.childNodes[i]);
					}
				}
			}
		};

		var displayPopUp = function(e) {
			var term = $(this).text();

			// lazy pop-up load
			if (loadedPopUps[term] == null) {
				$.ajax({
				url: '/lexicon/ajaxGetPopUp/?' + encodeURIComponent(term),
				async: false,
				type: 'post',
				dataType: 'html',
				success: function(popUpHtml) {
					loadedPopUps[term] = $(popUpHtml).hide();
				}});
			}

			popUp = loadedPopUps[term];

			$('body').append(popUp);
			popUp.css({position: 'absolute', top: e.pageY + 'px', left: e.pageX + 'px'}).fadeIn();
		};
		
		return this;
	};

}) (jQuery);
