var SpinnerHtml = '<h3><span class="spinnerText"><img src="/images/search/typeahead_loading_hor.gif" style="margin-left:-5px;"></span></h3>';

// This class creates a binding to an input element,
// and as a user enters text, we send a quick search
// to the Endeca engine.
var TypeAheadSearch = Class.create({

	initialize: function(args) {
		this.inputElementId = '';
		this.outputContainerId = '';
		this.outputContainer = null;
		this.outputReady = false;
		this.closeLink = null;
		this.searchBoxTemplateFile = '/templates/typeahead-search-box.tmpl';
		this.fullSearchBaseUrl = '/products/search/ecat.tmpl?search=';
		this.minSearchLength = 3;
		this.positionTop = 0;
		this.positionLeft = 0;
		this.activeLink = function() {};
		this.deactiveLink = function() {};
		this.maxProductsToShow = 2;
		//this.maxProductsToShow = 10000;
		this.maxContentToShow = 1;		

		// Load up passed params
        Object.extend(this, args || {});
        
		this.eProdCatalog = null;
		this.eProdMeta = null;
		this.eProdQuery = null;
		this.eContCatalog = null;
		this.eContQuery = null;
		this.gotProd = false;
		this.gotCont = false;

		this.querySearch = '';
		
        // If we have an element id and that element exists, bind to it
        if ( this.inputElementId ) {
        	this.inputElement = $(this.inputElementId);
        	if ( this.inputElement ) {
        	    this.inputElement.value = "Search Keywords";
        		this.inputElement.observe ( 'keyup', this.onKeyUp.bind(this) );
        		this.inputElement.observe ( 'focus', this.onFocus.bind(this) );
        		this._initOutputContainer();
        	}
        }
        
 	},
 	
 	onFocus: function() {
		this.activeLink();
		if ( !this.outputContainer ) {
			// Init container on first user keystroke
			this._initOutputContainer();
		}
 	},
	
	onKeyUp: function() {
		// NOTE: there are two asynchronous events that will happen when we begin the searching.
		// On the first keystroke, we want to init the output container so it's ready when we
		// have stuff to display.  But the user will probably keep typing while that init is
		// happening, so it's possible that we'll send the search query while still waiting
		// for the output container to load up.  Thus, we have an "outputReady" flag to
		// record when the output container is ready to write to.  We also know if we've made
		// a query already by checking the "eProdQuery" variable.
		
		this.activeLink();
		if ( !this.outputContainer ) {
			// Init container on first user keystroke
			this._initOutputContainer();
		}
		this._doSearchQuery();
	},
	
    _initOutputContainer: function() {
        this.wrapperTemplate = generic.templatefactory.get({path:this.searchBoxTemplateFile});
        this.outputContainer = $(this.outputContainerId);        
        this.wrapperTemplate.evaluateCallback({
		    object: {},
            callback: function(html) {
                this.outputContainer.insert(html);
                this._outputFillinCallback();
            }.bind(this)
        });
        //this.contentTemplate = generic.templatefactory.get({path:'/templates/ecat-mini-thumb.tmpl'});
        this.contentTemplate = generic.templatefactory.get({path:'/templates/typeahead-content-thumb.tmpl'});
        this.productTemplate = generic.templatefactory.get({path:'/templates/typeahead-thumb.tmpl'});
	},
	
	_outputFillinCallback: function() {
		this.outputWrapper = this.outputContainer.down('.typeahead-search-content');
		if ( this.outputWrapper ) {
			// Save close link element for later
			this.closeLink = this.outputWrapper.down('a.typeahead-close-link');
		}
		this.outputReady = true;
	},
    
    _doSearchQuery: function() {
    	// Get the search string and see if it's long enough
		var elStr = String(this.inputElement.value).strip();
		if ( elStr.length >= this.minSearchLength && 
			 elStr != this.querySearch && 
			 !this.eProdQuery && !this.eContQuery ) {

            this.outputContainer.select('.hideme').each(function(el){
                if ( el.hasClassName('conditional') ) {
                    if ( this.eProdCatalog && this.eProdCatalog.productCount() == 0 ) {  el.hide(); }
                } else {
                    el.hide();
                }
    		}.bind(this) );

			this._spin();
			this.querySearch = elStr;
			this.gotProd = false;
			this.gotCont = false;
			var self = this;
			
            

			// Set up the show-all link
			this.outputContainer.select('a.see-all-results').each(function(elSeeAll){
				elSeeAll.href = this.fullSearchBaseUrl+this.querySearch.split(" ").join('+');
			},this);
			
			// Create a product query
			self.eProdQuery = new EndecaQuery ({
				queryString: '',
				searchTerm: elStr,
				filterProducts: true,
				recsPerPage: this.maxProductsToShow,
				//typeAheadSearch: true,
				enableLogging: false,
				searchDimensions: false,
				rollupDetail: false,
				
				callbackCompleted: function(self) {
					self.eProdCatalog = new EndecaCatalog({jsonResult: self.eProdQuery.jsonResult});
					self.eProdMeta = new EndecaMeta({jsonResult: self.eProdQuery.jsonResult});
					
        			// Note: For typeahead searches, we'll avoid parsing the metadata 
        			// and focus only on products/content
					
					self._productsCallback();
				}.curry(self)
				
			});

			// Create a content query
			/*self.eContQuery = new EndecaQuery ({
				queryString: '',
				searchTerm: elStr,
				filterContent: true,
				recsPerPage: this.maxContentToShow,
				//typeAheadSearch: true,
				enableLogging: false,
				searchDimensions: false,
				searchMatchMode: 'matchallany',
				
				callbackCompleted: function() {
					self.eContCatalog = new EndecaCatalog({jsonResult: self.eContQuery.jsonResult});
					
					self._contentCallback();
				}
				
			});
			
			// Go do them
			*/
			self.eProdQuery.makeRequest();
			/*self.eContQuery.makeRequest();*/
		}
    },
    
    _spin: function() {
    	var elSummary = this.outputContainer.down('.typeahead-summary');
    	if ( elSummary ) {
    		elSummary.update(SpinnerHtml);
    		elSummary.show();
    	}
    },
    
    _updateSummary: function() {
		// Total product records
		var recsProd = ( this.eProdCatalog ? this.eProdCatalog.recordCount() : 0 );
		var recsCont = ( this.eProdMeta.contentList ? this.eProdMeta.contentList.length : 0 );
		var recsTotal = recsProd + recsCont;
		
		this.outputContainer.select('.hideme').each(function(el){
			if ( recsTotal > 0 ) el.show();
			else el.hide();
		});

		var elSummary = this.outputContainer.down('.typeahead-summary');
		var viewAll = this.outputContainer.down('.typeahead-seeall');
		if ( elSummary ) {
		    if ( recsTotal == 0 ) {
		        if ( viewAll ) { viewAll.hide(); }
		        elSummary.update('No results found.');
		        elSummary.show();
		    } else {
		        if ( viewAll ) { viewAll.show(); }
		        elSummary.update();
		        elSummary.hide();
		    }
		}
			
    },
    
    _productsCallback: function() {
    	this.gotProd = true;
    	this.showResults();
    },
    
    _contentCallback: function() {
    	this.gotCont = true;
    	this.showResults();
    },
    
	showResults: function() {
		
		this.wrapperTemplate = generic.templatefactory.get({path:this.searchBoxTemplateFile});
        this.outputContainer = $(this.outputContainerId);        
        this.outputContainer.update(this.wrapperTemplate.evaluate({object: {}}));
		this.outputContainer.style.zIndex = 9999;
		
		this.outputWrapper = this.outputContainer.down('.typeahead-search-content');
		if ( this.outputWrapper ) {
			// Save close link element for later
			this.closeLink = this.outputWrapper.down('a.typeahead-close-link');
		}
		
		this.outputContainer.select('a.see-all-results').each(function(elSeeAll){
			elSeeAll.href = this.fullSearchBaseUrl+this.querySearch.split(" ").join('+');
		},this);
			
		this._updateSummary();
		this._showProducts();
		//this._showContent();
		this._watchToClose();
	},
	
	// Set up an event observe to see when the user clicks away from the search box
	_watchToClose: function() {
		var self = this;
		Event.observe(document.body, 'click', function(evt){
			var clicked = Event.element(evt);
			// If the clicked item is the close link or any non-descendent of the output window
			// (excluding the input element and the output container itself)
			// then close the window
			if ( (clicked == self.closeLink || !clicked.descendantOf(self.outputContainer)) && 
				 clicked != self.inputElement && 
				 clicked != self.outputContainer ) {
				 	
         		self.outputContainer.hide();
         		self.deactiveLink();
            }
		},this);
	},
	
	_showProducts: function() {

		if ( this.outputReady && this.gotProd ) {
			
			// Find and clear out the products container
			var elProdWrap = this.outputContainer.down('.typeahead-products-wrapper');
			var elProdDiv  = elProdWrap ? elProdWrap.down('.browse-products') : null;
			if ( elProdDiv ) {
				elProdDiv.update('');
				
				var products = this.eProdCatalog.getProducts();
				var prodCount = products.size();
				var i = 0;

				if ( prodCount > 0 ) elProdWrap.show();
				else elProdWrap.hide();
				
				products.each( function(productRec) {
				    //if (i > 1) { throw $break; }
					var obj = {
						url_domain : window.URL_DOMAIN,
						url_domain_http : window.URL_DOMAIN_HTTP,
						priceString: el.productView.formatPriceRange(productRec),
						
						ratingReviewString: productRec.TOTAL_REVIEW_COUNT > 1 ? 'reviews' : 'review',
						ratingDisplay: typeof productRec.AVERAGE_RATING == 'number' && isFinite(productRec.AVERAGE_RATING) ? 'block' : 'none',
						ratingRounded: Math.round(productRec.AVERAGE_RATING*10)/10
					};
					
					obj = Object.extend( obj, productRec );
					
					var ulClass = 'content-thumb-row';
					if ( ++i >= prodCount ) ulClass += ' last';
					
					var ul = new Element("ul", {'class': ulClass});					
										
					this.productTemplate.evaluateCallback({
                        object: obj,
                        callback: function(elProdDiv, container, html) {
                            ul.insert(html);
                            elProdDiv.insert(ul);
                        }.curry(elProdDiv, ul)
                    });
                    					
				}, this);
				
				$('typeahead-products-shown').update(
				    '(' + products.size() + ' of ' + this.eProdMeta.totalAggrRecords + ' shown)'
				);
				
				if (this.eProdMeta.contentList.length > 0) {
				    this.eContCatalog = this.eProdMeta;
				    this.gotCont = true;
                    this._showContent();
				} else {
				    this.outputContainer.down('.typeahead-content-wrapper').hide();
				}
				
			}
			
			
			this.outputContainer.show();	
			
			this.eProdQuery = null;
			
			// Check if we need to make another query (if user kept typing...)
			this._doSearchQuery();
		}

	},
	
	_showContent: function() {

		if ( this.outputReady && this.gotCont ) {
			
			var elContWrap = this.outputContainer.down('.typeahead-content-wrapper');
			var elContDiv  = elContWrap ? elContWrap.down('.browse-products') : null;
			if ( elContDiv ) {
				elContDiv.update('');
				
				var prodHash = $A([ this.eContCatalog.contentList[0] ]);
				var prodCount = prodHash.length;
				var i = 0;
				
				if ( prodCount > 0 ) elContWrap.show();
				else elContWrap.hide();

				prodHash.each( function(contentRec) {
					var obj = {};
					obj = Object.extend( obj, contentRec );
					//obj = Object.extend( obj, contentRec.value.Dimensions ); // ??
					//obj.content_icon = '/images/search/supp/elcartouche_92x72.jpg';
					
					var ulClass = 'content-thumb-row';
					if ( ++i >= prodCount ) ulClass += ' last';
					
					var ul = new Element("ul", {'class': ulClass});
					
					this.contentTemplate.evaluateCallback({
                        object: obj,
                        callback: function(elContDiv, container, html) {
                            ul.insert(html);
                            elContDiv.insert(ul);
                        }.curry(elContDiv, ul)
                    });
				}, this);
				
				var showing = 1; //prodHash.length ? 1 : prodHash.length;
				
				$('typeahead-content-shown').update(
				    '(' + showing + ' of ' + this.eContCatalog.contentList.length + ' shown)'
				);
				
			}
			
			this.eContQuery = null;
			
			// Check if we need to make another query (if user kept typing...)
			this._doSearchQuery();
		}
	}
	
});

