define("dijit/form/_ComboBoxMenuMixin", [
	"dojo/_base/array", // array.forEach
	"dojo/_base/declare", // declare
	"dojo/dom-attr", // domAttr.set
	"dojo/i18n", // i18n.getLocalization
	"dojo/_base/window", // win.doc.createTextNode
	"dojo/i18n!./nls/ComboBox"
], function(array, declare, domAttr, i18n, win){

// module:
//		dijit/form/_ComboBoxMenuMixin
// summary:
//		Focus-less menu for internal use in `dijit.form.ComboBox`

return declare( "dijit.form._ComboBoxMenuMixin", null, {
	// summary:
	//		Focus-less menu for internal use in `dijit.form.ComboBox`
	// tags:
	//		private

	// _messages: Object
	//		Holds "next" and "previous" text for paging buttons on drop down
	_messages: null,

	postMixInProperties: function(){
		this.inherited(arguments);
		this._messages = i18n.getLocalization("dijit.form", "ComboBox", this.lang);
	},

	buildRendering: function(){
		this.inherited(arguments);

		// fill in template with i18n messages
		this.previousButton.innerHTML = this._messages["previousMessage"];
		this.nextButton.innerHTML = this._messages["nextMessage"];
	},

	_setValueAttr: function(/*Object*/ value){
		this.value = value;
		this.onChange(value);
	},

	onClick: function(/*DomNode*/ node){
		if(node == this.previousButton){
			this._setSelectedAttr(null);
			this.onPage(-1);
		}else if(node == this.nextButton){
			this._setSelectedAttr(null);
			this.onPage(1);
		}else{
			this.onChange(node);
		}
	},

	// stubs
	onChange: function(/*Number*/ /*===== direction =====*/){
		// summary:
		//		Notifies ComboBox/FilteringSelect that user selected an option.
		// tags:
		//		callback
	},

	onPage: function(/*Number*/ /*===== direction =====*/){
		// summary:
		//		Notifies ComboBox/FilteringSelect that user clicked to advance to next/previous page.
		// tags:
		//		callback
	},

	onClose: function(){
		// summary:
		//		Callback from dijit.popup code to this widget, notifying it that it closed
		// tags:
		//		private
		this._setSelectedAttr(null);
	},

	_createOption: function(/*Object*/ item, labelFunc){
		// summary:
		//		Creates an option to appear on the popup menu subclassed by
		//		`dijit.form.FilteringSelect`.

		var menuitem = this._createMenuItem();
		var labelObject = labelFunc(item);
		if(labelObject.html){
			menuitem.innerHTML = labelObject.label;
		}else{
			menuitem.appendChild(
				win.doc.createTextNode(labelObject.label)
			);
		}
		// #3250: in blank options, assign a normal height
		if(menuitem.innerHTML == ""){
			menuitem.innerHTML = " ";	//  
		}

		// update menuitem.dir if BidiSupport was required
		this.applyTextDir(menuitem, (menuitem.innerText || menuitem.textContent || ""));

		menuitem.item=item;
		return menuitem;
	},

	createOptions: function(results, options, labelFunc){
		// summary:
		//		Fills in the items in the drop down list
		// results:
		//		Array of items
		// options:
		//		The options to the query function of the store
		//
		// labelFunc:
		//		Function to produce a label in the drop down list from a dojo.data item

		this.items = results;

		// display "Previous . . ." button
		this.previousButton.style.display = (options.start == 0) ? "none" : "";
		domAttr.set(this.previousButton, "id", this.id + "_prev");
		// create options using _createOption function defined by parent
		// ComboBox (or FilteringSelect) class
		// #2309:
		//		iterate over cache nondestructively
		array.forEach(results, function(item, i){
			var menuitem = this._createOption(item, labelFunc);
			menuitem.setAttribute("item", i);	// index to this.items; use indirection to avoid mem leak
			domAttr.set(menuitem, "id", this.id + i);
			this.nextButton.parentNode.insertBefore(menuitem, this.nextButton);
		}, this);
		// display "Next . . ." button
		var displayMore = false;
		// Try to determine if we should show 'more'...
		if(results.total && !results.total.then && results.total != -1){
			if((options.start + options.count) < results.total){
				displayMore = true;
			}else if((options.start + options.count) > results.total && options.count == results.length){
				// Weird return from a data store, where a start + count > maxOptions
				// implies maxOptions isn't really valid and we have to go into faking it.
				// And more or less assume more if count == results.length
				displayMore = true;
			}
		}else if(options.count == results.length){
			//Don't know the size, so we do the best we can based off count alone.
			//So, if we have an exact match to count, assume more.
			displayMore = true;
		}

		this.nextButton.style.display = displayMore ? "" : "none";
		domAttr.set(this.nextButton,"id", this.id + "_next");
	},

	clearResultList: function(){
		// summary:
		//		Clears the entries in the drop down list, but of course keeps the previous and next buttons.
		var container = this.containerNode;
		while(container.childNodes.length > 2){
			container.removeChild(container.childNodes[container.childNodes.length-2]);
		}
		this._setSelectedAttr(null);
	},

	highlightFirstOption: function(){
		// summary:
		//		Highlight the first real item in the list (not Previous Choices).
		this.selectFirstNode();
	},

	highlightLastOption: function(){
		// summary:
		//		Highlight the last real item in the list (not More Choices).
		this.selectLastNode();
	},

	selectFirstNode: function(){
		this.inherited(arguments);
		if(this.getHighlightedOption() == this.previousButton){
			this.selectNextNode();
		}
	},

	selectLastNode: function(){
		this.inherited(arguments);
		if(this.getHighlightedOption() == this.nextButton){
			this.selectPreviousNode();
		}
	},

	getHighlightedOption: function(){
		return this._getSelectedAttr();
	}
});

});