/*********************************************************************************************
 * NB. Requires Mootools 1.2 Core and More files
 * 
 * Class: InlineSearch
 * Constructor Arguments: 
 * 		targetFieldsSelector: Expression to select the target elements to perform search over
 * 		inputFieldId:	The search string input field
 * 		searchOnKeyUp: Boolean indicating whether search should be performed upon changing of search string value
 * 
 * Attributes:
 * 		minLength: the minimum length required of the search string before performing a search
 *  	onSearchComplete: function to run upon completing a search
 * 		numberOfMatches: returns the current number of matches for the search string
 * 
 * Functions:
 * 		performSearch: marks up all text within the targetFields with a 
 * 			<span class="highlighted"> and runs onSearchComplete upon completion.
 * 		clearHighlighting: removes all highlighting mark up from the targetFields
 * 		focusNextResult: will add a class="focused" to the first or subsequent result.  
 * 			Selection wraps from the end of targetFields back to the first.    
 *
 ********************************************************************************************* 
 */

var InlineSearch = new Class({
	_searchFieldId: "inlineSearchField",
	_searchTargetSelector: ".searchTarget",
	_highlightedTextClass: "highlighted",
	
	_highlighted: false,
	_currentlyHighlighting: false,
	_searchOnKeyup: false,
	_enableBlockout: false,
	_enableArrows: false,
	
	onSearchComplete: $empty,
	numberOfMatches: 0,
	minLength: 3,
	/**
	 * Constructor
	 */
	initialize: function(targetFieldsSelector, inputFieldId, searchOnKeyup, enableBlockout, enableArrows) {
		this._searchFieldId = inputFieldId;
		this._searchTargetSelector = targetFieldsSelector;
		
		// If searchOnKeyup add an onKeyup event to the search input field to perform the search
		// NB. The search will be performed 1/2 second after the user has completed typing 
		if ($chk(searchOnKeyup)) {
			this._searchOnKeyup = searchOnKeyup;			
			$(this._searchFieldId).addEvent("keyup", function(event) {
					if (event.key == "enter" && this._currentTimer == null) {						
						this.focusNextResult();	
						$(this._searchFieldId).focus();
						(function() {this.selectResult($$("."+this._highlightedTextClass)[this._currentlyFocused]);}).bind(this).delay(10);
					} else {
						$clear(this._currentTimer);
						this._currentTimer = this.performSearch.delay(500, this);
					}
			}.bind(this));
		}
		
		//If enableBlockout, create a blockout object
		if ($chk(enableBlockout)) {
			this._enableBlockout = true;
			this._blockout = new Blockout();
			this._blockout.clickToHide = true;
			this._blockout.onHide = function() {$$(".focused").each(function(e){e.removeClass("focused")})}
		}		
		
		if ($chk(enableArrows)) {
			this._enableArrows = enableArrows;
		}
		if (this._enableArrows) {
			document.addEvent("scroll", this.repositionMatchArrows.bind(this));
			window.addEvent("resize", this.repositionMatchArrows.bind(this));
		}
	},
	/**
	 * performSearch
	 * 
	 * 
	 */
	performSearch: function() {
		this._currentTimer = null;
		if (this._currentlyHighlighting) {
			return;
		}
		
		if (this._enableBlockout) {
			this._blockout.hideBlockout();
		}
		
		var searchTerm = $(this._searchFieldId).get("value");
		if ($chk(searchTerm) && searchTerm.length>this.minLength)  {
			if (this._highlighted) {
				this.clearHighlighting();
			}
			
			this.numberOfMatches = 0;
			
			
			this._currentlyHighlighting = true;
			$each($$(this._searchTargetSelector), function(el) {
				el.set("html", this._doHighlight(el.get("html"), searchTerm));
			}.bind(this));
			this._highlighted = true;
			this._currentlyHighlighting = false;
			
			if (this._enableArrows) {
				this.repositionMatchArrows();
			}
			
			$$(".highlighted").each(
				function(el, i) {
					el.addEvent("focus", function(ev) {
						this.selectResult(ev.target);						
					}.bind(this));
					el.addEvent("blur", function(ev) {	
						this.deselectResult(ev.target);
					}.bind(this));
				}.bind(this)
			);
			
			this.onSearchComplete();
		} else {
			this.clearHighlighting();
		}
	},
	/**
	 * clearHighlighting
	 * 
	 * 
	 */
	clearHighlighting: function() {
		this._currentlyFocused = null;
		// only clear the highlighting if there is highlighted text to clear
		if (this._highlighted) {
			$each($$("."+this._highlightedTextClass), function(el) {				
				el.appendText(el.get('text'), 'after').destroy();
			});
			$each($$(".match-img"),function(el){
				el.destroy();				
			});
		}
	},
	/**
	 * focusNextResult
	 * 
	 * 
	 */
	focusNextResult: function() {
		if (this.numberOfMatches>0) {						
			if (this._currentlyFocused == null || (this._currentlyFocused == $$("."+this._highlightedTextClass).length - 1)) {
				this.clearCurrentlyFocused();
				$$("."+this._highlightedTextClass)[0].focus();
				this._currentlyFocused = 0;
			} else {
				this.clearCurrentlyFocused();
				this._currentlyFocused = this._currentlyFocused + 1;
				$$("."+this._highlightedTextClass)[this._currentlyFocused].focus()				
			}		
		}
	},
	/**
	 * selectResult
	 * 
	 * 
	 */
	selectResult: function(element) {
		this.clearCurrentlyFocused();
		element.addClass("focused");
		this._currentlyFocused = $$("."+this._highlightedTextClass).indexOf(element);
		
		if (this._enableBlockout) { 
			(function() {this._blockout.highlightElement($$(".focused")[0])}).bind(this).delay(0);
		};
		
	},
	/**
	 * deselectResult
	 * 
	 * 
	 */	
	deselectResult: function(element) {
		element.removeClass("focused");
		if (this._enableBlockout) { 
			(function() {this._blockout.hideBlockout()}).bind(this);
		};		
	},
	/**
	 * clearCurrentlyFocused
	 * 
	 * 
	 */	
	clearCurrentlyFocused: function() {
		if ($type(this._currentlyFocused) == "number") {
			this.deselectResult($$("."+this._highlightedTextClass)[this._currentlyFocused]);
		}
	},
	/**
	 * _doHighlight
	 * 
	 * 
	 */	
	_doHighlight: function (bodyText, searchTerm) 
	{  
	   var highlightStartTag = "<span class='highlighted' tabindex='0'";
	   var highlightEndTag = "</span>";
	  
	  // find all occurrences of the search term in the given text,
	  // and add some "highlight" tags to them (we're not using a
	  // regular expression search, because we want to filter out
	  // matches that occur within HTML tags and script blocks, so
	  // we have to do a little extra validation)
	  var newText = "";
	  var i = -1;
	  var lcSearchTerm = searchTerm.toLowerCase();
	  var lcBodyText = bodyText.toLowerCase();
	    
	  while (bodyText.length > 0) {
	    i = lcBodyText.indexOf(lcSearchTerm, i+1);
	    if (i < 0) {
	      newText += bodyText;
	      bodyText = "";
	    } else {
	      // skip anything inside an HTML tag
	      if (bodyText.lastIndexOf(">", i) >= bodyText.lastIndexOf("<", i)) {
	        // skip anything inside a <script> block
	        if (lcBodyText.lastIndexOf("/script>", i) >= lcBodyText.lastIndexOf("<script", i)) {
	          //increment the numberOfMatches
			  this.numberOfMatches = this.numberOfMatches + 1;	
	        	
	          newText += bodyText.substring(0, i) 
	          				+ highlightStartTag + " id='match"+this.numberOfMatches+"'>"
	          				+ bodyText.substr(i, searchTerm.length) 
	          				+ highlightEndTag;
			 
	          if (this._enableArrows) {
				  new Element("img",
							{
								"src": "../../images/arrow_right.gif",
								"alt": "",
								"class": "match-img",
								"id": "match"+this.numberOfMatches+"img"
							}
				  ).inject(document.body);
	          }
			  
	          bodyText = bodyText.substr(i + searchTerm.length);
	          lcBodyText = bodyText.toLowerCase();
	          i = -1;
	        }
	      }
	    }
	  }
	  
	  return newText;
	},
	
	repositionMatchArrows: function() {
		
		var s_y = window.scrollY;
		var d_y = window.getHeight();
		
		if ($("upCount")) {
			$("upCount").destroy();
		}
		
		if ($("downCount")) {
			$("downCount").destroy();				
		}
		
		if (!$chk(this.numberOfMatches)) return;
		if (this.numberOfMatches <= 0) return;
		
		for (var i=1,up=0,down=0; i<=this.numberOfMatches; i++) {
			var img = $("match"+i+"img");
			var match = $("match"+i);
			var m_y = match.getPosition(document.body).y;
			
			var f_y;
			
			if (m_y < (s_y - 5)) {
				img.set("src","../../images/arrow_up2.gif");
				f_y = s_y + 5;
				up = up + 1;
			} else if (m_y > (d_y + s_y)) {
				img.set("src","../../images/arrow_down.gif");
				f_y = s_y + d_y - 20;
				down = down + 1;
			} else {
				img.set("src","../../images/arrow_right.gif");
				f_y = m_y;
			}
			
			img.setStyles({
				"position":"absolute",
				"top": f_y + "px",
				"left":"50%",
				"margin-left":"-500px"
			});	
		}
		if (up>0) {
			new Element("div", {"html":up, "id":"upCount","title":"scroll up for "+up+" results"}).setStyles({"position":"fixed","top":"3px","left":"50%", "margin-left":"-506px","color":"white","font-size":"0.7em"}).inject(document.body);
		}
		if (down>0) {
			new Element("div", {"html":down, "id":"downCount","title":"scroll down for "+down+" results"}).setStyles({"position":"fixed","bottom":"0px","left":"50%", "margin-left":"-506px","color":"white","font-size":"0.7em"}).inject(document.body);
		}
	}
});
