function GlossaryTermHighlighter() {

	var ok = ((document.createElement) ? true : false);
	var terms = new Array();
	var foundCount = 0;
	var DEBUG = false;
	var elements;
	var alreadyUsed = new Array();
	var highlightClass;
	
	if (!ok) return;

	/**
	 * the css elements that can contain glossary terms (use "body" for the entire page)
	 */
	this.setElement = function(id) {
	
		if (!ok) return;
		
		elements = new Array();
		elements[0] = document.getElementById(id);
		
	}
	
	/**
	 * add a term to be highlighted
	 * term - the text
	 * termId - the id of an element that provides the rollover copy
	 */
	this.addTerm = function(term, termId) {
		if (!ok) return;
		terms.push(new GlossaryTerm(term, termId));
	}

	/** 
	 * highlight the terms on the page
	 */
	this.highlight = function(highFunc) {
	
		if (!ok || elements.length == 0 || terms.length == 0) return;
		
		terms.sort(function(term1, term2){return(term2.term.length-term1.term.length)});
		var msg = "Available terms\n";
		for (var i = 0; i < terms.length; i++) {
			term = terms[i];
			for (var j=0; j < elements.length; j++) {
				this.highlightTerm(elements[j], term, true, highFunc);
			}
			msg += term.term + " was" + (term.found ? " " : " not ") + " found\n";
		}

		if (DEBUG) alert(msg);

	}
	
	/** 
	 * get a list of all matching terms
	 */
	this.matching = function() {

		if (!ok || elements.length == 0 || terms.length == 0) return;

		var ret = new Array();
		terms.sort(function(term1, term2){return(term2.term.length-term1.term.length)});
		
		for (var i = 0; i < terms.length; i++) {
			term = terms[i];
			if (this.isAlreadyUsed(term)) continue;
			for (var j=0; j < elements.length; j++) {
				this.highlightTerm(elements[j], term, false);
			}
			if (term.found) ret.push(term);
		}

		return ret;
	}

	/**
	 *
	 */
	this.isAlreadyUsed = function(term) {
		for (var i=0; i<alreadyUsed.length; i++) {
			if (term.term == alreadyUsed.toLowerCase()) return true; 
		}
		return false;
	}

	/**	
	 * highlight a term within a given node
	 */
	this.highlightTerm = function(node, term, highlight, highFunc) {
		// this little step is required to prevent IE from getting wrapped around the axle on 
		// certain types of malformed HTML.
		if (node.nodeType == 1) // element
		{
			if (node.getAttribute("sth_x") == term.term) return;
			else node.setAttribute("sth_x", term.term);
		}
		
		if (node.hasChildNodes())
		{
			for (var i = 0; i < node.childNodes.length; i++) 
			{
				this.highlightTerm(node.childNodes[i], term, highlight, highFunc);
			}
		}

		if (node.nodeType == 3)
		{
			var p = node.parentNode;
			if (p.nodeName != 'TEXTAREA' && p.nodeName != 'SCRIPT' && p.className.substr(0, this.highlightClass.length) != term.cssClass)
			{
				var result = term.pattern.exec(node.nodeValue);
				if (result != null)
				{
					term.cssClass = this.highlightClass;
					term.found = true;
					foundCount++;
					if (highlight) {
						highFunc(node, term, result, p);
					}
				}
			}
		}
	}

}

/**
 * create a glossary term object used for highlighting
 */
function GlossaryTerm(term, termId) {
	this.term = term.toLowerCase();
	this.termId = termId;
	this.pattern = new RegExp('\\b' + this.term + '\\b', 'i');
	this.found = false;
	this.toString = function(){return this.term};
}
