Crossfade = function ( sElementID, sClassName, nDuration, nDelay ) {

  var aElement = document.getElementById( sElementID ).getElementsByTagName( 'div' );
  var nID      = 0;

  this.nAct = -1;
  this.aDiv = [];

  for (var i = 0; i < aElement.length; i++) {

    if (aElement[i].className && aElement[i].className == sClassName) {
      aElement[i].id = sElementID + '_' + nID++;
      this.aDiv.push( aElement[i].id );
    }
  }

  for (var i = 0; i < this.aDiv.length; i++) {

    document.getElementById( this.aDiv[i] ).style.opacity    = 0;
    document.getElementById( this.aDiv[i] ).style.position   = 'absolute';
    document.getElementById( this.aDiv[i] ).style.filter     = 'alpha( opacity = 0 )';
    document.getElementById( this.aDiv[i] ).style.visibility = 'hidden';
  }

  this.nDuration  = nDuration;
  this.nDelay     = nDelay;
  this.sElementID = null;

  this._newFade();
  this._initControl();
}

Crossfade.prototype._newFade = function ( sElementID ) {

  if (this.nID1) { window.clearInterval( this.nID1 ); }

  this.nOldAct = this.nAct;

  var nIndex = sElementID ? sElementID.split( '_' )[1] : null;
  if (nIndex != null) { this.nAct = nIndex; } else { this.nAct++; }

  if (!this.aDiv[this.nAct]) { this.nAct = 0; }

  if (this.nAct == this.nOldAct) { return false; }

  document.getElementById( this.aDiv[this.nAct] ).style.display    = 'block';
  document.getElementById( this.aDiv[this.nAct] ).style.visibility = 'visible';

  if (this.nAct > -1) { this._updateControl( 'reset', 'divControl_' + this.nAct ); }

  this.nInt  = 50;
  this.nTime = 0;

  var p = this;

  if (sElementID) {
    this.sElementID = sElementID;
    if (this.nID2) { window.clearInterval( this.nID2 ); }
  }

  this.nID2 = window.setInterval( function () { p._fade() }, this.nInt );
}

Crossfade.prototype._fade = function () {

  this.nTime += this.nInt;

  var ieop = Math.round( this._easeInOut( this.nTime, 0, 1, this.nDuration ) * 100 );
  var op = ieop / 100;

  document.getElementById( this.aDiv[this.nAct] ).style.opacity = op;
  document.getElementById( this.aDiv[this.nAct] ).style.filter  = 'alpha( opacity = ' + ieop + ' )';

  if (this.nOldAct > -1) {
    document.getElementById( this.aDiv[this.nOldAct] ).style.opacity = 1 - op;
    document.getElementById( this.aDiv[this.nOldAct] ).style.filter  = 'alpha( opacity = ' + (100 - ieop) + ' )';
  }

  if (this.nTime == this.nDuration) {

    window.clearInterval( this.nID2 );

    if (this.nOldAct > -1) {
      document.getElementById( this.aDiv[this.nOldAct] ).style.visibility = 'hidden';
    }

    if (this.sElementID == null) {
      var oCrossfade = this;
      this.nID1 = window.setInterval( function() { oCrossfade._newFade() }, this.nDelay );
    }

    this._updateControl( 'active', 'divControl_' + this.nAct );
  }
}

Crossfade.prototype._easeInOut = function ( t, b, c, d ) {
  return c / 2 * (1 - Math.cos( Math.PI * t / d )) + b;
}

Crossfade.prototype._initControl = function () {

  var oCrossfade = this;

  // if more than one item... 
  if (aItem.length) {

    // loop items
    for (var i = 0; i < aItem.length; i++) {

      // create element
      var divControl = document.createElement( 'div' ); 
 
      // assign class
      divControl.id        = 'divControl_' + i;
      divControl.className = 'control_0' + (i + 1) + '_' + (i ? '0' : '1');

      // assign onclick event
      divControl.onclick = function () {
        oCrossfade._newFade( this.id );
        oCrossfade._updateControl( 'active', this.id );
      }

      // append button  
      document.getElementById( 'divCrossFadeControl' ).appendChild( divControl );
    }
  }
}

Crossfade.prototype._updateControl = function ( sMode, sElementID ) {

  // assign values
  var oCrossfade = this;
  var nIndex = sElementID.split( '_' )[1];

  // load control array/parse control index
  var aElement = document.getElementById( 'divCrossFadeControl' ).getElementsByTagName( 'div' );

  // loop items...
  for (var i = 0; i < aElement.length; i++) {

    // assign class
    aElement[i].className = 'control_0' + (i + 1) + '_' + (i != nIndex ? '0' : '1');

    // if 'reset' mode...
    if (sMode == 'reset') {

      // remove onclick event
      aElement[i].onclick      = null;
      aElement[i].style.cursor = 'auto';

    } else {

      // assign onclick event
      aElement[i].onclick = (i != nIndex) ? function () { oCrossfade._updateControl( 'active', this.id ); oCrossfade._newFade( this.id ); } : null;
      aElement[i].style.cursor = 'pointer';
    }
  }
}

