/* Copyright (c) 2010 ShopifyConcierge. All Rights reserved. Author: Gavin Terrill */
(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.account = account;
        base.queryInput = $(el);
        base.el = el; 
        base.queryInput.data("searchify", base);
		
		var instances = $(window).data('searchify_counter');
		base.instances = instances ? parseInt(instances) : 0;
        $(window).data('searchify_counter', base.instances + 1);
		
        base.init = function() {
            base.options = $.extend({}, $.searchify.defaultOptions, options);
			if (typeof(options) != "undefined") {  // legacy options
				base.options.moneyformat = options.moneyFormat || base.options.moneyformat;
			}
			if (typeof(base.options.searchify) == "undefined")
				base.options.searchify = "http://" + base.account + ".shopifywidgets.com";
			
			// don't know how to handle anything other than text or string input types
			var type = base.queryInput.attr('type') ;
			if (type != "text" && type != "search") {
				return;
			}
			
			base.flashfix();
			
			// load api.js so we can access money formatting according to shop preference
			if (base.instances == 0 && (typeof Shopify.formatMoney) == 'undefined') {
				$.getScript("/shopify/api.js", function() {  
					//alert("Script loaded and executed.");  
				});
			}
			
			base.queryInput.attr("autocomplete", base.options.autocomplete ? "on" : "off");
			
			// turn on cool safari search if applicable
			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;
			}
			
			/* Add some event handlers */
			
			// 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');
					}
				}).blur(function() {
					if (this.value == "") {
						this.value = base.options.prompt;
						$(this).addClass('searchify_prompt');
					}
				});
			}
			
			// keypress handling
			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) {
					if (!base.resultsContainerDiv.is(":visible")) return;
					if (e.shiftKey || e.ctrlKey || e.altKey) return;
					var next = (base.selected ? base.selected.next('li') : jQuery('#' + base.ulId).find('li:first-child')); 
					if (next.length == 0) next = jQuery('#' + base.ulId).find('li:first-child');
					base.current(next);
					return false;
				} else if (keynum == ARRUP) {
					if (!base.resultsContainerDiv.is(":visible")) return;
					if (e.shiftKey || e.ctrlKey || e.altKey) return;
					var prev = (base.selected ? base.selected.prev('li') : jQuery('#' + base.ulId).find('li:last-child')); 
					if (prev.length == 0) prev = jQuery('#' + base.ulId).find('li:last-child');
					base.current(prev);
					return false;
				} else if (keynum == PAGEUP) {
					if (!base.resultsContainerDiv.is(":visible")) return;
					base.current(jQuery('#' + base.ulId).find('li:first-child'));
				} else if (keynum == PAGEDOWN) {
					if (!base.resultsContainerDiv.is(":visible")) return;
					base.current(jQuery('#' + base.ulId).find('li:last-child'));
				} else {
					if (/[a-zA-Z0-9]/.test(String.fromCharCode(keynum)) || keynum == DELETE || keynum == BACKSPACE) {
						base.lookup()
					}
				}
			});
			
			/* Create HTML markup */
			
			// create container for search results
			base.resultsContainerDivId = base.options.resultsContainerDivId; if (base.instances > 0) base.resultsContainerDivId += base.instances;

			var resultContainer = [];
			resultContainer.push("<div id='");
			resultContainer.push(base.resultsContainerDivId);
			resultContainer.push("' class='searchify'>");
			resultContainer.push("<div class='searchify_header'><div class='searchify_corner'></div><div class='searchify_bar'></div></div>");
			
			base.resultsId = base.options.resultsId; if (base.instances > 0) base.resultsId += base.instances;
			base.ulId = base.options.ulId; if (base.instances > 0) base.ulId += base.instances;
			
			resultContainer.push("<div id='" + base.resultsId + "' class='searchify_results'></div>");
			resultContainer.push("<div class='searchify_footer'><div class='searchify_corner'></div><div class='searchify_bar'></div></div>");
			resultContainer.push("</div>");
			base.queryInput.parent().append(resultContainer.join(''));
			
			// position container relative to the input field
			var pos = base.queryInput.position();
			base.resultsContainerDiv = $("#" + base.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());
			
			jQuery('.searchify_product a').live('mouseover', function() {
				//base.current($('#' + base.ulId + " a[name='" + jQuery(this).attr('name') + "']").parent());
				base.current(jQuery(this).parent());
			}).live('click', function(e) {
				e.preventDefault(); // location set in base.select()
				base.select();
			});
			
			jQuery('.searchify_suggest a').live('click', function(e) {
				base.queryInput.val($(this).text());
				e.preventDefault();
				//$(this).parents('form').submit();
			});			
        }
        
        // Schedule search
        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
			}
		}
		
		// Set current node
		base.current = function(node) {
			if ($(node).length > 0) {
				base.clear();
				base.selected = $(node);
				base.selected.addClass("searchify_highlight");
			}
		}
		
		// Unselect any selected node
		base.clear = function() {
			if (base.selected) {
				base.selected.removeClass("searchify_highlight");
				base.selected = null;
			}
		}
		
		// Track a search hit then go to the selected node's url
		base.select = function() {
			if (base.selected) {
				var inputString = base.queryInput.val();
				var a = base.selected.find('a');
				var product = a.attr('rel');
				base.queryInput.val(base.selected.find(".suggestion").text());
				
				// track hits in ga
				if (base.options.trackGA && typeof(pageTracker) != "undefined") {
					pageTracker._trackEvent("searchify", inputString, a.attr('href'), 0);
				}
				
				// track hits in searchify
				jQuery.ajax({
					type: 'get', 
					url: base.options.searchify + "/searchify/track/" + product, 
					data: {"term": inputString}, 
					async: false,
					dataType: 'jsonp',
					success: function(data) {
						document.location.href = a.attr('href');
					}
				});
			}
		}
		
		// Hide the results
		base.fadeout = function() {
			if (base.options.fadeout) {
				base.resultsContainerDiv.fadeOut();
			}
		}
		
		base.highlight = function(title, term) {
			if (typeof(title) == 'undefined') return;
			
			var index = title.toLowerCase().indexOf(term);
			if (index > -1) {
				var result = title.substring(0, index) + "<span class='searchify_query'>";
				result  += title.substring(index, index + term.length) + "</span>";
				result  += title.substring(index + term.length);
				return result;
			} else {
				return title;
			}
		}
		
		// Timer used to wait for input to stop before initiating search
		base.time0 = function() {
			if (base.timer) {
				clearTimeout(base.timer);
			}
		}
		
		base.addProductLi = function(i, item, inputString, results) {
			if (i == base.options.maxresults) {
				return false;
			}
			
			var data = [];
			data.push("<li class='searchify_product'>");
			data.push("<a name='" + i + "' href='" + base.options.producturl + item.handle + "' rel='" + item.id + "'>");
			if (base.options.thumbnail) data.push("<img src='" + item.thumbnail + "' alt=''/>");
			data.push("<div><p class='suggestion ellipsis'>");
			data.push(base.highlight(item.title, inputString));
			data.push("</p>");
			if (base.options.vendor) {
				data.push("<span class='searchify_vendor'>" + base.highlight(item.vendor, inputString) + "</span>");	
			}
			
			if (base.options.price) {
				data.push("<span class='searchify_price'>");
				if ((typeof Shopify) != 'undefined') {
					data.push(Shopify.formatMoney(item.price_min * 100, base.options.moneyformat));
				} else {
					data.push(item.price_min.toFixed(2));
				}
				data.push("</span>");
			} else
				data.push("&nbsp;");

			data.push("</div></a></li>");
			results.push(data.join(''));
		}
		
		// Perform the AJAXy search
		base.search = function() {
			var inputString = base.queryInput.val();
			
			$('body').css('cursor', 'wait');
			setTimeout(function() { // async
				$('#' + base.ulId).remove();
				base.resultsContainerDiv.find('.searchify_msg').remove();
				
				var msg = [];
				msg.push("<div class='searchify_msg searchify_searching'>");
				msg.push(base.options.searchingprompt.replace("#q", inputString));
				msg.push("</div>");
				$('#' + base.resultsId).append(msg.join(''));
				
				base.resultsContainerDiv.fadeIn(); // show the results div while remote search going on
				$.ajax({
					url: base.options.searchify + "/searchify/search/" + inputString,
					data: {page:1, limit:base.options.maxresults, title:base.options.matchtitle, soundex:base.options.soundex},
					dataType: "jsonp", cache: true,
					error: function(e) {
						alert("Search fail: " + e);
						$('body').css('cursor', 'default');
					}, 
					success: function(json) {
						$('#' + base.resultsId).empty();
						
						var results = [];

						try {
							if (json.soundex.length > 0) {
								results.push("<div class='searchify_msg'>");
								results.push(base.options.soundexprompt);
								results.push("</div>");
								results.push("<ul id='" + base.ulId + "'  class='searchify_result_list'>");
								$.each(json.soundex, function(i, item) {
									base.addProductLi(i, item, inputString, results);
								});
								results.push('</ul>');
							} else if (json.products.length > 0) {
								results.push("<div class='searchify_msg'>");
								results.push(base.options.matchingprompt.replace("#q", inputString));
								results.push("</div>");
								results.push("<ul id='" + base.ulId + "' class='searchify_result_list'>");
								$.each(json.products, function(i, item) {
									base.addProductLi(i, item, inputString, results);
								});
								results.push('</ul>');
								if (json.products.length == base.options.maxresults) {
									var more = [];
									more.push("<div id='searchify_more"); if (base.instances > 0) more.push(base.instances);
									more.push("' class='searchify_msg searchify_more'>");
									more.push(base.searchqueryurl(inputString, base.options.moreprompt));
									more.push("</div>");
									results.push(more.join(''));
								}
							} else {
								results.push("<div id='searchify_notfound"); if (base.instances > 0) results.push(base.instances);
								results.push("' class='searchify_msg searchify_more'>");
								results.push(base.searchqueryurl(inputString, base.options.notfoundprompt.replace("#q", inputString)));
								results.push("</div>");
							}
						} catch (e) {
							console.log(e);
						}
						
						$('#' + base.resultsId).append(results.join(''));						
						$('body').css('cursor', 'default');
					}
				})
			}, 0); 
		}
		
		base.searchqueryurl = function(q, prompt) {
			var result = "<a href='/search?q=";
			//result += escape("q=title:" + (q) + "*");
			result += escape(q); 
			result += "'>";
			result += prompt + "</a>";
			return result;
		}
		
		base.flashfix = function() { //http://css-tricks.com/snippets/jquery/change-wmode-with-jquery/
			$("embed").attr("wmode", "opaque");
			var embedTag;
			$("embed").each(function(i) {
				embedTag = $(this).attr("outerHTML");
			    if ((embedTag != null) && (embedTag.length > 0)) {
					embedTag = embedTag.replace(/embed /gi, "embed wmode='opaque' ");
					$(this).attr("outerHTML", embedTag);
				} else {
					$(this).wrap("<div></div>");
				}
			});
		}
		
        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,
		trackGA: true,
		vendor: true,
		price: true,
		matchtitle: false,
		soundex: true,
		moneyformat: '$ {{ amount }}',
		matchingprompt: "Products matching '#q'...",
		soundexprompt: "Did you mean...",
		moreprompt: "View all search results",
		notfoundprompt: "No products match '#q'. Search entire site.",
		searchingprompt: "Searching for products matching '#q'..."
    }

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

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

