function CustomSelect( form_input ) {
  this.toString = function() { return '[CustomSelect]'; }

  this.options = [];
  this.values_panel = null;
  this.selectedIndex = 0;

  this.tmo = null;

  //  On crée un input hidden qui permettra de transférer la valeur sélectionnée quand le formulaire sera soumit
  this.hidden_input = CustomForm.createHidden( form_input.name, form_input.options[ 0 ].value );

  //  Gestionnaire d'évènement onClick de chaque substitut de la liste des valeurs
  this.onAnchorClick = function( e, selectedValueItem ) {
    DOMEvent.preventDefault( e );
    var eventTarget = DOMEvent.getTarget( e );

    this.hidePanel();

    this.selectedIndex = selectedValueItem.index;

    this.notify( 'changed' );
  }
  this.hidePanel = function() {
    if ( this.values_panel != null )
      this.values_panel.style.display = 'none';
    this.panel_hidden = true;
  }
  this.cleanTimeout = function() {
    if ( this.tmo == null )
      return true;
    clearTimeout( this.tmo );
    this.tmo = null;
  }
  this.startTimeout = function() {
    if ( this.tmo != null )
      return true;
    this.tmo = setTimeout( Delegate.create( this, 'hidePanel' ), 500 );
  }
  //  Gestionnaire d'évènement onClick pour le déclencheur
  this.onTriggerMouseOut = function( e ) {
    DOMEvent.preventDefault( e );
    this.startTimeout();
  }
  this.onTriggerMouseOver = function( e ) {
    DOMEvent.preventDefault( e );
    this.cleanTimeout();
  }
  this.onTriggerClick = function( e ) {
    DOMEvent.preventDefault( e );
    if ( this.panel_hidden ) {
      var selectedValueItem = this.options[ this.selectedIndex ];
      if ( isSet( selectedValueItem ) )
        selectedValueItem.substitute.className = 'selected';
      this.values_panel.style.display = 'block';
      this.panel_hidden = false;
    } else {
      this.hidePanel();
    }
  }
  //  Gestionnaire d'évènement onMouseOver pour la liste des valeurs
  this.onValuesMouseOut = function( e ) {
    DOMEvent.preventDefault( e );
    this.startTimeout();
  }
  this.onValuesMouseOver = function( e ) {
    DOMEvent.preventDefault( e );
    this.cleanTimeout();

    var selectedValueItem = this.options[ this.selectedIndex ];
    if ( isSet( selectedValueItem ) )
      selectedValueItem.substitute.className = '';
  }

  this.handleEvent = function( eventType, eventSource ) {
    if ( 'changed' == eventType ) {
      var selectedValueItem = this.options[ this.selectedIndex ];
      if ( isSet( selectedValueItem ) ) {
        if ( isSet( this.trigger.firstChild ) )
          this.trigger.replaceChild( document.createTextNode( selectedValueItem.text ), this.trigger.firstChild );
        else
          this.trigger.appendChild( document.createTextNode( selectedValueItem.text ) );
        this.hidden_input.value = selectedValueItem.value;
        selectedValueItem.substitute.className = 'selected';
      }
    }
  }

  this._createSubstitutes = function() {
    for( var i=0; i<this.options.length; i++ ) {
      var li = document.createElement( 'li' );
      var anchor = document.createElement( 'a' );
      anchor.appendChild( document.createTextNode( this.options[ i ].text ) );
      anchor.href = '';
      addListener( anchor, 'click', Delegate.create( this, 'onAnchorClick', this.options[ i ] ) );
      li.appendChild( anchor );
      this.values_panel.appendChild( li );

      this.options[ i ].substitute = anchor;
    }
  }

  this.setSelectedIndex = function( index ) {
    var selectedValueItem = this.options[ index ];
    if ( !isSet( selectedValueItem ) )
      return false;

    this.selectedIndex = index;
    this.notify( 'changed' );
  }

  //  Liste des valeurs
  this.values_panel = document.createElement( 'ul' );
  this.values_panel.className = 'customSelectValues';

  var options = form_input.options;
  for( var i=0; i<options.length; i++ ) {
    var tmp_value = options[ i ].value;
    if ( options[ i ].hasAttribute && !options[ i ].hasAttribute( 'value' ) )    //  Pour changer, IE ne connait pas cette fonction :\
      tmp_value = options[ i ].text;
    this.options[ i ] = { index: i, text: options[ i ].text, value: tmp_value };
  }
  this._createSubstitutes();

  addListener( this.values_panel, 'mouseover', Delegate.create( this, 'onValuesMouseOver' ) );
  addListener( this.values_panel, 'mouseout', Delegate.create( this, 'onValuesMouseOut' ) );
  this.hidePanel();

  //  Déclencheur affichant la valeur sélectionnée et switchant l'affichage de la liste des valeurs
  this.trigger = document.createElement( 'div' );
  this.trigger.className = 'customSelectTrigger';
  addListener( this.trigger, 'click', Delegate.create( this, 'onTriggerClick' ) );
  addListener( this.trigger, 'mouseover', Delegate.create( this, 'onTriggerMouseOver' ) );
  addListener( this.trigger, 'mouseout', Delegate.create( this, 'onTriggerMouseOut' ) );

  this.extend( new Listenable() );
  this.registerListener( 'changed', this );

  if ( isSet( form_input.selectedIndex ) )
    this.setSelectedIndex( form_input.selectedIndex );

  //  On ajoute les différents éléments de substitution
  var parentNode = form_input.parentNode;
  parentNode.insertBefore( this.hidden_input, form_input );
  parentNode.replaceChild( this.values_panel, form_input );
  parentNode.insertBefore( this.trigger, this.values_panel );
}
