function ImageMenu() {
  this.initialize(arguments[0] || null, arguments[1] || null);
};

ImageMenu.prototype.setOptions = function(options) {
  this.options = {};
  this.options.openWidth = options.openWidth || 260;
  this.options.transition = options.transition || function(pos) { return 1 - Math.pow(1 - pos, 2) };
  this.options.duration = options.duration || 700;
  this.options.open = options.open || null;
  this.options.border = options.border || 0;
  this.options.fps = 50;
};

Array.prototype.forEach = function (fn, bind) {
  for (var i = 0, j = this.length; i < j; i++) fn.call(bind, this[i], i, this)
}

ImageMenu.prototype.initialize = function(element, options) {
  this.setOptions(options);

  var elParent = document.getElementById(element);

  if (!elParent) return null;
  this.elements = [];
  var elIdx = 0;
  for (var idx = 0; idx < elParent.childNodes.length; idx++) {
    var elLi = elParent.childNodes[idx];
    if (elLi.tagName == 'LI') { this.elements.push(elLi); }
  }

  this.widths = {};
  this.widths.closed = this.elements[0].offsetWidth;
  this.widths.openSelected = this.options.openWidth;
  this.widths.openOthers = Math.round(((this.widths.closed * this.elements.length) - (this.widths.openSelected + this.options.border)) / (this.elements.length - 1))

  this.elements.iterate(function(el, i) {
    var obj = this;

    var FMouseOver = function(evt) {
      var event = new ajax.events.Event(evt);
      if (event.relatedTarget == this || ajax.layout.elementHasChild(this, event.relatedTarget)) return;
      event.stop();
      obj.effectReset(i);
    };
    ajax.events.register(el, 'mouseover', function(e) { FMouseOver.call(el, e || event); });

    var FMouseOut = function(evt) {
      var event = new ajax.events.Event(evt);
      if (event.relatedTarget == this || ajax.layout.elementHasChild(this, event.relatedTarget)) return;
      event.stop();
      obj.effectReset(obj.options.open);
    };
    ajax.events.register(el, 'mouseout', function(e) { FMouseOut.call(el, e || event); });
  }
			, this);

  if (this.options.open) {
    if (typeof (this.options.open) == typeof (1)) {
      this.effectReset(this.options.open);
    } else {
      for (var i = 0; i < this.elements.length; i++) {
        var el = this.elements(i);
        if (el.id == this.options.open) {
          this.effectReset(parseInt(i, 10));
        }
      }
    }
  }
};

ImageMenu.prototype.effectStep = function() {
  var time = new Date().getTime();
  if (time < this.time + this.options.duration) {
    this.delta = this.options.transition((time - this.time) / this.options.duration);
    this.effectSetNow();
    this.effectIncrease();
  } else {
    this.effectStop(true);
    this.effectSet(this.to);
    if (this.options.onComplete) this.options.onComplete(this);
  }
};
ImageMenu.prototype.effectSetNow = function () {
  for (var i=0; i<this.elements.length; i++) {
    this.now[i] = (this.to[i] - this.from[i]) * this.delta + this.from[i];
  }
};
ImageMenu.prototype.effectSet = function(to) {
  for (var i=0; i<to.length; i++) {
    this.elements[i].style.width = to[i] + 'px';
    this.now[i] = to[i];
  }
  this.effectIncrease();
};
ImageMenu.prototype.effectStart = function(widths) {
  this.now = [];
  this.from = [];
  this.to = [];
  for (var i=0; i<this.elements.length; i++) {
    this.to[i] = widths[i];
    this.from[i] = this.elements[i].offsetWidth;
  }

  this.effectStop();
  this.change = this.to - this.from;
  this.time = new Date().getTime();
  this.effectStep();
  var thisObj = this;
  this.timer = setInterval(function() { thisObj.effectStep(); }, Math.round(1000 / this.options.fps));
  if (this.options.onStart) this.options.onStart(this);
};
ImageMenu.prototype.effectIncrease = function () {
  for (var i=0; i<this.now.length; i++) {
    this.elements[i].style.width = this.now[i] + 'px';
  }
};
ImageMenu.prototype.effectStop = function(end) {
  if (!this.timer) return this;
  clearInterval(this.timer);
  this.timer = null;
  if (!end && this.options.onCancel) this.options.onCancel(this);
};
ImageMenu.prototype.effectReset = function(num) {
  var width;
  if (typeof(num) == typeof(1)) {
    width = this.widths.openOthers;
    if (num + 1 == this.elements.length) {
      width += this.options.border;
    }
  } else {
    width = this.widths.closed;
  }

  var widths = [];
  for (var i=0; i<this.elements.length; i++) {
    widths[i] = width;
  }

  if (typeof (num) == typeof (1)) {
    widths[num] = this.widths.openSelected;
  }
  
  this.effectStart(widths);
};

