
var Terms = function(terms) {
	this.terms = {};
	this.options={
		excludeTags: ['a', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'option', 'input', 'textarea', 'script', 'style'],
		wrapperTag: 'span'
	};
	
	this.tags = [];
	this.getTextNodes();
	
	if ( typeof terms != 'undefined' ) {
		if ( typeof terms == 'string' ) {
			var terms = eval("("+terms+")");
		}
		if ( terms.constructor === Object ) {
			this.addTerms(terms);
		} else {
			// this shouldn't run?
			this.addTerm(terms);
		}
		
		this.check();
	}
};

Terms.prototype = {
	getTextNodes: function getTextNodes(node) {
		if ( typeof node == 'undefined' ) {
			var node = document.body;
		}
		if ( node.id == 'driller' || this.options.excludeTags.inArray(node.tagName.toLowerCase()) ) {
			node = node.nextSibling;
		}
		var childNodes = node.childNodes, cnLength = childNodes.length;
		var len = -1;
		
		while ( ++len < cnLength ) {
			var current = childNodes[len];
			if ( current.nodeType === 1 && !this.options.excludeTags.inArray(current.tagName.toLowerCase()) && !(current.tagName == 'SPAN' && current.className == 'term')) {
				this.getTextNodes(current);
			}
			if ( current.nodeType !== 3 || (current.nodeType === 3 && current.nodeValue.replace(/\s/g, '') == '')) {
				continue;
			}
			this.tags.push(current);
		}
		
		return this.tags;
	},
	addTerm: function addTerm(id, term) {
		this.terms[id] = term;
	},
	addTerms: function addTerms(terms) {
		if ( terms.constructor !== Object ) {
			return false;
		}
		for ( var id in terms ) {
			if ( !terms.hasOwnProperty(terms) ) {
				this.terms[id] = terms[id];
			}
		}
	},
	check: function check() {

		for ( var i = 0; i < this.tags.length; i++ ) {
			var elm = this.tags[i];
			var data = (elm.innerHTML || elm.nodeValue);
			
			var reg = [];
			for ( var id in this.terms ) {
				if ( !this.terms.hasOwnProperty(id) || typeof this.terms[id] == 'undefined' ) {
					continue;
				}
				var term = this.terms[id].term;
				var plural = this.terms[id].plural;
				
				if ( plural == '' ) {
					//var reg = new RegExp("(\\b"+term+"\\b)", "gi");
					reg.push(term);
				} else {
					reg.push(plural);
					reg.push(term);
					//var reg = new RegExp("(\\b("+term+"|"+plural+")\\b)", "gi");
				}
			}
			var regex = new RegExp("\\b"+reg.join('|')+"\\b", 'gi');
			if ( data.match(regex) ) {
				this.createTerm(regex, elm, data);
			}
		}
	},
	createTerm: function createTerm(reg, elm, data) {
		var parent = elm.parentNode; // tag wrapping the text node
		
		var splits = data.split(reg);
		var matches = data.match(reg);
		
		// IE! If the term is at the end of the string, the split string will only have one part.
		// If term is at the beginning of a one term string, it would create an empty textnode, but since
		// matches[1] doesn't exist nothing really happens.
		if ( splits.length == 1 ) {
			splits[1] = '';
		}
		
		// Handle the case that the data contains ONLY the term, nothing else, not even whitespace.
		// IE will make splits empty, we need to make it look like other browsers in that there
		// will be two empty strings when splitting on the term.
		if ( splits.length == 0 ) {
			splits[0] = '';
			splits[1] = '';
		}
		
		var empty_first = data.search(reg) == 0 ? false : true; // IE fixxxxx
		for ( i = 0; i < splits.length; i++ ) {
			var o = i;
			// if splits[i] is blank, skip this unless it's the last element.
			// we want to make sure to handle the case that terms are at the very end of the textnode.
			if ( typeof splits[i] != 'undefined' && (splits[i] != '' || i == splits.length - 1) ) {
				/*
				var node = document.createElement('span');
				var text = document.createTextNode(splits[i]);
				node.appendChild(text);
				*/
				var node = document.createTextNode(splits[i]);
				parent.insertBefore(node, elm);
			} else {
				empty_first = true;
			}
			if ( empty_first ) {
				o = i-1;
			}
			if ( matches[o] ) {
				// matches[o]: the term, parent: tag wrapping text, node: textnode from split text
				this.createMatch(matches[o], parent, node);
			}
		}
		// remove the pre-existing textnode since we've basically rebuilt it.
		parent.removeChild(elm);
	},
	createMatch: function createMatch(match, parent, node) {
		var id = null;
		for ( x in this.terms ) {
			if ( !this.terms.hasOwnProperty(x) || typeof this.terms[x] == 'undefined' ) {
				continue;
			}
			if ( this.terms[x].term.toLowerCase() == match.toLowerCase() || this.terms[x].plural.toLowerCase() == match.toLowerCase() ) {
				id = x
				break;
			}
		}
		var span = document.createElement('span');
		addClass(span, 'term');
		span.onmouseover = function(e) {
			loadTerm(e, 'glossary/term/'+id);
		}
		/*
		registerEvent(span, 'mouseover', function(e) {
			loadTerm(e, 'glossary/term/'+id);
		});
		*/
		registerEvent(span, 'mouseout', function(e) {
			loaded_term = null;
			hideID('term_popin');
		});
		span.innerHTML = match;
		parent.insertBefore(span, node);
	}
};
