
// 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 = 'typeahead-search-box';
		this.fullSearchBaseUrl = '/templates/products/search/ecat.tmpl?search=';
		this.minSearchLength = 3;
		this.positionTop = 0;
		this.positionLeft = 0;
		this.activeLink = function() {};
		this.deactiveLink = function() {};
		this.maxProductsToShow = 2;
		this.maxContentToShow = 1;		

		// Load up passed params
        Object.extend(this, args || {});
        
		this.eProdCatalog = 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.observe ( 'keyup', this.onKeyUp.bind(this) );
        		this.inputElement.observe ( 'focus', this.onFocus.bind(this) );
        	}
        }
        
 	},
 	
 	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.outputContainer = $(this.outputContainerId);
        this.outputContainer.fillin({
        	template: templatefactory.get(this.searchBoxTemplateFile),
        	position: 'replace',
        	callback: this._outputFillinCallback.bind(this)
        });
        this.contentTemplate = templatefactory.get('content-mini-thumb');
        this.productTemplate = templatefactory.get('typeahead-thumb');
	},
	
	_outputFillinCallback: function() {
		this.outputReady = true;
		
		this.outputContainer.style.zIndex = 9999;
		
		this.outputWrapper = this.outputContainer.down('.typeahead-search-wrapper');
		if ( this.outputWrapper ) {
			this.outputWrapper.style.zIndex = 9999;
			this.outputWrapper.style.top = this.positionTop+'px';
			this.outputWrapper.style.left = this.positionLeft+'px';
			
			// Save close link element for later
			this.closeLink = this.outputWrapper.down('a.typeahead-close-link');
		}
		
		this._doSearchQuery();
	},
    
    _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._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,
				
				callbackCompleted: function() {
					self.eProdCatalog = new EndecaCatalog({jsonResult: self.eProdQuery.jsonResult});
					
        			// Note: For typeahead searches, we'll avoid parsing the metadata 
        			// and focus only on products/content
					
					self._productsCallback();
				}
				
			});

			// 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);
    	}
    },
    
    _updateSummary: function() {
		// Total product records
		var recsProd = ( this.eProdCatalog ? this.eProdCatalog.recordCount() : 0 );
		var recsCont = ( this.eContCatalog ? this.eContCatalog.recordCount() : 0 );
		var recsTotal = recsProd + recsCont;
		
		this.outputContainer.select('.typeahead-seeall').each(function(el){
			if ( recsTotal > 0 ) el.show();
			else el.hide();
		});

		var elSummary = this.outputContainer.down('.typeahead-summary');
		if ( elSummary ) {
			var stxt = ( recsTotal == 0 ? 'No results found' :
						 recsTotal == 1 ? 'Top result shown' : 
						 				  'Top ' + recsTotal + ' results shown' );
			elSummary.update(stxt);
		}
			
    },
    
    _productsCallback: function() {
    	this.gotProd = true;
    	this.showResults();
    },
    
    _contentCallback: function() {
    	this.gotCont = true;
    	this.showResults();
    },
    
	showResults: function() {
		
		if ( this.outputReady ) {
			
			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 prodHash = $H(this.eProdCatalog.productList);
				var prodCount = prodHash.size();
				var i = 0;

				if ( prodCount > 0 ) elProdWrap.show();
				else elProdWrap.hide();
				
				prodHash.each( function(productRec) {
					var obj = {
						url_domain : window.URL_DOMAIN,
						url_domain_http : window.URL_DOMAIN_HTTP,
						priceString: productPage.formatPriceRange(productRec.value),
						
						ratingReviewString: productRec.value.TOTAL_REVIEW_COUNT > 1 ? 'reviews' : 'review',
						ratingDisplay: typeof productRec.value.AVERAGE_RATING == 'number' && isFinite(productRec.value.AVERAGE_RATING) ? 'block' : 'none',
						ratingRounded: Math.round(productRec.value.AVERAGE_RATING*10)/10
					};
					
					obj = Object.extend( obj, productRec.value );
					
					var ulClass = 'content-thumb-row';
					if ( ++i >= prodCount ) ulClass += ' last';
					
					var ul = new Element("ul", {'class': ulClass});
					ul.fillin ( { template: this.productTemplate, position: 'replace', object: obj } );
					
					elProdDiv.insert(ul);
				}, this);
			}
			
			
			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 = $H(this.eContCatalog.contentList);
				var prodCount = prodHash.size();
				var i = 0;
				
				if ( prodCount > 0 ) elContWrap.show();
				else elContWrap.hide();

				prodHash.each( function(contentRec) {
					var obj = {
						'p_THUMBNAIL_IMAGE' : '/images/global/clinlogo_thumb.jpg'
						};
					obj = Object.extend( obj, contentRec.value.Properties );
					//obj = Object.extend( obj, contentRec.value.Dimensions ); // ??
					
					var ulClass = 'content-thumb-row';
					if ( ++i >= prodCount ) ulClass += ' last';
					
					var ul = new Element("ul", {'class': ulClass});
					ul.fillin ( { template: this.contentTemplate, position: 'replace', object: obj } );
					
					elContDiv.insert(ul);
				}, this);
				
				
			}
			
			this.eContQuery = null;
			
			// Check if we need to make another query (if user kept typing...)
			this._doSearchQuery();
		}
	}
	
});
