(function($){
	var RETURN = 13;
	var TAB = 9;
	var ESC = 27;
	var ARRLEFT = 37;
	var ARRUP = 38;
	var ARRRIGHT = 39;
	var ARRDOWN = 40;
	var BACKSPACE = 8;
	var DELETE = 46;
	var PAGEUP = 33;
	var PAGEDOWN = 34;
	
    $.searchify = function(el, account, options){
        var base = this;
        base.swurl = account == "{{shop.name}}" ? "" : "http://" + account + ".shopifywidgets.com";
        base.queryInput = $(el);
        base.el = el; 
        base.queryInput.data("searchify", base);
        
        base.init = function() {
            base.options = $.extend({}, $.searchify.defaultOptions, options);
			
			// don't know how to handle anything other than text
			var type = base.queryInput.attr('type') ;
			if (type != "text" && type != "search") {
				return;
			}
			
			// load api.js so we can access the money formatting logic
			if ((typeof Shopify) == 'undefined') {
				$.getScript("/shopify/api.js", function() {  
					//alert("Script loaded and executed.");  
				}); 			
			}
			
			base.queryInput.attr("autocomplete", base.options.autocomplete ? "on" : "off");
			
			if (base.options.searchtype && jQuery.browser.safari) {
				var clone = base.queryInput.clone(true).attr("type", "search").attr("results", "5");
				clone.insertBefore(base.queryInput);
				base.queryInput.remove();
				base.queryInput = clone;
			}
			
			// fade out the suggestions box when not active
			base.queryInput.blur(function() {
				base.fadeout();
			});
			
			if (base.options.highlight) {
				base.queryInput.focus(function() {
					this.select();
				});
			}
			
			// provide a prompt if supplied
			if (base.options.prompt && base.options.prompt.length > 0) {
				base.el.value = base.options.prompt;
				base.queryInput.addClass('searchify_prompt');
				
				base.queryInput.focus(function() {
					if (this.value == base.options.prompt) {
						this.value = "";
						$(this).removeClass('searchify_prompt');
					}
				});
				
				base.queryInput.blur(function() {
					if (this.value == "") {
						this.value = base.options.prompt;
						$(this).addClass('searchify_prompt');
					}
				});
			}
			
			base.queryInput.keyup(function(e) {
				base.time0(); // reset timer
				
				var keynum;
				if (window.event) // IE
					keynum = e.keyCode;
				else if (e.which) // Netscape/Firefox/Opera
					keynum = e.which;
					
				if (keynum == ESC) {
					if (!base.resultsContainerDiv.is(":visible")) return;
					base.resultsContainerDiv.fadeOut();
					base.clear();
				} else if (keynum == RETURN || keynum == TAB) {
					if (!base.resultsContainerDiv.is(":visible")) return;
					base.fadeout();
					base.select();
				} else if (keynum == ARRDOWN || keynum == ARRRIGHT) {
					if (!base.resultsContainerDiv.is(":visible")) return;
					if (e.shiftKey || e.ctrlKey || e.altKey) return;
					base.current(base.selected ? base.selected.next() : base.results.find('li:first-child'));
					return false;
				} else if (keynum == ARRUP || keynum == ARRLEFT) {
					if (!base.resultsContainerDiv.is(":visible")) return;
					if (e.shiftKey || e.ctrlKey || e.altKey) return;
					base.current(base.selected ? base.selected.prev() : base.results.find('li:last-child'));
					return false;
				} else if (keynum == PAGEUP) {
					if (!base.resultsContainerDiv.is(":visible")) return;
					base.results.find('li:first-child');
				} else if (keynum == PAGEDOWN) {
					if (!base.resultsContainerDiv.is(":visible")) return;
					base.results.find('li:last-child');
				} else {
					if (/[a-zA-Z0-9]/.test(String.fromCharCode(keynum)) || keynum == DELETE || keynum == BACKSPACE) {
						base.lookup()
					}
				}
			});
			
			// create container for search results
			var resultContainer = "<div id='" + base.options.resultsContainerDivId + "'>";
			resultContainer += "<div class='searchify_header'><div class='searchify_corner'></div><div class='searchify_bar'></div></div>";
			resultContainer += "<div id='" + base.options.resultsId + "'><ul id='" + base.options.ulId + "'></ul></div>";
			resultContainer += "<div class='searchify_footer'><div class='searchify_corner'></div><div class='searchify_bar'></div></div>";
			resultContainer += "</div>";
			base.queryInput.parent().append(resultContainer);
			
			// position container relative to the input field
			var pos = base.queryInput.position();
			base.resultsContainerDiv = $("#" + base.options.resultsContainerDivId);
			base.resultsContainerDiv.css("left", pos.left);
			base.resultsContainerDiv.css("top", pos.top + base.queryInput.height() + base.options.offsety);
			base.resultsContainerDiv.css("width", base.options.width > 0 ? base.options.width: base.queryInput.width());
			
			base.results = base.resultsContainerDiv.find('#' + base.options.ulId);
			
			jQuery('#' + base.options.ulId + ' a').live('mouseover', function() {
				base.highlight(jQuery(this).attr('name'));
			}).live('click', function() {
				base.select();
			});
        }
        
        // 
        base.lookup = function() {
			if (base.queryInput.val().length < base.options.minchars) {
				base.resultsContainerDiv.fadeOut(); // hide the results div
			} else {
				base.timer = setTimeout(base.search, base.options.delay); // queue search lookup
			}
		}
		
		base.current = function(node) {
			if ($(node).length > 0) {
				base.clear();
				base.selected = $(node);
				base.selected.addClass("searchify_highlight");
			}
		}
		
		// highlight selected result li
		base.highlight = function(id) {
			base.current($('#' + base.options.ulId + " a[name='" + id + "']").parent());
		}
		
		base.clear = function() {
			if (base.selected) {
				base.selected.removeClass("searchify_highlight");
				base.selected = null;
			}
		}
		
		base.select = function() {
			if (base.selected) {
				base.queryInput.val(base.selected.find(".suggestion").text());
				document.location.href = base.selected.find('a').attr('href');
			}
		}
		
		base.fadeout = function() {
			if (base.options.fadeout) {
				base.resultsContainerDiv.fadeOut();
			}
		}
		
		base.time0 = function() {
			if (base.timer) {
				clearTimeout(base.timer);
			}
		}
		
		base.search = function() {
			var inputString = base.queryInput.val();
			
			$('body').css('cursor', 'wait');
			setTimeout(function() {
				jQuery.ajax({
					type: "GET", url: base.swurl + "/searchify/search/" + inputString + "?page=1&limit=" + base.options.maxresults,
					dataType: "jsonp", cache: true,
					error: function(e) {
						alert("error:" + e);
						$('body').css('cursor', 'default');
					}, 
					success: function(json) {
						base.results.children().remove();
						base.resultsContainerDiv.find('#searchify_more').remove();
						base.resultsContainerDiv.find('#searchify_notfound').remove();
						
						base.resultsContainerDiv.fadeIn(); // show the results div
						if (json.length > 0) {
							$.each(json, function(i, item) {
								if (i == base.options.maxresults) {
									base.more.html("<a href='/search?q='" + inputString + "* class='searchify_more'>" + base.options.moreprompt + "</a>");	
									return false;
								}
								
								var data = "<li class='" + item.entity + "'>";
								data += "<a name='" + i + "' href='" + base.options.producturl + item.handle + "'>";
								if (base.options.thumbnail) data += "<img src='" + item.thumbnail + "' alt=''/>";
								data += "<div><p class='suggestion ellipsis'>";
								
								var index = item.title.toLowerCase().indexOf(inputString);
								if (index > -1) {
									var title = item.title.substring(0, index) + "<span class='searchify_query'>";
									title += item.title.substring(index, index + inputString.length) + "</span>";
									title += item.title.substring(index + inputString.length);
									data += title;
								} else {
									data += item.title;
								}
								
								data += "</p>";
								if (base.options.vendor) {
									data +=  "<span class='searchify_vendor'>" + item.vendor + "</span>";	
								}
								
								if (base.options.price) {
									data += "<span class='searchify_price'>";
									if ((typeof Shopify) != 'undefined') {
										data += Shopify.formatMoney(item.price_min * 100, base.options.moneyFormat);
									} else {
										data += item.price_min.toFixed(2);
									}
									data += "</span>";
								} else
									data += "&nbsp;";

								data += "</div></a>";
								data += "</li>";
								base.results.append(data); // fill the results div
								
								if (i == base.options.maxresults - 1) {
									var more = "<div id='searchify_more'>";
									more += base.searchqueryurl(inputString, base.options.moreprompt);
									more += "</div>";
									base.results.parent().append(more);
								}	
							});
						} else {
							var nf = "<div id='searchify_notfound'>";
							nf += base.searchqueryurl(inputString, base.options.notfoundprompt.replace("#q", inputString));
							nf += "</div>";
							base.results.parent().append(nf);
						}
						$('body').css('cursor', 'default');
					}
				})
			}, 0); 
		}
		
		base.searchqueryurl = function(q, prompt) {
			var result = "<a href='/search?";
			result += escape("q=title:" + (q) + "*");
			result += "'>";
			result += prompt + "</a>";
			return result;
		}
		
        base.init();
    }

    $.searchify.defaultOptions = {
        resultsContainerDivId: "searchify_result_container",
		queryInputId: "query",
		ulId: "searchify_list",
		resultsId: "searchify_results",
		offsety: 0,
		fadeout: true,
		minchars: 3,
		insensitive: true,
		delay: 150,
		width: -1,
		maxresults: 5,
		highlight: true,
		producturl: "/products/",
		thumbnail: true,
		autocomplete: false,
		searchtype: true,
		//description: false,
		vendor: true,
		price: true,
		moreprompt: "View all search results",
		notfoundprompt: "No shortcuts found for '#q'. Search entire site."
    }

    $.fn.searchify = function(inactiveFade, options){
        return this.each(function(){
            (new $.searchify(this, inactiveFade, options));
        });
    }

    // This function breaks the chain, but returns
    // the searchify if it has been attached to the object.
    $.fn.getsearchify = function(){
        return this.data("searchify");
    }
})(jQuery);