/**
This renderer is used to render results of an Endeca search.  Each search dimension is
rendered as a dojo Select widget containing all of the refinements for a dimension.
When a value is selected the search service is called to update the relevant refinements.

To use this renderer a page must define the following:
	* HTML element with an id of "selectOptions". A <div> for each Select widget is generated
	* (optional) HTML element with an id of "resultCount"; 
	  innerHTML will be set to a the number of records (products) in the results
*/



Function.prototype.bind = function(obj) {
	var method = this,
	temp = function() {
		return method.apply(obj, arguments);
	};
	return temp;
}

function EndecaSearch(/*Array(String)*/ dimensions, /*Array(hashtable(String, String)*/ translations ,/*Array(hashtable(String, String)*/reverseTranslations) {
	console.debug("Creating new Endeca Search");
	this.dimWidgets = [];       // an array of ComboBox widgets, each widget is a Select containing refinements
	this.listeners = [];        // list of currently registered listeners

	// the search service
	this.service = new dojo.rpc.JsonService("/webstore/ajax/services/endeca.smd");

	// Dimensions
	var validDimensions = new dojox.collections.ArrayList(dimensions);

	// Dimension translations
	var translations = translations;
	function translate(/*String*/ val) {
		// summary: Translates a dimension name
		return translations[val] ? translations[val] : val;
	}
	
	
	var reverseTranslations = reverseTranslations;
	function reverseTranslate(/*String*/ val) {
		// summary: reverseTranslates a dimension name
		return reverseTranslations[val] ? reverseTranslations[val] : val;
	}	

	this.getSelectedNValues = function() {
		// summary:
		//		Parse all of the currently selected refinements and call the search service in the controller.
		var nValues = new Array(1);
		nValues[0] = 0;
		for (var i = 0; i < this.dimWidgets.length; i++) {
			var nValue = this.dimWidgets[i].getValue();
			if (/\d+/.test(nValue)) {
				nValues.length++;
				nValues[nValues.length - 1] = nValue;
			}
		}
		return nValues;
	}
	
	this.getSelectedDisplayedValues = function() {
		// summary:
		//		Parse all of the currently selected refinements and call the search service in the controller.
		var displayedValues = new Array(1);
		displayedValues[0] = 0;
		for (var i = 0; i < this.dimWidgets.length; i++) {
			var wigitId = this.dimWidgets[i].id;
			var displayValue = this.dimWidgets[i].getDisplayedValue();
			if ('Show all' != displayValue) {
				displayedValues.length++;
				displayedValues[displayedValues.length - 1] = reverseTranslate(wigitId) + '|' + displayValue;
			}
		}
		return displayedValues;
	}

	this.doSearch = function() {
		// summary: perform an async search
		
		if (this.valuesChanged()) {
			this.quickSearch(this.getSelectedNValues());
		}
	}
	
	this.valuesChanged = function() {
		if (this.dimWidgets.length <= 0) {
			return true;
		}
		for (var i = 0; i < this.dimWidgets.length; i++) {
			if (this.dimWidgets[i].oldValue != this.dimWidgets[i].getValue()) {
				debug(" " + i + " : Old Value != GetValue:  " + this.dimWidgets[i].oldValue + " != " + this.dimWidgets[i].getValue());
				this.dimWidgets[i].oldValue = this.dimWidgets[i].getValue();
				return true;
			}
		}
		return false;
	}
	
	this.doBrowse = function () {
		// summary:	Browse to selected refinement
		debug("doBrowse called");
		var nValues = this.getSelectedNValues();
		var displayedValue = this.getSelectedDisplayedValues();
		var queryString = 'l/search/';
		for (var i = 0; i < displayedValue.length; i++) {
			if (displayedValue[i] != 0)
			{
				queryString += displayedValue[i];
				queryString += '/';
			}
		}
		if (displayedValue == '0')
		{
			alert("You have not selected any options.");
		} else {
			queryString = queryString.substring(0, queryString.length - 1).toLowerCase();
			debug("browse query string: " + queryString);
			
			window.location.href = escape("/webstore/" + queryString + "/");
		}
	}
	
	this.quickSearchResultsCallback = function(result) {
		// summary:
		//		Callback function. Called by the result of the asynchronous search initiated by doSearch().

		debug('Received response: ' + result.toString());
	
		// first stop the dimWidgets generating events - we are about to update their contents
		// and not disabling event handling produces a nasty infinite loop
		for (var i = this.listeners.length; i > 0; i--) {
			dojo.disconnect(this.listeners.pop());
		}
		for (var i = 0; i < this.dimWidgets.length; i++) {
// TODO REMOVE ME:			debug("Widget " + i + " has " + this.dimWidgets[i].onChange._listeners.length);
			this.dimWidgets[i].setDisabled(true);
		}

		// this is where we'll write out any dimWidgets we create
		var dynamicWidgetsDiv = dojo.byId("selectOptions");
	
		// for each dimension build a list of refinements and add a "Show All" option
		for (var validDimNum = 0; validDimNum < validDimensions.count; validDimNum++)
		{
			validDimension = validDimensions.item(validDimNum);
			for (var i = 0; i < result.dimensions.length; i++)
			{
				var dimension = result.dimensions[i];
				if (validDimension == dimension.name) {
					// try to find a widget for this dimension
					var title = translate(dimension.name);
					var widgetId = escape(title);
					var selectWidget = dijit.byId(widgetId);
	
					// create new widget if one doesn't exist already and set the
					// data list (drop-down contents) for the widget
					if (null == selectWidget) {
						var label = document.createElement("label");
						label.innerHTML = title;
						label.htmlFor = title;
						var br = document.createElement("br");
						var div = document.createElement("div");
						div.id = widgetId;
						dynamicWidgetsDiv.appendChild(label);
						dynamicWidgetsDiv.appendChild(br);
						dynamicWidgetsDiv.appendChild(div);
	
						selectWidget = new dijit.form.FilteringSelect(null,  div);
						this.dimWidgets.push(selectWidget);
						selectWidget.store = createComboBoxData(dimension.refinements);
						// if we've just created the widget, then the selected item must be "All"
						selectWidget.oldValue = "All";
						selectWidget.setValue('All');
						// selectWidget.textInputNode.value = 'Show All';  // this was needed for dojo 0.4
						
						dynamicWidgetsDiv.appendChild(br);
					} else {
						selectWidget.store = createComboBoxData(dimension.refinements);
					}
					
					selectWidget.setDisabled(false);
					selectWidget.touched = true;
				}
			}
		}

		// Create a "go" button if we haven't got one
		var goButton = dojo.byId("goSearch");
		if (goButton.type != "button") {
			goButton = new dijit.form.Button({label: ""}, goButton);
			dojo.connect(goButton, 'onClick', this, this.doBrowse);
			goButton.value = "GO";
		}
	
		// process the now complete set of dimWidgets
		for (var i = 0; i < this.dimWidgets.length; i++) {
			var thisWidget = this.dimWidgets[i];
			
			// if the widget has a number selected it has been used to refine
			// the results so won't have been processed yet (not in dimension list
			// returned from Endeca so we need to manually create a list containing
			// Show All and <Selected Value>.
			if (/\d+/.test(thisWidget.getValue())) {
				if (false == thisWidget.touched) {
					var data = { 
						identifier: "abbreviation", 
						items: [
							{name: "Show all", abbreviation: "All"}, 
							{name: thisWidget.getDisplayedValue(), abbreviation: thisWidget.getValue()}] 
					};
					thisWidget.store = new dojo.data.ItemFileWriteStore({data: data});
					//createComboBoxData();
					
					thisWidget.getValue()
					thisWidget.touched = true;
				}
			}

			if (thisWidget.touched)	{
				// if the widget was updated it is "live" so show it
				thisWidget.setDisabled(false);
			} else {
				// if the widget wasn't updated it is empty, so don't show it
				thisWidget.store = null;
			}

			// connect as event handler to call the search when value changes
			this.listeners.push(dojo.connect(thisWidget, 'onChange', this, this.doSearch));
			debug("Handle: " + this.listeners[i]);
			thisWidget.touched = false;
		}

		// show the result count if available
		setResultCount(result.resultCount);
	}

	function setResultCount(count) {
		var resultElement = dojo.byId("resultCount");
		if (null != resultElement) {
			resultElement.innerHTML = count;
		}
	}

	this.quickSearch = function (nValues) {	
		// summary: Async search function that calls quickSearchResultsCallback when a response is received from server
		if (0 == nValues.length) {
			nValues.length++;
			nValues[0] = 0;
		}
		this.service.quickSearch(nValues).addCallback(this, this.quickSearchResultsCallback);
	}

	function createComboBoxData(refinements) {
		// summary: Helper function to create data for a ComboBox
		function createItem(name, abbreviation) {
			return {name: name, abbreviation: abbreviation }
		}
		var data = { identifier: "abbreviation", items: [createItem("Show all", "All")] }
		if (refinements) {
			for (var i = 0; i < refinements.length; i++) {
				data.items.push(createItem(refinements[i].name, refinements[i].id)); 
			}
		}
		return new dojo.data.ItemFileWriteStore({data: data});;
	}
	
	
	function debug() {
		// summary: A convenience method for writing debug message to the console
	    for (var i = 0; i < arguments.length; ++i) {
	    	try{
		    	console.debug("Endeca Search: " + arguments[i]);
		    }catch(error) {
		    	//do nothing
		    }
    	}
	}
	
	
	// On load do a search to populate the drop down boxes
	dojo.addOnLoad(this.doSearch.bind(this));
	
}

function init(){
//Added new initialization method as on slow connections the creation of the EndecaSearch object failed
//as the dojo library was not fully loaded.
	try{
		console.debug("Running init creating Endeca Search Object");
	}catch(error){
			
	}
	new EndecaSearch(['Recipient', 'Price', 'Gift finder category', 'Occasion'], {'Gift finder category': 'Category'},{'Category': 'Gift finder category'});
}
// Create the EndecaSearch object
dojo.addOnLoad(init);


