/*
 * GroupingList controls three select lists.  One is the 'to' select where selected options are displayed
 * and can be sorted.  Another is the 'from' select that shows options of the current type, and the third
 * is the 'type' select that chooses the type of options shown in the 'from' select.
 * The type function is a function that take a select list Option object as a parameter and computes the
 * type of the option from it.
 */
function GroupingList( to, from, type, typeFunction )
{
  this.to = to;
  this.from = from;
  this.type = type;
  this.typeFunction = typeFunction;

  this.optionSets = new Object();
  this.optionTypeState = null;
  this.sortLists = new Object();
}

GroupingList.prototype.addOption = function( text, value, selected, toolTip )
{
  var option = new Option(text,value);
  option.title = toolTip;
  var type = this.typeFunction( option );

  if ( ! this.optionTypeState )
    this.optionTypeState = type;
  var oset = this.optionSets[ type ];
  if ( ! oset )
  {
    oset = new Array();
    this.optionSets[ type ] = oset;
    var newOption = new Option(type, type);
    newOption.title = toolTip;
    this.type.options[this.type.options.length] = newOption;
  }
  oset[oset.length] = option;

  var sortList = this.sortLists[type];
  if ( sortList == null )
  {
    sortList = new Array();
    this.sortLists[ type ] = sortList;
  }
  sortList[sortList.length] = option;

  if ( selected )
  {
    var index = this.getOptionIndex(this.to.options, option.value);
    if (index != null)
      this.to.options[index].text = option.text;
  }
  else if ((! selected) && (type == this.optionTypeState))
  {
    var newOption = new Option(option.text, option.value);
    newOption.title = toolTip;
    this.from.options[this.from.options.length] = newOption;
  }
}

GroupingList.prototype.getOptionIndex = function( options, value )
{
  for ( var i=0; i < options.length; i++ )
  {
    if ( options[i].value == value )
      return i;
  }

  return null;
}

GroupingList.prototype.addContent = function( )
{
  for ( var i=0; i < this.from.options.length; i++ )
  {
    if ( this.from.options[i].selected )
    {
      var newOption = new Option(this.from.options[i].text, this.from.options[i].value);
      newOption.title = this.from.options[i].title;
      this.to.options[this.to.options.length] = newOption;
      this.from.options[i--] = null;
    }
  }
}

GroupingList.prototype.removeContent = function( )
{
  for ( var i=0; i < this.to.options.length; i++ )
  {
    if ( this.to.options[i].selected )
    {
      var type = this.typeFunction( this.to.options[i] );
      var opts = this.optionSets[type];
      var newOption = new Option(this.to.options[i].text, this.to.options[i].value);
      newOption.title = this.to.options[i].title;
      opts[opts.length] = newOption;

      if ( type == this.optionTypeState )
      {
        var newOption = new Option(this.to.options[i].text, this.to.options[i].value);
        newOption.title = this.to.options[i].title;
        this.from.options[this.from.options.length] = newOption;
      }
      this.to.options[i--] = null;
    }
  }
  this.sortFromList();
}

GroupingList.prototype.changeOptionTypes = function( type )
{
  var options = this.optionSets[ type ];
  this.from.options.length = 0;
  for ( var i=0; i < options.length; i++ )
  {
    var option = new Option(options[i].text, options[i].value, false, options[i].selected);
    option.title = options[i].title;
    if (! this.isChosen(option))
      this.from.options[this.from.options.length] = option;
  }

  this.optionTypeState = type;
  this.sortFromList();
}

GroupingList.prototype.isChosen = function( option )
{
  for ( var i=0; i < this.to.options.length; i++ )
  {
    if (this.to.options[i].value == option.value)
      return true;
  }

  return false;
}


GroupingList.prototype.moveUp = function( )
{
  if (( this.to.options.length == 0 ) || ( this.to.options[0].selected )) return;

  for ( var i=1; i < this.to.options.length; i++ )
  {
    if ( this.to.options[i].selected )
      GroupingList.swapOptions( this.to.options[i-1], this.to.options[i] );
  }
}

GroupingList.prototype.moveDown = function( )
{
  if (( this.to.options.length == 0 ) || ( this.to.options[this.to.options.length - 1].selected )) return;

  for ( var i=this.to.options.length - 2; i >= 0 ; i-- )
  {
    if ( this.to.options[i].selected )
      GroupingList.swapOptions( this.to.options[i+1], this.to.options[i] );
  }
}

GroupingList.swapOptions = function( o1, o2 )
{
  var tmpText = o1.text;
  var tmpValue = o1.value;
  var tmpSelected = o1.selected;
  var tmpTitle = o1.title;
  alert('o1.title: ' + o1.title + ', o2.title: ' + o2.title);
  o1.text = o2.text;
  o1.value = o2.value;
  o1.selected = o2.selected;
  o1.title = o2.title;
  o2.text = tmpText;
  o2.value = tmpValue;
  o2.selected = tmpSelected;
  o2.title = tmpTitle;
}

GroupingList.prototype.sortFromList = function()
{
  var sortList = this.sortLists[this.optionTypeState];
  // copy option values into map
  var options = new Object();
  for (var i=0; i<this.from.options.length; i++)
  {
    options[this.from.options[i].value] = new Object();
  }

  // copy sort list options into select list if their value was available in original select list values
  this.from.options.length = 0;
  for (var i=0; i<sortList.length; i++)
  {
    if ( options[sortList[i].value] )
    {
      var newOption = new Option(sortList[i].text,sortList[i].value);
      newOption.title = sortList[i].title;
      this.from.options[this.from.options.length] = newOption;
    }
  }
}
