/*********************************************************
 * fader.js - Fader class for web sites                  *
 *                                                       *
 * This class handles dynamically fading-in and fading-  *
 * out elements on a page in a simple and straightfoward *
 * way.  It provides for launching an event after the    *
 * fade is complete, as well as controlling the speed    *
 * and ratio of the fade.  It should work equally well   *
 * in all browsers.                                      *
 *                                                       *
 * Usage:                                                *
 *   done  = function() { alert('All done!'); };         *
 *   fader = new Fader(document.getElementById("fid"),   *
 *                     'in', done);                      *
 *   fader.start();                                      *
 *********************************************************/

function Fader(element, direction, do_after, range, speed, step) {
  /*
   * ERROR MESSAGES
   */
  var e_missingelem, e_dirwrong, e_rangewrong, e_badspeed, e_badstep;

  e_missingelem = "Element missing - must be an Object";
  e_dirwrong    = "Direction is wrong, must be 'in' or 'out'";
  e_rangewrong  = "Range is bad - must be a two-elem Array of Numbers from " +
                  "0-100 (they must be different numbers)";
  e_badspeed    = "Speed is bad - must be a Number (milliseconds)";
  e_badstep     = "Step is bad - must be a Number from 0-100";

  this.ERR_MISSINGELEM = function() { return e_missingelem }
  this.ERR_DIRWRONG    = function() { return e_dirwrong    }
  this.ERR_RANGEWRONG  = function() { return e_rangewrong  }
  this.ERR_BADSPEED    = function() { return e_badspeed    }
  this.ERR_BADSTEP     = function() { return e_badstep     }

  /*
   * INITIALIZATION
   */

  var _this, _element, _running, _cur_fade, _range_start, _range_end;
  _this    = this;
  _element = element;
  _running = false;

  //
  // provide default args
  if (typeof range == 'undefined') range = [0, 100];
  if (typeof speed == 'undefined') speed = 3;
  if (typeof step  == 'undefined') step  = 8;
 
  //
  // verify args
  if (typeof element != 'object')             
    throw(e_missingelem);

  if (direction != 'in' && direction != 'out')
    throw(e_dirwrong);

  if (typeof range    != 'object' || range.length    != 2   ||
      typeof range[0] != 'number' || typeof range[1] != 'number')
    throw(e_rangewrong);

  if (range[0] > 100 || range[0] < 0 ||
      range[1] > 100 || range[1] < 0 || range[0] == range[1])
    throw(e_rangewrong);

  if (typeof speed != 'number')
    throw(e_badspeed);

  if (typeof step != 'number' || step < 0 || step > 100)
    throw(e_badstep);

  //
  // other initialization
  if (range[0] < range[1]) {
    if (direction == 'in') {
      _range_start = range[0];
      _range_end   = range[1];
    }
    else {
      _range_start = range[1];
      _range_end   = range[0];
    }
  }
  else {
    if (direction == 'in') {
      _range_start = range[1];
      _range_end   = range[0];
    }
    else {
      _range_start = range[0];
      _range_end   = range[1];
    }
  }

  /*
   * PRIVATE FUNCTIONS
   */

  var doFade;

  function doFade(fade) {
    if (!_running) return;
    var fade_next, anon;

    if (direction == 'in') {
      if (fade > _range_end) {
        fade = _range_end;
      }
      else {
        fade_next = fade + step;
      }
    }
    else {
      if (fade < _range_end) {
        fade = _range_end;
      }
      else {
        fade_next = fade - step;
      }
    }

    element.style.opacity = fade / 100;
    element.style.filter  = 'alpha(opacity=' + fade + ')';

    if (fade == _range_end) {
      if (do_after) do_after();
      _this.reset();
    }
    else {
      _cur_fade = fade_next;
      setTimeout(function() { doFade(fade_next) }, speed);
    }
  }

  /*
   * PUBLIC FUNCTIONS
   */
  this.reset = function() {
    _running  = false;
    _cur_fade = _range_start;
  }

  this.start = function() {
    if (_running) return;
    _running = true;

    if (typeof _cur_fade == 'undefined') _cur_fade = _range_start;
    doFade(_cur_fade);
  }

  this.stop = function() {
    _running = false;
  }
}
