
var getSearchKeywords = function(options) {
	var ref = options.debug_referrer || document.referrer;

	if(!ref && options.keys==undefined) 
		return this;

	var q = options.keys != undefined?options.keys.toLowerCase().split(/[\s,\+\.]+/):ParseReferrer.decodeURL(ref,ParseReferrer.engines);

	if (q == null)
		return this;
	
	var phrase = q.toString().replace(/,/g," ");

	if(q)
	{
		for(i = 0; i < q.length; i++)
		{
			if(q[i].length == 1)
				q[i] = "";
			else
			{/*
				switch(q[i]) 
				{
				case "of":
					q[i] = "";
					break;
				case "in":
					q[i] = "";
					break;
				case "and":
					q[i] = "";
					break;
				case "for":
					q[i] = "";
					break;
				case "sale":
					q[i] = "";
					break;
				case "albuquerque":
					if(phrase.search("north albuquerque acres")==-1 && 
							phrase.search("albuquerque acres west")==-1)
						q[i] = "";
					break;
				case "nm":
					q[i] = "";
					break;
				case "nw":
					q[i] = "";
					break;
				case "ne":
					q[i] = "";
					break;
				case "se":
					q[i] = "";
					break;
				case "sw":
					q[i] = "";
					break;
				case "rd":
					q[i] = "";
					break;
				case "dr":
					q[i] = "";
					break;
				case "ave":
					q[i] = "";
					break;
				case "home":
					q[i] = "";
					break;
				case "homes":
					q[i] = "";
					break;
				case "real":
					q[i] = "";
					break;
				case "estate":
					q[i] = "";
					break;
				}
				*/
			}
		}
	}
	
	if(q && q.join("")) 
		return q.toString().replace(/,/g," ");
	
	return "";
}

var ParseReferrer = 
{
options: {},
regex: [],
engines: 
	[
	 [/^http:\/\/(www\.)?google\./i, /[?&]q=([^&]+)/i],                            // Google
	 [/^http:\/\/(www\.)?bing\./i, /q=([^&]+)/i],                              // bing
	 [/^http:\/\/(www\.)?search\.yahoo\./i, /p=([^&]+)/i],                     // Yahoo
	 [/^http:\/\/(www\.)?search\.msn\./i, /q=([^&]+)/i],                       // MSN
	 [/^http:\/\/(www\.)?search\.live\./i, /query=([^&]+)/i],                  // MSN Live
	 [/^http:\/\/(www\.)?search\.aol\./i, /q=([^&]+)/i],               		   // AOL
	 [/^http:\/\/(www\.)?ask\.com/i, /q=([^&]+)/i],                            // Ask.com
	 [/^http:\/\/(www\.)?altavista\./i, /q=([^&]+)/i],                         // AltaVista
	 [/^http:\/\/(www\.)?feedster\./i, /q=([^&]+)/i],                          // Feedster
	 [/^http:\/\/(www\.)?search\.lycos\./i, /q=([^&]+)/i],                     // Lycos
	 [/^http:\/\/(www\.)?alltheweb\./i, /q=([^&]+)/i],                         // AllTheWeb
	 [/end/i, /end/i],           											   // last array element
	 ],
	 subs: {},

	 decodeURL: function(URL,reg) 
	 {
		 URL = decodeURIComponent(URL);
		 var query = null;

		 $.each(reg,
				 	function(i,n)
				 	{
	 					if(n[0].test("end")) 
	 						return false;
			 			
	 					if(n[0].test(URL)) 
						{
							 var match = URL.match(n[1]);

							 if(match) 
							 {
								 query = match[1].toLowerCase();
								 return false;
							 }
						}
				 	}
		 		)

		 if (query) 
		 {
			 query = query.replace(/(\'|")/, '\$1');
					 query = query.split(/[\s,\+\.]+/);
		 }
		 return query;
	 }
}

mdwParseKeywords = function(keywordStr) {
	var onewordRe = /(?:^|\s+)(?:"([^"]+)"|(\S+))/g, 
		stopwordsRe = /(?:^(?:I|a|an|are|as|at|be|by|for|from|in|is|it|of|on|or|that|the|this|to|was|will|with|\*)$)|(?:^-)/,
	    stripPunctuationRe = /(?:^["'`+-]+)|(?:["'`,.?!]+$)/g;
	var match, keywords = [];
	while (match = onewordRe.exec(keywordStr))
	{
		var word = match[1] ? match[1] : match[2];
		if (!stopwordsRe.test(word))
		{
			keywords.push(word.replace(stripPunctuationRe, ""));
		}
	}
	return keywords;
},
mdwGatherTextnodes = function(startNode) {
	var nodeStack = [ startNode ];
	var textNodes = [];
	while (nodeStack.length > 0)
	{
		var n = nodeStack.shift();
		if (n.nodeType == 1 && n.childNodes && n.tagName != "SCRIPT" && n.tagName != "STYLE" && n.id != "search-box")
		{
			for (var i = n.childNodes.length - 1; i >= 0; i--)
			{
				nodeStack.unshift(n.childNodes[i]);
			}
		}
		else if (n.nodeType == 3) 
		{
			if (jQuery.trim(n.data).length > 0)
			{
				textNodes.push(n);
			}
		}
	}
	return textNodes;
},
mdwNormalizeTextnodes = function(startNode) {
	if (!startNode || !startNode.hasChildNodes()) { return false; }
	var elementStack = [ startNode ],
	    toCollapse = [],
	    collapseNodes = function(toCollapse) {
			var combinedText = "", p = toCollapse[0].parentNode;
			jQuery.each(toCollapse, function() { combinedText += this.nodeValue });
			var newNode = document.createTextNode(combinedText);
			p.insertBefore(newNode, toCollapse[0]);
			jQuery.each(toCollapse, function() { p.removeChild(this) });
			return [];
		};
	while (elementStack.length > 0)
	{
		var e = elementStack.shift();
		var n = e.childNodes[0];
		while (n)
		{
			if (n.nodeType == 1 && n.childNodes && n.tagName != "SCRIPT" && n.tagName != "STYLE")
			{
				if (toCollapse.length > 0)
				{
					toCollapse = collapseNodes(toCollapse);
				}
				elementStack.push(n);
			}
			else if (n.nodeType == 3)  
			{
				toCollapse.push(n);
			}
			n = n.nextSibling;
		}
		if (toCollapse.length > 0)
		{
			toCollapse = collapseNodes(toCollapse);
		}
	}
},
mdwBuildRegexp = function (words) {
	return (words.length > 0) ? 
		new RegExp("\\b(" +
			jQuery.map(words, function(w) {
				return w.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") 
			}).join("|") + ")\\b", "g"
		) : null;
},
addSearchHighlight = function(keywords, targets) {
	var keywordsUp = jQuery.map(keywords, function (k,i) { return k.toUpperCase(); });
	var keywordsRe = mdwBuildRegexp(keywordsUp);
	jQuery.each(targets, function() {
		var textnodes = mdwGatherTextnodes(this);
		jQuery.each(textnodes, function (idx, node) {
			var searchText = node.data.toUpperCase(),
				workNode = node,
				offset = 0,
				m;
			while (m = keywordsRe.exec(searchText))
			{
				var realIdx = m.index - offset;
				offset = m.index + m[1].length;
				var keywordNum = jQuery.inArray(m[1], keywordsUp) + 1;
				var matched = workNode.splitText(realIdx); 
				var postMatched = matched.splitText(m[1].length);
				var wrapSpan = document.createElement('span');
				wrapSpan.className = "word-color" + keywordNum;
				wrapSpan.appendChild(matched.cloneNode(true));
				//alert(wrapSpan.outerHTML);
				matched.parentNode.replaceChild(wrapSpan, matched);
				workNode = postMatched;
			} 
		}); 
	});
	$("#search-highlight-bar").addClass('search-highlight-applied');
},
removeSearchHighlight = function(targets) {
	$(targets).find("span").each(function() {
		if ($(this).parent().is("span.search-words")) { return true; }
		var spanNode = $(this).get(0);
		//alert(spanNode.outerHTML);
		if(spanNode.className.indexOf("word-color") == 0)
			spanNode.parentNode.replaceChild(spanNode.firstChild, spanNode);
	});
	jQuery.each(targets, function () {
		mdwNormalizeTextnodes(this);
	});
	$("#search-highlight-bar").removeClass('search-highlight-applied');
},

updateSearchBox = function() {
	var $bar = $("#search-highlight-bar"), 
		hi = $bar.data("searchHighlight");
	if ($bar.hasClass('search-highlight-applied'))
	{
		var keywordsSpan = $("<span/>").addClass("search-words");
		jQuery.each(hi.keywords, function (idx, keyword) { 
			$("<span/>")
				.addClass("word-color" + (idx+1))
				.text(keyword)
				.appendTo(keywordsSpan)
				.after(" ")  
			;
		});
		$bar.empty()
			.append("").append(keywordsSpan)
			.append('<br><a href="#">remove highlighting</a><br><br>')
			.find("a").click(function () {
				var hi = $("#search-highlight-bar").data("searchHighlight");
				removeSearchHighlight(hi.targets);
				updateSearchBox();
				return false;
			});
	}
	else
	{
		var keywordsSpan = $("<span/>").addClass("search-words").text(hi.keywordStr);
		$bar.empty()
			.append("").append(keywordsSpan)
			.append('<br><a href="#">highlight these words</a><br><br>')
			.find("a").click(function () {
				var hi = $("#search-highlight-bar").data("searchHighlight");
				addSearchHighlight(hi.keywords, hi.targets);
				updateSearchBox();
				return false;
			});
		;
	}
};

var options = 
{
	exact:"exact",
	style_name_suffix:false,
	//debug_referrer:"http://www.google.com/search?sourceid=navclient&aq=hss0&oq=Rio Rancho&ie=UTF-8&rlz=1T4ADFA_enUS380US397&q=rio rancho new mexico and for sale",
	debug_referrer:"",
	remove: false, 
	hide: false, 
	immediate: false,
	container: this[0]
};

jQuery.fn.highlightSearchKeywords = function(settings) {
	settings = jQuery.extend(true, {
		container: this[0]  
	}, settings);

	searchTerms = getSearchKeywords(options);
	var searchTerms = getSearchKeywords(options);
	
	if (options.hide)
	{
		removeSearchHighlight(this.get());
		updateHighlightText();
		return this;
	}
	else if (options.remove)
	{
		removeSearchHighlight(this.get());
		$("#search-highlight-bar").remove();
		return this;
	}

	var keywords = mdwParseKeywords(searchTerms);

	if (searchTerms.length == 0 || keywords.length == 0) { return false; }

	if ($("#search-highlight-bar").length === 0)
	{
		$('<div id="search-highlight-bar"/>').prependTo(settings.container);
	}

	$("#search-highlight-bar").data('searchHighlight', {'keywordStr': searchTerms, 'keywords': keywords, 'targets': this.get()});

	if (settings.immediate)
	{
		addSearchHighlight(keywords, this.get());
	}

	updateSearchBox();

	return this;
};

$(document).ready(function() {
		$("#word-highlighting").highlightSearchKeywords();
	}); 

