/******************************************************************************
 ** ui.choiceTree - use a series of dropdowns to progressively refine a choice.
 **
 ** Requires: jquery ui
 ** Example:

  var dropdowns = $( '*[name="size"]' )
               .add( '*[name="color"]' );

  $('fieldset.shoe-choice').choiceTree( {
    dropdowns: dropdowns,
    tree: {
      name: "size",
      options: [
        {
          text: "10.5",
          value: "Men's Size 10.5",
          name: "color",
          options : [
            { text : "Red", value : "red" },
            { text : "Blue", value : "blue" },
          ],
        },
        {
          text: "11.5",
          value: "Men's Size 11.5",
          name: "color",
          options : [
            { text : "Green", value : "green" },
            { text : "Blue", value : "blue" },
          ],
        },
      ],
    },
  } );

 *****************************************************************************/

(function ($) { // protect the namespace

$.widget( "ui.choiceTree", {

  _init: function () {

    var self = this;
    var state = $.extend(true, {}, this.options);
    self._setData('state', state);

    // When a dropdown changes, update all downstream dropdowns.

    $.each( state.dropdowns, function(i,elem) {
      state.choices.push(null);
      $( state.dropdowns[i] ).bind( 'change.'+self.widgetEventPrefix, function () {
        update_choices( state.dropdowns, state.tree, state.choices, i );
      } );
    } );

    // Populate the first dropdown.

    populate_dropdown( state.dropdowns[0], state.tree.options );
    update_choices( state.dropdowns, state.tree, state.choices, 0 );
  },

  destroy: function () {
    var self = this;
    var state = self._getData('state');
    state.dropdowns.unbind( 'change.'+self.widgetEventPrefix );
    $.widget.prototype.destroy.apply( self, arguments );
  }

} );

$.extend( $.ui.choiceTree, {
  version: "1.0",
  defaults: {
    dropdowns: $([]),   // A jquery collection of <select> elements.
    choices: [],        // The array of initial values for the dropdowns.
    tree: {}            // A choice tree with nested options.
  }
});


function update_choices( dropdowns, tree, choices, index ) {

  // Update the dropdown starting at index and all downstream dropdowns.

  if (index == null)
    index = 0;

  for (var i=index; i<dropdowns.length; i++) {

    var cur = dropdowns[i];
    var next = (i+1 < dropdowns.length) ? dropdowns[i+1] : null;

    choices[i] = null;

    // Account for the first header option ("-- Select --")

    if ($( cur ).val() != '')
      choices[i] = cur.selectedIndex - 1;

    // If there is a downstream dropdown,
    // either populate it, or clear and disable it.

    if (next) {
      if (choices[i] != null) {
        populate_dropdown( next, get_choice_branch( tree, choices, i+1 ) );
        $( next ).removeAttr('disabled');
        $( next ).trigger( 'enable.choiceTree' );
      }
      else {
        populate_dropdown( next, [] );
        $( next ).val('');
        $( next ).attr('disabled', 'disabled');
        $( next ).trigger( 'disable.choiceTree' );
      }
    }

  }

  return choices;
};


function get_choice_branch( tree, path, depth ) {
  var p = tree.options;

  // Descend into a choice tree.
  // Retrieve the options at the node specified by path.

  $.each( path, function(i,val) {
    if (i == depth)
      return false;
    if (val != null)
      p = p[val].options;
    else
      return false;
  } );

  return p;
};


function populate_dropdown( dropdown, options ) {

  // If the dropdown already has a header option as it's first,
  // retain it, otherwise use generic text.

  if (dropdown.length && $(dropdown.options[0]).val() == '') {
    dropdown.selectedIndex = 0;
    $( ':not(:first)', dropdown ).remove();
  }
  else {
    $( dropdown ).empty();
    dropdown.options.add( new Option( '-- Select --', '' ) );
  }

  // Populate the dropdown
  $.each( options, function(i,option) {
    dropdown.options.add( new Option( option.text, option.value ) );
  } );

  $( dropdown ).trigger( 'choiceTree.populate' );
};


})(jQuery); // function ($)

