var HumiraSearch = new (new Class(function() {
	var self = this;
	
/* == PRIVATE == */	
	// default options
	var options = {
		request: {
			url: (applicationRoot || "") + "/searchJSON.aspx" // results page for JSONP					
		},
		
		searchTarget: {
			url: (applicationRoot || "") + "/searchResults.aspx", // search page for showing search results
			k: "q" // querystring key to use for search term
		},		
		
		targetId: "searchWrap",
		searchField: ".inputWrap input",
		
		minCharacters: 0,
		maxResults: 10,
		maxVisible: 4,
		
		termWrapStart: '<span class="term">',
		termWrapEnd: '</span>',
		defaultMessage: "Enter search term.",
		
		overClass: "itemOver",
		selectedClass: "",
		
		initScrollHeight: null,
		scrollHandleClass: "smartScrollKnob",
		scrollBarClass: "smartScrollBar",
		barYOffset: 3
				
	};	
	
	// term and data related
	var currTerm, currContent=null, currSelectedEl=null, currSelectedIndex=null, currResultMap=null, resultsJSON;

	// fx instances
	var slideFx, dragFx, scrollFx;
	
	// search field related
	var searchParent, searchField, searchDefaultValue = "", searchRequest;
	
	// scroll related
	var scrollSize=null, scrollEls=null, isDragging=false;

	// create elements for smart search	
	var smartWrap 	= new Element("div", {"id": "smartWrap"});
	var contentWrap = new Element("div", {"id": "smartContentWrap"});
	var slider 		= new Element("div", {"id": "smartSlider"});
	var sliderIn 	= new Element("div", {"id":"smartSliderIn"});
	var tab 		= new Element("div", {"id": "smartTab", events: {
		'click': function() {
			slideFx.toggle().chain(function() {
				setToggleState();
			});
		}
	}});	
	/*	
	var searchRequest = new Request.JSONP($extend({
		onComplete: function(data) {			
			processSearch(data);
			self.fireEvent("onSearchComplete", [data]);			
		}
	}, options.request));	*/
		
	var init = function() {
		searchParent = $(options.targetId) || new Element("div");
		
		build();
		setDefaultContent();
		
		slideFx 	= new Fx.Slide(slider).hide();
		searchField = searchParent.getElement(options.searchField)
		.addEvents({
			"keyup": function(e) {
				e.preventDefault();
				e.stopPropagation();
				searchFieldDelegate(e.key, e);
			},
			"keydown": function(e) {
				if (e.key == "enter") e.preventDefault();
			},
			"focus": function(e) {				
				if (this.value == searchDefaultValue) this.value = ""
			},
			"blur": function(e) {
				if (!this.value) this.value = (searchDefaultValue || "")
			}		
		});
		searchDefaultValue = searchField.value;
		
	};					
	
	var setToggleState = function() {
		var state = slideFx.open;
		var height = tab.getStyle("height").toInt()

		if (state) tab.setStyle("backgroundPosition", "0px " + (-(height)) + "px");
		else tab.setStyle("backgroundPosition", "0px 0px");
	};
	
	var makeRequest = function(str) {
		searchRequest = new Request.JSONP($extend({
			onComplete: function(data) {			
				processSearch(data);
				self.fireEvent("onSearchComplete", [data]);			
			},
			data:{term: str, max: options.maxResults}
		}, options.request));		
		
		//searchRequest.options.data = {term: str, max: options.maxResults};		
		searchRequest.send();
	};
	
	var processSearch = function(data) {		
		var _content, _results = data.r;
		
		if (_results.length <= options.maxVisible) removeScroll();
				
		if (_results.length > 0) {
			currResultMap 	= new Object();
			_content 		= new Element("ul");	
			var ex 			= new RegExp("("+currTerm.escapeRegExp()+")", "g");
			
			for (var i=0; i < _results.length; i++) (function(i){
				var replaced = _results[i].replace(ex, options.termWrapStart+"$1"+options.termWrapEnd)			
				var li = new Element("li", {"html":"<a href='"+options.searchTarget.url+"?"+options.searchTarget.k+"="+_results[i]+"'>"+replaced+"</a>"})
				.addEvents({
					"mouseenter":function(e) {
						e.stop();
						selectSearchItem(i);
					},
					"mouseleave":function(e) {
						e.stop();
						deselectSearchItem(i);
					}
				})				
				currResultMap[i] = li;
				
				_content.adopt(li)			
			})(i);
			
			setSmartContent(_content);							
		}
		else {
			removeScroll();
			setDefaultContent();			
		}
		
		if (_results.length > options.maxVisible) addScroll();		
		
		slideFx.slideIn().chain(function() {
			setToggleState();
		});
		resultsJSON = data;
	};
	
	var searchFieldDelegate = function(key, e) {
		var keymap = {
			"down": 	selectNext,
			"up": 		selectPrev,
			"enter": 	gotoSearchItem
		};      				
		// remove initial space and any occurrence of 2+ consecutive spaces
		var _term = (searchField.value.replace(/^\s+/g, '').replace(/\s{2,}/g, ' '));
		if (keymap.hasOwnProperty(key))
			keymap[key]();
		else if (_term.length >= options.minCharacters && currTerm != _term) {			
			makeRequest(_term);
			currTerm = _term;			
		}
		else {
			// they've hit backspace to the point that there are characters, but less than the minimum
		}			
	};
	
	var build = function() {		
		searchParent.adopt(smartWrap.adopt(contentWrap.adopt(slider.adopt(sliderIn)), tab));		
	};
	
	var selectNext = function() {
		var next = (!$chk(currSelectedIndex)) ? 0 : (currSelectedIndex + 1 > resultsJSON.r.length - 1) ? 0 : currSelectedIndex + 1;
		selectSearchItem(next);
	};
	
	var selectPrev = function() {
		var prev = (!$chk(currSelectedIndex)) ? 0 : (currSelectedIndex - 1 < 0) ? resultsJSON.r.length - 1 : currSelectedIndex - 1;
		selectSearchItem(prev);		
	};
	
	var gotoSearchItem = function() {
		if ($chk(currSelectedIndex)) window.location.href = (currResultMap[currSelectedIndex].getElement("a").get("href") || "#")
	};
	
	var selectSearchItem = function(index) {
		if (isDragging) return;
		
		if ($chk(currSelectedIndex) && currSelectedIndex != index) currResultMap[currSelectedIndex].removeClass(options.overClass);
		currResultMap[index].addClass(options.overClass);
		
		currSelectedEl = currResultMap[index];
		currSelectedIndex = index;
		if (resultsJSON.r.length > options.maxVisible && scrollFx) scrollSlider(currSelectedIndex);
	};
	
	var deselectSearchItem = function(index) {
		currResultMap[index].removeClass(options.overClass);
		if (currSelectedIndex == index) currSelectedIndex = null;
	};
	
	var setSmartContent = function(con) {				
		if (currContent)
			con.replaces(currContent);
		else sliderIn.adopt(con);
		
		currContent = con;	
	};	
	
	var setDefaultContent = function() {		
		var _default = new Element("p", {"html": options.defaultMessage});
		setSmartContent(_default);
	};
	
	var addScroll = function() {
		var el = currContent.getFirst("li");
		if (!scrollSize && el) {			
			scrollSize = el.getSize();			
			scrollSize.margin = el.getStyle("marginTop").toInt() + el.getStyle("marginBottom").toInt();
		}
		
		[slider, sliderIn].each(function(el, i) {
			el.setStyles({
				height: (scrollSize.y * options.maxVisible) + (scrollSize.margin * options.maxVisible) + "px",
				overflow: "hidden"
			});			
		});

		
		// first time scrolling, elements and fx instance not created
		if (!scrollEls) {
			scrollFx = new Fx.Scroll(sliderIn, {link: "cancel"});
			
			var barSize = {
				y: (scrollSize.y * options.maxVisible) + (scrollSize.margin * options.maxVisible) - (options.barYOffset * 2) + "px"				
			};
			
			scrollEls = {};
			scrollEls.bar = {};
			scrollEls.handle = {};
			
			scrollEls.bar.el 		= new Element("div", {"class": options.scrollBarClass, styles: {height: barSize.y, top: options.barYOffset + "px"}}).inject(slider);
			scrollEls.handle.el 	= new Element("div", {"class": options.scrollHandleClass, styles: {height: "20px"}}).inject(scrollEls.bar.el);
			
			scrollEls.bar.size 		= scrollEls.bar.el.getSize();
			scrollEls.handle.size 	= scrollEls.handle.el.getSize();
			
			dragFx = new Drag.Move(scrollEls.handle.el, {
				container: scrollEls.bar.el, 
				onDrag: function(el, e) {
					scrollSlider(el, e);
				},
				onStart: function() {
					isDragging = true;
				},
				onComplete: function() {
					isDragging = false;
				},
				onCancel: function() {
					isDragging = false;
				}
			});
		};
		
		resetScroll();
		
		scrollEls.bar.el.setStyle("display", "");
		scrollEls.handle.el.setStyle("display", "");
		
	};
	
	var removeScroll = function() {
		if (scrollEls) {
			scrollEls.bar.el.setStyle("display", "none");	
			scrollEls.handle.el.setStyle("display", "none");
		};		
		
		[slider, sliderIn].each(function(el, i) {
			el.setStyles({
				height: "",
				overflow: ""
			});			
		});
		
		resetScroll();						
	};
	
	var resetScroll = function() {
		if (scrollFx) scrollFx.set(0,0);
		if (scrollEls) scrollEls.handle.el.setStyle("top", "0px");
	};
	
	var scrollSlider = function(index) {
		var top, height = scrollEls.handle.size.y, base = scrollEls.bar.size.y;		
		
		if ($type(index) == "element") {									
			top = index.style.top.toInt();
			if (!$chk(height)) height = index.getSize().y;
				
			index = ((top / (base - height).toInt()) * resultsJSON.r.length).round() - 1;
			scrollFx.start(0, index * scrollSize.y);
			
			//console.log(Math.floor(index / options.maxVisible))
			//scrollFx.start(0, Math.floor(index / options.maxVisible) * options.maxVisible)
			
			//if (index - 1 <= 0) scrollFx.start(0,0);
			//else if (index - 1 == resultsJSON.length - 1) scrollFx.toBottom();
			//else scrollFx.start(0, currResultMap[index - 1].getPosition(sliderIn).y)
		}
		else if ($type(index) == "number") {
			//scrollFx.toElement(currResultMap[index]);
			scrollFx.start(0, index * scrollSize.y)
			scrollEls.handle.el.tween("top", ((index / (resultsJSON.r.length - 1)) * (base - height)).round());
		}
		
	};
	
/* == PUBLIC == */
	$extend(this, {		
		setOptions: function(opts) {
			if ($type(opts) != "object") return;			
			$extend(options, opts);
		}
	})

	//$extend(this, new Options());	
	$extend(this, new Events());	
	
	// initialize when DOM is ready
	window.addEvent('domready', init)
	
}))();
/*
HumiraSearch.setOptions({
		request: {
			url: (applicationRoot || "") + "/searchJSON.aspx" // results page for JSONP					
		},
		
		searchTarget: {
			url: (applicationRoot || "") + "/searchResults.aspx", // search page for showing search results
			k: "q" // querystring key to use for search term
		}	
});
*/
