/// <reference path="../../../../References/jquery-1.2.6-vsdoc.js" />

(function($)
{

	// get the XML path from src attibute of this file's scipt element ( ie <script src="thisfile.js?[xmlPath] ) 
	// needs to be executed straight away for it to work
	var xmlPath = function()
	{
		try
		{
			// get this xml path from querystring in this script's src (everything after "?xml=")
			var xmlPath = getLastChild(document.lastChild).getAttribute('src').replace(/.*\.js\?xml=/, '');
			// unescape path (Url Decode it)
			xmlPath = unescape(xmlPath);
			// covert any &amp; back to &
			xmlPath = xmlPath.replace(/&amp;/g, '&');
			// if path is less than 4 characters long then assume it isn't correct
			if (xmlPath.length < 4) throw { message: "Couldn't find path to XML file" };
			return xmlPath;
		}
		catch (e)
		{
			// if there are any errors then fall back to the hard coded path below
			return "/_assets/xml/jargonterms.xml";
		}
		function getLastChild(el) { return (el.lastChild && el.lastChild.nodeName != '#text') ? getLastChild(el.lastChild) : el; }
	} ();

	// escapes any special characters used in RegExp found in strings
	RegExp.escape = function(str)
	{
		var specials = new RegExp("[.*+?|()\\[\\]{}\\\\]", "g");
		return str.replace(specials, "\\$&");
	}


	// the rest of this script is to be triggered when dom is ready...

	// we only want to highlight jargons that appear anywhere in this div
	$("#iContentHolder").ready
	(
		function()
		{
			// load in XML
			$.get(xmlPath, {}, dataRecieved);
			function dataRecieved(data)
			{
				// check data - if data is string the parse string to xml dom
				if (typeof (data) == "string") data = parseXML(data);

				HighlightJargon(data);

				function parseXML(data)
				{
					var dom;
					if (window.ActiveXObject && window.GetObject)
					{
						dom = new ActiveXObject('Microsoft.XMLDOM');
						dom.loadXML(data);
						return dom;
					}
					if (window.DOMParser)
					{
						dom = new window.DOMParser();
						dom = dom.parseFromString(data, "text/xml");
						return dom;
					}
					return "error";
				}
			}
		}
	);

	function HighlightJargon(xml)
	{
		// loop through all terms in xml and test to see if they exist in the div - if they do then add to array to shorten list of terms
		var tStart = new Date().getTime();
		var divContent = $("#iContentHolder").html();
		var terms = new Array(), term, re = new RegExp();
		$(xml).find("term").each
		(
			function()
			{
				term = $(this).text();
				desc = $(this).siblings("desc").text();
				vars = $(this).siblings("vars").text(); // optional: possible term variations separated by commas
				vars = (vars) ? vars.split(",") : new Array();
				vars.push(term);
				// now let's loop throught the vars and check if they exits.
				var searchTerm;
				for (var i = 0; i < vars.length; i++)
				{
					searchTerm = $.trim(vars[i]);
					if (searchTerm == '') continue;
					re = new RegExp("\\b(" + RegExp.escape(searchTerm) + ")(\\b|\\W)", "ig"); // case-insensitive
					if (re.test(divContent))
					{
						terms.push({ searchTerm: searchTerm, term: term, desc: desc, re: re });
					}
				}
			}
		);
		// Sort array so that the longest term is first - the outermost term will win
		terms.sort(function(a, b) { return b.searchTerm.length - a.searchTerm.length; });

		// now loop through all text nodes and for each node loop through the terms and replace
		$("#iContentHolder *").contents().filter("[nodeType=3]").each
		(
			function()
			{
				if (!(/[^\t\n\r ]/.test(this.data))) return; // if empty text node then ignore
				if ($(this).parents("a, table").length > 0) return; // ignore text nodes who are children of the selected parents (comma separate these)
				// loop through all previous found terms and do replacement.
				var d = this.data;
				for (var i = 0; i < terms.length; i++)
				{
					d = d.replace(terms[i].re, '<span class="jargonterm term' + i + '">$1</span>');
				}
				// check for any replacements
				if (this.data.length == d.length) return; // no replacements for this node so move on
				// update dom...
				$(this).replaceWith(d);
			}
		);

		// there may be nested span terms elements so now check and get rid
		$("span.jargonterm span.jargonterm").each(function() { $(this).replaceWith($(this).text()); });

		var descTimer;

		// lastly apply events & functionality...
		$("span.jargonterm")
			.hover
			(
				function() { $(this).css({ "cursor": "help" }); }
				,
				function()
				{
					$(this).css({ "cursor": "default" });
					$(this).one('click', showDesc);
					descTimer = setTimeout(function() { $(".jargonDesc").fadeOut(250); }, 500);
				}
			)
			.one('click', showDesc);

		function showDesc(e)
		{
			$(this).css({ "cursor": "default" });
			// remove any previous descriptions and clear any timers
			$(".jargonDesc").remove();
			if (descTimer) { clearTimeout(descTimer); descTimer = null; }
			// create description
			var itemId = parseInt($(this).attr("class").replace(/\D*(\d*)$/g, '$1'));
			if (isNaN(itemId)) return;
			$("#iContentHolder").append('<div class="jargonDesc"><div><h3>' + terms[itemId].term + '</h3>' + terms[itemId].desc + '</div></div>');
			// position description (making sure it stays within #iContentHolder)
			var desc = $("div.jargonDesc");
			var descT = $(this).offset().top - $("#iContentHolder").offset().top - desc.height() + $(this).height() - parseInt($(this).css("font-size")) * 2.5;
			var descL = $(this).offset().left - $("#iContentHolder").offset().left;
			var descR = descL + desc.width();
			var contW = $("#iContentHolder").width();
			descL = (descR < contW) ? descL : contW - desc.width();
			descT = (descT > 0) ? descT : $(this).offset().top - $("#iContentHolder").offset().top + $(this).height();
			desc.css({ "top": descT, "left": descL });
			// add events to the description
			desc.hover
			(
				function() { if (descTimer) { clearTimeout(descTimer); descTimer = null; } }
				,
				function() { $(this).fadeOut(250); }
			);
			// fade in description
			desc.fadeIn(500);
		}

	} // end - HighlightJargon()

})(jQuery);