var SelectableList = Class.create({
  initialize : function(element, options) {
    //optional parameters workaround
    options = options || {};

    //make self a reference to this
    var self = this;

    //set encapsulated elements
    if(!Object.isElement(element))
      throw new Error('Cannot instantiate SelectableList: ' + element + ' is not a DOM node.');
    this.elements = element.select('a');

    //set number of elements
    this.length = this.elements.length;

    //set allowMultipleSelection - default is false
    this.allowMultipleSelection = options.allowMultipleSelection || false;

    //set className - default is 'selectablelist-element'
    this.className = options.className || 'selectablelist-element';

    //set classNameSelected - default is 'selectablelist-element-selected'
    this.classNameSelected = options.classNameSelected || 'selectablelist-element-selected';

    //set onChange callback
    if(options.onChange && !Object.isFunction(options.onChange))
      throw new Error('Cannot instantiate SelectableList: ' + options.onChange + ' is not a function.');
    this.onChange = options.onChange;

    //set event handlers for each encapsulated element
    for(var i = 0; i < this.elements.length; i++) {
      //set prototype event handler
      this.elements[i].observe('click', function(event) {
        //cache current state
        var cache = self.getSelectedElements().inspect();

        //set clicked element selected
        self.setSelectedElements(Event.findElement(event, 'a'));

        //call onClick callback
        if(self.onClick)
          self.onClick(self);

        //call onChange callback if current state differs from cached state
        if(self.onChange && cache != self.getSelectedElements().inspect()) {
          self.onChange(self);
        }
      });

      //set standard event handler to avoid linking
      this.elements[i].onclick = function() {
        return false;
      };
    }
  },

  setSelectedElements : function(elements) {
    //make elements an array
    if(!Object.isArray(elements))
      elements = $A([elements]);

    for(var i = 0; i < elements.length; i++) {
      //consider only encapsulated elements
      if(this.elements.indexOf(elements[i]) == -1)
        continue;

      if(this.allowMultipleSelection) {
        if(elements[i].hasClassName(this.classNameSelected)) {
          elements[i].removeClassName(this.classNameSelected);
          elements[i].addClassName(this.className);
        }
        else {
          elements[i].removeClassName(this.className);
          elements[i].addClassName(this.classNameSelected);
        }
      }
      else {
        this.clearSelection();
        elements[i].removeClassName(this.className);
        elements[i].addClassName(this.classNameSelected);
      }
    }
  },

  getSelectedElements : function() {
    var elements = $A([]);
    for(var i = 0; i < this.elements.length; i++) {
      if(this.elements[i].hasClassName(this.classNameSelected))
        elements.push(this.elements[i]);
    }
    return elements;
  },

  getSelectedValues : function() {
    var values = $A([]);
    for(var i = 0; i < this.elements.length; i++) {
      if(this.elements[i].hasClassName(this.classNameSelected))
        values.push(this.elements[i].hash.substring(1));
    }
    return values;  
  },

  selectAll : function() {
    if(!this.allowMultipleSelection)
      return;

    for(var i = 0; i < this.elements.length; i++) {
      this.elements[i].removeClassName(this.className);
      this.elements[i].addClassName(this.classNameSelected);
    }
  },

  clearSelection : function() {
    for(var i = 0; i < this.elements.length; i++) {
      this.elements[i].removeClassName(this.classNameSelected);
      this.elements[i].addClassName(this.className);
    }
  }
});
