/*
  * --------------------------------------------------------------------
  * 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
  *
  * --------------------------------------------------------------------
  */


jQuery.fn.selectToUISlider = function(settings){
  var selects = jQuery(this);

  //accessible slider options
  var options = jQuery.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_'+jQuery(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: jQuery(this).attr('value'),
        text: jQuery(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 = jQuery(this).attr('label');
        groupedData[i].options = [];
        jQuery(this).find('option').each(function(){
          groupedData[i].options.push({text: jQuery(this).text(), value: jQuery(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 = jQuery(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 = jQuery('#' + thisHandle.attr('id').split('handle_')[1]);
  currSelect.find('option').not(ui.value).prop('selected', false);
  currSelect.find('option').eq(ui.value).prop('selected', true);

},
values: (function(){
  var values = [];
  selects.each(function(){
    values.push( jQuery(this).get(0).selectedIndex );
  });
  return values;
})()
};

  //slider options from settings
  options.sliderOptions = (settings) ? jQuery.extend(sliderOptions, settings.sliderOptions) : sliderOptions;

  //select element change event
  selects.bind('change keyup click', function(){
    var thisIndex = jQuery(this).get(0).selectedIndex;
    var thisHandle = jQuery('#handle_'+ jQuery(this).attr('id'));
    var handleIndex = thisHandle.data('handleNum');
    thisHandle.parents('.ui-slider:eq(0)').slider("values", handleIndex, thisIndex);
  });


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

  //CREATE HANDLES
  selects.each(function(i){
    var hidett = '';

  //associate label for ARIA
  var thisLabel = jQuery('label[for=' + jQuery(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;"';}
  jQuery('<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)');
    jQuery(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;
      jQuery(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)');
    jQuery(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){
    jQuery(this).css({
      'left': ((100 /( groups.length))*i).toFixed(2) + '%'
    });
  });


  //inject and return
  sliderComponent
  .insertAfter(jQuery(this).eq(this.length-1))
  .slider(options.sliderOptions)
  .attr('role','application')
  .find('.ui-slider-label')
  .each(function(){
    jQuery(this).css('marginLeft', -jQuery(this).width()/2);
  });

  //update tooltip arrow inner color
  sliderComponent.find('.ui-tooltip-pointer-down-inner').each(function(){
    var bWidth = jQuery('.ui-tooltip-pointer-down-inner').css('borderTopWidth');
    var bColor = jQuery(this).parents('.ui-slider-tooltip').css('backgroundColor');
    jQuery(this).css('border-top', bWidth+' solid '+bColor);
  });

  var values = sliderComponent.slider('values');

  if(isArray(values)){
    jQuery(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;
};
