/*
 * --------------------------------------------------------------------
 * jQuery-Plugin - selectToUISlider - creates a UI slider component from a select element(s)
 * by Scott Jehl, scott@filamentgroup.com
 * http://www.filamentgroup.com
 * reference article: http://www.filamentgroup.com/lab/update_jquery_ui_16_slider_from_a_select_element/
 * demo page: http://www.filamentgroup.com/examples/slider_v2/index.html
 * 
 * Copyright (c) 2008 Filament Group, Inc
 * Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
 *
 * Usage Notes: please refer to our article above for documentation
 *  
 * --------------------------------------------------------------------
 */

(function($) {
    $.fn.selectToUISlider = function(settings){
    	var selects = $(this);
	
    	//accessible slider options
    	var options = $.extend({
    		labels: 3, //number of visible labels
    		tooltip: true, //show tooltips, boolean
    		tooltipSrc: 'text',//accepts 'value' as well
    		labelSrc: 'value',//accepts 'value' as well	,
    		sliderOptions: null
    	}, settings);


    	//handle ID attrs - selects each need IDs for handles to find them
    	var handleIds = (function(){
    		var tempArr = [];
    		selects.each(function(){
    			tempArr.push('handle_'+$(this).attr('id'));
    		});
    		return tempArr;
    	})();
	
    	//array of all option elements in select element (ignores optgroups)
    	var selectOptions = (function(){
    		var opts = [];
    		selects.eq(0).find('option').each(function(){
    			opts.push({
    				value: $(this).attr('value'),
    				text: $(this).text()
    			});
    		});
    		return opts;
    	})();
	
    	//array of opt groups if present
    	var groups = (function(){
    		if(selects.eq(0).find('optgroup').size()>0){
    			var groupedData = [];
    			selects.eq(0).find('optgroup').each(function(i){
    				groupedData[i] = {};
    				groupedData[i].label = $(this).attr('label');
    				groupedData[i].options = [];
    				$(this).find('option').each(function(){
    					groupedData[i].options.push({text: $(this).text(), value: $(this).attr('value')});
    				});
    			});
    			return groupedData;
    		}
    		else return null;
    	})();	
	
    	//check if obj is array
    	function isArray(obj) {
    		return obj.constructor == Array;
    	}
    	//return tooltip text from option index
    	function ttText(optIndex){
    		return (options.tooltipSrc == 'text') ? selectOptions[optIndex].text : selectOptions[optIndex].value;
    	}
	
    	//plugin-generated slider options (can be overridden)
    	var sliderOptions = {
    		step: 1,
    		min: 0,
    		orientation: 'horizontal',
    		max: selectOptions.length-1,
    		range: selects.length > 1,//multiple select elements = true
    		slide: function(e, ui) {//slide function
    				var thisHandle = $(ui.handle);
    				//handle feedback 
    				var textval = ttText(ui.value);
    				thisHandle
    					.attr('aria-valuetext', textval)
    					.attr('aria-valuenow', ui.value)
    					.find('.ui-slider-tooltip .ttContent')
    						.text( textval );

    				//control original select menu
    				var currSelect = $('#' + thisHandle.attr('id').split('handle_')[1]);
    				currSelect.find('option').eq(ui.value).attr('selected', 'selected');
    		},
    		values: (function(){
    			var values = [];
    			selects.each(function(){
    				values.push( $(this).get(0).selectedIndex );
    			});
    			return values;
    		})()
    	};
	
    	//slider options from settings
    	options.sliderOptions = (settings) ? $.extend(sliderOptions, settings.sliderOptions) : sliderOptions;
		
    	//select element change event	
    	selects.bind('change keyup click', function(){
    		var thisIndex = $(this).get(0).selectedIndex;
    		var thisHandle = $('#handle_'+ $(this).attr('id'));
    		var handleIndex = thisHandle.data('handleNum');
    		thisHandle.parents('.ui-slider:eq(0)').slider("values", handleIndex, thisIndex);
    	});
	

    	//create slider component div
    	var sliderComponent = $('<div></div>');

    	//CREATE HANDLES
    	selects.each(function(i){
    		var hidett = '';
		
    		//associate label for ARIA
    		var thisLabel = $('label[for=' + $(this).attr('id') +']');
    		//labelled by aria doesn't seem to work on slider handle. Using title attr as backup
    		var labelText = (thisLabel.size()>0) ? 'Slider control for '+ thisLabel.text()+'' : '';
    		var thisLabelId = thisLabel.attr('id') || thisLabel.attr('id', 'label_'+handleIds[i]).attr('id');
		
		
    		if( options.tooltip == false ){hidett = ' style="display: none;"';}
    		$('<a '+
    				'href="#" tabindex="0" '+
    				'id="'+handleIds[i]+'" '+
    				'class="ui-slider-handle" '+
    				'role="slider" '+
    				'aria-labelledby="'+thisLabelId+'" '+
    				'aria-valuemin="'+options.sliderOptions.min+'" '+
    				'aria-valuemax="'+options.sliderOptions.max+'" '+
    				'aria-valuenow="'+options.sliderOptions.values[i]+'" '+
    				'aria-valuetext="'+ttText(options.sliderOptions.values[i])+'" '+
    			'><span class="screenReaderContext">'+labelText+'</span>'+
    			'<span class="ui-slider-tooltip ui-widget-content ui-corner-all"'+ hidett +'><span class="ttContent"></span>'+
    				'<span class="ui-tooltip-pointer-down ui-widget-content"><span class="ui-tooltip-pointer-down-inner"></span></span>'+
    			'</span></a>')
    			.data('handleNum',i)
    			.appendTo(sliderComponent);
    	});
	
    	//CREATE SCALE AND TICS
	
    	//write dl if there are optgroups
    	if(groups) {
    		var inc = 0;
    		var scale = sliderComponent.append('<dl class="ui-slider-scale ui-helper-reset" role="presentation"></dl>').find('.ui-slider-scale:eq(0)');
    		$(groups).each(function(h){
    			scale.append('<dt style="width: '+ (100/groups.length).toFixed(2) +'%' +'; left:'+ (h/(groups.length-1) * 100).toFixed(2)  +'%' +'"><span>'+this.label+'</span></dt>');//class name becomes camelCased label
    			var groupOpts = this.options;
    			$(this.options).each(function(i){
    				var style = (inc == selectOptions.length-1 || inc == 0) ? 'style="display: none;"' : '' ;
    				var labelText = (options.labelSrc == 'text') ? groupOpts[i].text : groupOpts[i].value;
    				scale.append('<dd style="left:'+ leftVal(inc) +'"><span class="ui-slider-label">'+ labelText +'</span><span class="ui-slider-tic ui-widget-content"'+ style +'></span></dd>');
    				inc++;
    			});
    		});
    	}
    	//write ol
    	else {
    		var scale = sliderComponent.append('<ol class="ui-slider-scale ui-helper-reset" role="presentation"></ol>').find('.ui-slider-scale:eq(0)');
    		$(selectOptions).each(function(i){
    			var style = (i == selectOptions.length-1 || i == 0) ? 'style="display: none;"' : '' ;
    			var labelText = (options.labelSrc == 'text') ? this.text : this.value;
    			scale.append('<li style="left:'+ leftVal(i) +'"><span class="ui-slider-label">'+ labelText +'</span><span class="ui-slider-tic ui-widget-content"'+ style +'></span></li>');
    		});
    	}
	
    	function leftVal(i){
    		return (i/(selectOptions.length-1) * 100).toFixed(2)  +'%';
		
    	}
	

	
	
    	//show and hide labels depending on labels pref
    	//show the last one if there are more than 1 specified
    	if(options.labels > 1) sliderComponent.find('.ui-slider-scale li:last span.ui-slider-label, .ui-slider-scale dd:last span.ui-slider-label').addClass('ui-slider-label-show');

    	//set increment
    	var increm = Math.max(1, Math.round(selectOptions.length / options.labels));
    	//show em based on inc
    	for(var j=0; j<selectOptions.length; j+=increm){
    		if((selectOptions.length - j) > increm){//don't show if it's too close to the end label
    			sliderComponent.find('.ui-slider-scale li:eq('+ j +') span.ui-slider-label, .ui-slider-scale dd:eq('+ j +') span.ui-slider-label').addClass('ui-slider-label-show');
    		}
    	}

    	//style the dt's
    	sliderComponent.find('.ui-slider-scale dt').each(function(i){
    		$(this).css({
    			'left': ((100 /( groups.length))*i).toFixed(2) + '%'
    		});
    	});
	

    	//inject and return 
    	sliderComponent
    	.insertAfter($(this).eq(this.length-1))
    	.slider(options.sliderOptions)
    	.attr('role','application')
    	.find('.ui-slider-label')
    	.each(function(){
    		$(this).css('marginLeft', -$(this).width()/2);
    	});
	
    	//update tooltip arrow inner color
    	sliderComponent.find('.ui-tooltip-pointer-down-inner').each(function(){
    				var bWidth = $('.ui-tooltip-pointer-down-inner').css('borderTopWidth');
    				var bColor = $(this).parents('.ui-slider-tooltip').css('backgroundColor')
    				$(this).css('border-top', bWidth+' solid '+bColor);
    	});
	
    	var values = sliderComponent.slider('values');
	
    	if(isArray(values)){
    		$(values).each(function(i){
    			sliderComponent.find('.ui-slider-tooltip .ttContent').eq(i).text( ttText(this) );
    		});
    	}
    	else {
    		sliderComponent.find('.ui-slider-tooltip .ttContent').eq(0).text( ttText(values) );
    	}
	
    	return this;
    }
})(jQuery);
