$.fn.customDropdown = function(settings) {
  var customDropdown = $.fn.customDropdown;
  var settings = $.extend({}, customDropdown.defaultSettings, settings);

  
  return $(this).each(function() {

    var selectElm = this;
    var listExpandedHeight = 0;

    var list = $('<ul />').attr({ // create the list of other options the user can select from 
          'class': 'sv-dropdown-expanded'
        }).bind('showList.sv', function() {
          customDropdown.showList.apply(this, [settings.speed]);
        }).bind('hideList.sv', function() {
          customDropdown.hideList.apply(this, [settings.speed]);
        }).click(function(e) { // bind the event to the container element
          if ( $(e.target).data('sv-customDropdown') ) { // check an element created for the custom dropdown was clicked
            $(selected).trigger('click'); // tigger the close for the list
            customDropdown.itemWasSelected.apply( selectElm, [$(e.target).data('sv-customDropdown').value] );
            $(selectElm).trigger('updateList.sv'); // rebuild the list of options
          };
        });
    
    var selected = $('<p/>').attr({ // create the element that will show the currently selected item
          'class': "sv-dropdown-selected"
        }).bind('updateSelected.sv', function() {
          customDropdown.updateSelected.apply(this, []);
        }).toggle(function() {
          $(list).trigger('showList.sv');
        }, function() {
          $(list).trigger('hideList.sv');
        });
    
    $(selectElm).bind('updateList.sv', function() { // update the custom custom element contents

      customDropdown.updateSelected.apply(selected, [$('option:selected', this).text(), settings.selectedPrefixText] ); // set selected text

      // update dropdown list
      $(list).empty();
      $('option:not(:selected)', this).each(function(index) {
        $(list).append( customDropdown.addToList(index, this, settings.listPrefixText) );
      });
    }).after(selected) // append the custom elements
      .after(list);
    
    $(selectElm).trigger('updateList.sv');
  });
};

$.fn.customDropdown.addToList = function(index, obj, prefixText) {
  prefixText = prefixText || '';
  return $('<li />').text( prefixText + $(obj).text() )
                    .data( 'sv-customDropdown', {value: $(obj).val()} );
};

$.fn.customDropdown.showList = function(speed) {
  $(this).stop()
         .slideDown(speed);
};

$.fn.customDropdown.hideList = function(speed) {
  $(this).stop()
         .slideUp(speed);
};

$.fn.customDropdown.updateSelected = function(text, prefixText) {
  prefixText = prefixText || '';
  $(this).text( prefixText + text );
};

$.fn.customDropdown.itemWasSelected = function(value) {
  $('option[value="' + value +'"]', this).attr('selected', 'selected');
  $(this).trigger('change');
};

$.fn.customDropdown.defaultSettings = {
  listContainer: '<ul/>',       // container for drop down list
  selectedContainer: '<p>/',    // container for currently selected item
  listAttributes: {
    'class': "sv-dropdown-expanded" // HTML attributes listContainer
  },
  selectedAttributes: {
    'class': "sv-dropdown-selected" // HTML attributes for selectedContainer
  },
  speed: 'fast',
  listPrefixText: null,
  selectedPrefixText: null
};