/*
	Glossary Of Terms (GOT)
	
	Dependencies:
		request.js
		domutilities.js
		clientutilities.js
		
	Public Properties:
		WIDTH: width of GOT div
		VOFFSET: vertical distance offset of GOT div from the mouseover location
		HOFFSET: horizontal distance offset of GOT div from the mouseover location
		AUTOLINK: boolean on whether or not to parse the content element, doing a 
				 search & replace on textnodes to create gotlinks 
		AUTOELEMENTIDS: an array of element id strings that will be searched and autolinked.
		ADDHREF2GLOSSARY: boolean; Add an href to the full glossary listing
		
	Manual Usage:
		Set class of <a> to 'gotlink' and set title attribute to term to show
		e.g. <a class="gotlink" title="hardwood">Hardwood</a>
		If ADDHREF2GLOSSARY is set to true and the anchor doesn't have an existing 
		href attribute, one is added to the glossary of terms full listing page.
		
	AutoLink Usage:
		When AUTOLINK is set to true, all text nodes within the 'content' elements
		named in the AUTOELEMENTIDS array are searched for matches in the synonym list,
		if a match is found and the textnode isn't a child of <a>, then it's wrapped in a <a>
		e.g. <a class='gotlink' title='[matchvalue]'>[matchvalue]</a>
	
	Modification: 11/27/2006
	- No longer using title attribute because of native browser behavior. Now using faux 'synonym' attribute.
*/
var GOT = {
	WIDTH: 300,
	VOFFSET: 50,
	HOFFSET: 20,
	AUTOLINK: true,
	AUTOELEMENTIDS: new Array('maincontent'),
	ADDHREF2GLOSSARY: true,
	DEBUG: false,
	BASEURL: '/',
	got_init: function(){
		if(navigator.userAgent.indexOf('Safari') > 0){return;}// Reject Safari due to poor regex and event handling
		
		if(GOT.AUTOLINK){
			//request Synonyms
			Http.get({
				//url: "../got/getAllSynonyms.aspx",
				url: GOT.BASEURL + "got/getAllSynonyms.aspx",
				callback: GOT.createGOTLinks,
				cache: Http.Cache.Get
				});
		}
		else{
			GOT.attachEventsToLinks();
		}
	},
	
	createGOTLinks: function(xmlreply){

		if (xmlreply.status != Http.Status.OK){
			if(GOT.DEBUG){alert('Ajax call to getAllSynonyms.aspx failed. xmlreply.status = ' + xmlreply.status);}
			return;
		}

		var xmlTerms = xmlreply.responseXML;
		// make sure we have the needed objects
		if(xmlTerms == null || GOT.AUTOELEMENTIDS.length == 0){return;}
		
		var synNodes = xmlTerms.documentElement.getElementsByTagName('synonym');
		for(var i = 0; i < GOT.AUTOELEMENTIDS.length; i++){
			var elToSearch = document.getElementById(GOT.AUTOELEMENTIDS[i])
			if(elToSearch != null){
				var dtStart = new Date();
				GOT.searchAndreplaceTextNodeWithLinks(elToSearch, synNodes);
				var dtEnd = new Date();
				if(GOT.DEBUG){
					alert('searchAndreplaceTextNodeWithLinks took \n ' +  ((dtEnd - dtStart)/1000) + ' seconds for ' + synNodes.length + ' synonyms');
				}
			}
			else{
				if(GOT.DEBUG){
					alert('GOT.AUTOELEMENTID of ' + GOT.AUTOELEMENTIDS[i] + ' does not exist.');
				}
			}
		}

		GOT.attachEventsToLinks();

	},
	
	searchAndreplaceTextNodeWithLinks: function(node, synonyms){
		if (node.nodeType == 3) { // text node
		//if (node.nodeType == 3) { // text node
			
			var strNewText = new String(node.data);
			var parent = node.parentNode;
			var bfoundmatches = false;
			
			// make sure the parent isn't a link or a script tag and there is a 1+ word(s) in the node
			if(parent.nodeName.toLowerCase() != 'a' && parent.nodeName.toLowerCase() != 'script' && (new RegExp('\\w+', 'gi').test(strNewText))){
			//if(parent.nodeName.toLowerCase() != 'a' && parent.nodeName.toLowerCase() != 'script'){
				for(var i=0; i < synonyms.length; i++){
					var regexstring = '\\b(' + synonyms[i].firstChild.nodeValue + ')\\b' ;
					var rex = new RegExp(regexstring, 'gi');
					// look for a match
					if(rex.test(strNewText)){
						bfoundmatches = true;
						//strNewText = strNewText.replace(rex, "<a class='gotlink' title='$&'>$&</a>");
						strNewText = strNewText.replace(rex, "<a class='gotlink' synonym='$&'>\$&</a>");
					}
				}
				if(bfoundmatches){
					// replace old text node with new node
					var newNode = document.createElement('span');
					newNode.innerHTML = strNewText;
					parent.replaceChild(newNode, node);
				}
			}
		}
		else {
			// Not a Text node, loop through its children
			// and recursively call this function on each child.
			var kids = node.childNodes;
			for(var i = 0; i < kids.length; i++){
				GOT.searchAndreplaceTextNodeWithLinks(kids[i], synonyms);
			}
		}
	},

	attachEventsToLinks: function(){
		// get links with gotlink class and attache mouse events
		var lnks = document.getElementsByTagName('a');
		for(var i=0; i < lnks.length; i++){
			if(lnks[i].className.indexOf('gotlink') != -1){
				var lnk = lnks[i];
				// make sure they have a title attribute
				//if(lnk.getAttribute('title') && lnk.getAttribute('title') != ''){
				if(lnk.getAttribute('synonym') && lnk.getAttribute('synonym') != ''){
					addEvent(lnk, 'mouseover', GOT.getGot);
					addEvent(lnk, 'mouseout', GOT.killGot);
					
					// add href to full glossary if a href hasn't been defined
					if((GOT.ADDHREF2GLOSSARY) && (lnk.getAttribute('href')== null || lnk.getAttribute('href') == '')){
						//lnk.setAttribute('href', '../how_to/glossary.aspx#' + escape(lnk.getAttribute('title').toLowerCase()));
						lnk.setAttribute('href', GOT.BASEURL + 'how_to/glossary.aspx#' + escape(lnk.getAttribute('synonym').toLowerCase()));
					}
				}
			}
		}
	},
	
	killGot: function(){
		var elGot = document.getElementById('got');
		if(elGot == null || typeof elGot == 'undefined'){return;}
		var parent = elGot.parentNode
		if(typeof parent!="undefined"){parent.removeChild(elGot);}
		else {elGot.style.display='none';}
	},
	
	getGot: function(e){
		var target = window.event ? window.event.srcElement : e ? e.target : null;
		var evt = e || window.event;
		
		// accomodate for image inside of <a>
		while(target.className.indexOf('gotlink') == -1){
			target = target.parentNode;
		}
		// get the synonym
		//var synonym = target.getAttribute('title');
		var synonym = target.getAttribute('synonym');
		
		// store the mouse coordinates of this mouseover
		target.setAttribute('mousex', e.clientX);
		target.setAttribute('mousey', e.clientY);

		// XMLHTTPRequest for this link
		//TODO: I may need to kill/cancel any existing requests at this time
		if ((Http!=null)){Http.Init();}
		
		Http.get({
			//url: "../got/getTermDetails.aspx?synonym=" +  escape(synonym.toLowerCase()),
			url: GOT.BASEURL + "got/getTermDetails.aspx?synonym=" +  escape(synonym.toLowerCase()),
			callback: GOT.fillGot,
			cache: Http.Cache.Get
		}, [target]);
	},
	
	fillGot: function(xmlreply, elLink){
		GOT.killGot();
	
		if (xmlreply.status == Http.Status.OK){

			var elDiv = document.createElement('div');
			elDiv.setAttribute('id', 'got');
			// set the width
			elDiv.style.width = GOT.WIDTH + 'px';
			
			// set the position
			//GOT.setPosition(parseInt(elLink.getAttribute('mousex')), parseInt(elLink.getAttribute('mousey')), elDiv);
			elDiv.style.top = GOT.calculateTopPosition(elLink)  + 'px';
			elDiv.style.left = GOT.calculateLeftPosition(elLink) + 'px';
			
			// insert the response for the synonym into the div
			elDiv.innerHTML = xmlreply.responseText;
			//add to <body>
			//elLink.appendChild(elDiv);
			document.body.appendChild(elDiv);
			
			// add suicide mouseout
			addEvent(elDiv, 'mouseout', GOT.killGot);
			//alert(elDiv.offsetHeight);
			
		}
		else{
			if(GOT.DEBUG){
				alert('Ajax call to getTermDetails.aspx failed. xmlreply.status = ' + xmlreply.status);
			}
		}
		/*
		elLink.onclick = function(){
			var msg = '';
			//msg += 'elLinkID=' + elLink.id;
			msg+= '\n elLink X=' + findPosX(elLink) + ', elLink Y=' + findPosY(elLink) ;
			msg+= '\n getWindowDimensions().height=' + getWindowDimensions().height + ', getWindowDimensions().width=' + getWindowDimensions().width;
			msg+= '\n getWindowHeight()=' + getWindowHeight();
			msg+= '\n elLink.getAttribute(mousex)=' + elLink.getAttribute('mousex') + ', elLink.getAttribute(mousey)=' + elLink.getAttribute('mousey');
			msg+= '\n elDiv.style.top=' + elDiv.style.top + ', elDiv.style.left=' + elDiv.style.left;
			alert(msg);
			};
		*/
	},
	
	calculateLeftPosition: function(elLink){
		var leftPos = 0;
		//var linkStartX = findPosX(elLink); // do I need this var?
		//var scrollLeftAmount = getDocumentScrollAmount().left;
		var mouseX = parseInt(elLink.getAttribute('mousex'));
		var canvasWidth = getWindowDimensions().width;
		// Left or right?
		
		if((mouseX + GOT.WIDTH + GOT.HOFFSET) > canvasWidth){
			// not enough room to the right of the mouse
			// add extra offset to left
			leftPos = mouseX - GOT.WIDTH - (GOT.HOFFSET * 2); 
		}
		else{
			// default, place to the right of mouse
			// there's enough room on the right
			leftPos = mouseX + GOT.HOFFSET; // move 20px to the right or the mouse position
		}
		return leftPos;
	},
	
	calculateTopPosition: function(elLink){
		var topPos = 0;
		var canvasHeight = getWindowDimensions().height;
		var scrollTopAmount = getDocumentScrollAmount().top;
		//var linkStartY = findPosY(elLink); // do I need to use this var?
		var mouseY = parseInt(elLink.getAttribute('mousey'));
		
		if((mouseY - GOT.VOFFSET) < 1){
			// mouse is too close to the top, position at top of viewport
			topPos = scrollTopAmount;
		}
		else if((canvasHeight - mouseY) < GOT.VOFFSET ){
			// mouse is too close to the bottom, add extra offset
			topPos = mouseY - GOT.VOFFSET * 2 + scrollTopAmount;
		}
		else{
			// default
			topPos = mouseY - GOT.VOFFSET + scrollTopAmount;
		}
		return topPos;
	}
}
addEvent(window, 'load', GOT.got_init);


//setTimeout('GOT.got_init();', 5000);

//addEvent(window, 'load', setTimeout('GOT.got_init();', 5000));

//GOT.got_init();
// optional property override usage

//GOT.WIDTH = 300;
//GOT.VOFFSET =  50;
//GOT.HOFFSET = 20;
//GOT.AUTOLINK = true;
//GOT.AUTOELEMENTIDS = new Array('maincontent','contentleft');
//GOT.ADDHREF2GLOSSARY = true;
