﻿
String.prototype.reverse = function () {
	return this.split('').reverse().join('');
};

var Highlighter = 
{
	highlightTag:"span",
	highlightClass:"highlighted",
	pattern:"(<[^>]*?)(<0>)([^>]*?>)",
	
	get_text:function () { return document.body.innerHTML; },
	set_text:function (value) { document.body.innerHTML=value; },
	
	get_replacementText:function(value) 
	{ 
		var pattern ='<<0> class="<1>"><2></<0>>'.replace(/<0>/g,this.highlightTag).replace(/<1>/g, this.highlightClass).replace(/<2>/g, value);
		return pattern; 
	},
	
	highlightText:function(value)
	{
		/* Description:
		 * Regular expression look-behind values are non existant in JS so this function uses an unusual technique to 
		 * compensate. First, everything is reversed. Then with the reversed string we find each instance of the highlighted 
		 * text and replace it with a temporary token that is wrapped in a span tag. This is done for two reasons: 1) Global 
		 * search and replaces dont seem to work with this algorithm; 2) We must replace with a different value from the 
		 * highlight term to prevent from entering into an infinite loop. One all the search-and-replaces are done and the 
		 * tokens are in place, we do a simple search-and-replace on the token to insert the original highlight value back in.
		 */
		 
		if(value==null || value=='') return;
		
		var pattern = this.pattern.replace(/<0>/g, value.reverse());
		var searchText = this.get_text().reverse();
		var replacementText = this.get_replacementText('@@@@').reverse();
		
		var tokenText = this.replaceText(searchText, pattern, replacementText).reverse();
		var newText = tokenText.replace(/@@@@/g, value);
		this.set_text(newText);
		
	},
	replaceText:function(data, pattern, replacement)
	{
		var re = new RegExp(pattern);
		re.ignoreCase=true;
		re.global=true;
		
		var previousValue='';
		
		while(previousValue!=data)
		{
			previousValue=data;
			data=data.replace(re, function($0, $1, $2, $3) { return $1 + replacement + $3; });
		}
		return data;
	}
	
}
