 /*
 * jQuery UI selectmenu
 *
 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI
 */

(function($) {

$.widget("ui.selectmenu", {
    eventPrefix: "selectmenu",
	options: {
		transferClasses: true,
		style: 'popup', 
		width: null, 
		menuWidth: null,
		handleWidth: 26,
		//maxHeight: null,
		icons: null, 
		format: null,
		errorClass: 'ui-state-error ui-selectmenu-error'
    },
	
	_create: function() {
		var self = this, o = this.options;
		
		//quick array of button and menu id's
		this.ids = this._genId();
		
		//create menu button wrapper
		this.newelement = $('<a class="ui-selectmenu ui-widget ui-state-default ui-corner-all" id="'+this.ids[0]+'" href="#" aria-haspopup="true" aria-owns="'+this.ids[1]+'"></a>')
			.insertAfter(this.element);
		
		//transfer tabindex
		var tabindex = this.element.attr('tabindex') || '0'; 
		this.newelement.attr('tabindex', tabindex);
		
		
		//menu icon
		this.selectmenuIcon = $('<span class="ui-selectmenu-icon ui-icon"></span>')
			.prependTo(this.newelement)
			.addClass( (o.style == "popup")? 'ui-icon-triangle-2-n-s' : 'ui-icon-triangle-1-s' );	

			
		//make associated form label trigger focus
		$('label[for='+this.element.attr('id')+']')
			.attr('for', this.ids[0])
			.bind('click', function(){
				self.newelement.focus();
				return false;
			});	

		//click toggle for menu visibility
		this.newelement
		.bind('click', function(){
			self._closeOthers();
			self._toggle();
			return false;
		})
		.keydown(function(event){
			var ret = true;
			switch (event.keyCode) {
				case $.ui.keyCode.ENTER:
				case $.ui.keyCode.SPACE:
					ret = false;
					self._closeOthers();
					self._toggle();	
					break;
				case $.ui.keyCode.UP:
				case $.ui.keyCode.LEFT:
					ret = false;
					self.list.find('li.ui-selectmenu-item-selected').prev().trigger('mouseup');	
					break;
				case $.ui.keyCode.DOWN:
				case $.ui.keyCode.RIGHT:
					ret = false;
					self.list.find('li.ui-selectmenu-item-selected').next().trigger('mouseup');	
					break;	
				default:
				//	self._typeAhead(event.keyCode);
					break;	
			}
			return ret;
		})
		.bind('mouseover focus', function(){ $(this).addClass('ui-selectmenu-focus ui-state-hover'); })
		.bind('mouseout blur', function(){  
			$(this).removeClass('ui-selectmenu-focus ui-state-hover'); 
		});
		
		//document click closes menu
		//$(document).click(function(){
		//	self.close();
		//});

		//change event on original selectmenu
			this.element
				.click(function(){ this._refreshValue(); })
				.focus(function(){ this.newelement.focus(); });
		
		
		//create menu portion, append to body
		var cornerClass = (o.style == "dropdown")? " ui-corner-bottom" : " ui-corner-all"
		this.list = $('<ul class="ui-selectmenu-menu ui-widget ui-widget-content'+cornerClass+'" role="menu" aria-labelledby="'+this.ids[0]+'" id="'+this.ids[1]+'"></ul>').appendTo('body');				
		
		//get selectmenu element option data	
		var s_options = this._selectOptions();
		var activeClass = (self.options.style == "popup") ? " ui-state-active" : "";
		//write li's
		for(var i in s_options){
		
			var thisLi = $('<li><a href="#" tabindex="-1" role="option" aria-selected="false">'+ s_options[i].text +'</a></li>')
				.data('index',i)
				.addClass(s_options[i].classes)
				.data('optionClasses', s_options[i].classes)
				.mouseup(function(){
					self.value($(this).data('index'));
				})
				.bind('mouseover focus', function(){ 
					$(this).parent().find('.ui-selectmenu-item-selected').addClass(activeClass); 
					$(this).parent().find('.ui-selectmenu-item-focus').removeClass('ui-selectmenu-item-focus ui-state-hover'); 
					$(this).removeClass('ui-state-active').addClass('ui-selectmenu-item-focus ui-state-hover'); 
				})
				.bind('mouseout blur', function(){ 
					if($(this).is('.ui-selectmenu-item-selected')){ $(this).addClass(activeClass); }
					$(this).removeClass('ui-selectmenu-item-focus ui-state-hover'); 
				})
				.appendTo(this.list);
				
				//append icon if option is specified
				if(o.icons){
					for(var j in o.icons){
						if(thisLi.is(o.icons[j].find)){
							thisLi
								.data('optionClasses', s_options[i].classes + ' ui-selectmenu-hasIcon')
								.addClass('ui-selectmenu-hasIcon');
							var iconClass = o.icons[j].icon || "";
							
							thisLi
								.find('a:eq(0)')
								.prepend('<span class="ui-selectmenu-item-icon ui-icon '+iconClass + '"></span>');
						}
					}
				}
				
		}	
		
		//add corners to top and bottom menu items
		this.list.find('li:last').addClass("ui-corner-bottom");
		if(o.style == 'popup'){ 
			this.list.find('li:first').addClass("ui-corner-top");
		}
		
		//transfer classes to selectmenu and list
		if(o.transferClasses){
			var transferClasses = this.element.attr('class') || ''; 
			this.newelement.add(this.list).addClass(transferClasses);
		}
		
		//original selectmenu width
		var selectWidth = this.element.width();
		//set menu button width
		this.newelement.width( (o.width) ? o.width : selectWidth);
		//set menu width to either menuWidth option value, width option value, or select width 
		if(o.style == 'dropdown'){ this.list.width( (o.menuWidth) ? o.menuWidth : ((o.width) ? o.width : selectWidth)); }
		else { this.list.width( (o.menuWidth) ? o.menuWidth : ((o.width) ? o.width - o.handleWidth : selectWidth - o.handleWidth)); }	
		
		if(this.list.width() > this.newelement.width()){  }
		
		//set max height from option 
		if(o.maxHeight && o.maxHeight < this.list.height()){ this.list.height(o.maxHeight); }
		
		//transfer menu click to menu button
		this.list
		.click(function(){
			self.newelement.trigger('click');	// (should be abstracted out)
			return false;
		})
		.keydown(function(event){
			var ret = true;

			switch (event.keyCode) {
				case $.ui.keyCode.UP:
				case $.ui.keyCode.LEFT:
					ret = false;
					if($(event.target).parents('li:eq(0)').prev().size()>0){
						$(event.target).blur().parents('li:eq(0)').prev().find('a:eq(0)').focus();
					}	
					break;
				case $.ui.keyCode.DOWN:
				case $.ui.keyCode.RIGHT:
					ret = false;
					if($(event.target).parents('li:eq(0)').next().size()>0){
						$(event.target).blur().parents('li:eq(0)').next().find('a:eq(0)').focus();
					}	
					break;		
				case $.ui.keyCode.ENTER:
				case $.ui.keyCode.SPACE:
					ret = false;
					self.close();
					$(event.target).parents('li:eq(0)').trigger('mouseup');
					break;		
				case $.ui.keyCode.TAB:
					ret = true;
					self.close();
					break;	
				default:
					ret = false;
					self._typeAhead(event.keyCode);
					break;		
			}
			return ret;
		});
		
		//selectmenu style
		if(o.style == 'dropdown'){
			this.newelement
				.addClass("ui-selectmenu-dropdown");
			this.list
				.addClass("ui-selectmenu-menu-dropdown");	
		}
		else {
			this.newelement
				.addClass("ui-selectmenu-popup");
			this.list
				.addClass("ui-selectmenu-menu-popup");	
		}
		
		this.newelement.prepend('<span class="ui-selectmenu-status" id="ddlLabelSpan">'+ s_options[this._selectedIndex()].text +'</span>');
		
		//hide original selectmenu element
		this.element.hide();
		
		//update value 
		if(o.value){ this.value(o.value); }
		else { this._refreshValue(); }
		this._setOption("value", this._selectedIndex());
	},
	
	destroy: function() {
		this.newelement.remove();
		this.element.show();
		//unbind click on label, reset its for attr
		$('label[for='+this.newelement.attr('id')+']')
			.attr('for',this.element.attr('id'))
			.unbind('click');
	},
	
	_prevChar: ['',0],
	
	_typeAhead: function(code){
		var self = this;
		var C = String.fromCharCode(code);
		c = C.toLowerCase();
		var focusFound = false;
		this.list.find('li a').each(function(i){	
			if(!focusFound){
				var thisText = $(this).text();
				if( thisText.indexOf(C) == 0 || thisText.indexOf(c) == 0){
						if(self._prevChar[0] == C){
							if(self._prevChar[1] < i){
								focusFound = true;
								$(this).focus();
								self._prevChar[1] = i;
							}	
						}
						else{
							focusFound = true;
							$(this).focus();
							self._prevChar[1] = i;
						}	
				}
			}
		});
		this._prevChar[0] = C;
	},
	
	_closeOthers: function(){
		//this needs to be handled better
		$('.ui-selectmenu-open').not(this.list).removeClass('ui-selectmenu-open');
		$('.ui-select').not(this.newelement).trigger('blur');
	},
	
	_genId: function(type){
		var num = Math.round(Math.random() * 1000);
		return [this.element.attr('id') + '_' + 'button' + '_' + num, this.element.attr('id') + '_' + 'menu' + '_' + num];
	},
	
	open: function(){
		this._refreshPosition();
		this.newelement.addClass('ui-state-active');
		this.list
			.appendTo('body')
			.addClass('ui-selectmenu-open')
			.find('li:eq('+ this._selectedIndex() +') a').focus();	
			
		if(this.options.style == "dropdown"){ this.newelement.removeClass('ui-corner-all').addClass('ui-corner-top'); }	
		return this.element;	
	},
	
	close: function(){
		this.newelement.removeClass('ui-state-active');
		this.list.removeClass('ui-selectmenu-open');
		if(this.options.style == "dropdown"){ this.newelement.removeClass('ui-corner-top').addClass('ui-corner-all'); }
		this.newelement.focus();	
		return this.element;
	},
	
	_toggle: function(){
		if(this.list.is('.ui-selectmenu-open')){ this.close(); }
		else { this.open(); }
	},
	
	_formatText: function(text){
		var o = this.options;
		var newText = text;
		if(o.format){
			for(var i in o.format){
				newText = newText.replace(o.format[i].find, o.format[i].rep);
			}
		}
		return newText;
	},
	
	_selectedIndex: function(){
		return this.element[0].selectedIndex;
	},
	
	_selectOptions: function(){
		var opts = [];
		var self = this;
		this.element.find('option').each(function(i){
			opts.push({
				value: jQuery(this).attr('value'),
				text: self._formatText(jQuery(this).text()),
				selected: (i == self._selectedIndex()),
				classes: jQuery(this).attr('class')
			});
		});
		return opts;
	},

	_change: function(event, index) {
			var uiHash = {
			//value: this.value(),
			//option: "Test"
			index: this.value(),
	        option: $("option", this.element).get(index),
	        value: this.element[0].value
		};
		this._trigger("change", event, uiHash);
	},

	value: function(newValue) {
		if (arguments.length) {
			this._setOption("value", newValue);
			this.element[0].selectedIndex = newValue;
			this._refreshValue();
			this._refreshPosition();
			this._change(null, 0);
		}
		return this._value();
	},

	//_setOption: function(key, value) {
	//	$.widget.prototype._setOption.apply(this, arguments);
	//	this._refreshValue();

//	},

    _setData: function(key, value) {
		$.widget.prototype._setData.apply(this, arguments);
		this._refreshValue();

	},

	_value: function() {
		var val = this.options.value;
		return val;
	},
	

	_refreshValue: function() {
		var activeClass = (this.options.style == "popup") ? " ui-state-active" : "";
		this.list.find('.ui-selectmenu-item-selected').removeClass("ui-selectmenu-item-selected"+activeClass).find('a').attr('aria-selected', 'false');
		this.list.find('li').eq(this._selectedIndex()).addClass("ui-selectmenu-item-selected"+activeClass).find('a').attr('aria-selected', 'true');
		
		//toggle any class brought in from option
		var currentOptionClasses = this.newelement.data('optionClasses') ? this.newelement.data('optionClasses') : "";
		var newOptionClasses = this.list.find('li.ui-selectmenu-item-selected').data('optionClasses') ? this.list.find('li.ui-selectmenu-item-selected').data('optionClasses') : "";
		
		this.newelement
		.removeClass(currentOptionClasses)
		.data('optionClasses', newOptionClasses)
		.addClass( newOptionClasses )
		.find('.ui-selectmenu-status')
		.html( this.list.find('li').eq(this._selectedIndex()).find('a').html() );
	},
	
	_refreshPosition: function(offsetTop, offsetLeft){
		var topOffset = offsetTop || 0;
		var leftOffset = offsetLeft || 0;
		
		var menuHeight = this.list.height();
		var sHeight = this.list[0].scrollHeight;
		
		//set left value
		this.list.css('left', this.newelement.offset().left);
		
		//set top value
		this.list.find('li:lt('+this._selectedIndex()+')').each(function(){
			topOffset -= $(this).outerHeight();
		});
		
		var menuTop = this.newelement.offset().top;

		if(this.newelement.is('.ui-selectmenu-popup')){
			menuTop+=topOffset; 
			this.list.css('top', menuTop); 
		}	
		else { 
			menuTop += this.newelement.height();
			this.list.css('top', menuTop); 
		}
		
	}
});

$.extend($.ui.selectmenu, {
	version: "@VERSION"
});

})(jQuery);



