var ElementTransition = Class.create({
  initialize: function(element, options) {
    this.element = $(element);
    this.controls = $(this.element.id + '-controls');
    this.options = $H({
      elements_selector: '.transition-element',
      effect: 'appear',
      delay: 8,
      duration: 2,
      even_height: false,
      condition: function() {return false;}
    }).merge(options);
    this.options.set('condition', this.options.get('condition').bind(this));

    this.elements = this.element.select(this.options.get('elements_selector'));
    if(this.options.get('even_height')) {
      var max_height = this.elements.max(function(e) {return e.getHeight()});
      this.elements.each(function(e) {e.setStyle({height: max_height + 'px'})});
      this.element.setStyle({height: max_height + 'px'});
    }
    this.index = 0;
    var delay = this.options.get('delay');
    if(delay) this.heartbeat = new PeriodicalExecuter(this.transition.bind(this), delay);

    if(this.controls) {
      this.controls.select('.trigger').each((function(trigger, index) {
        trigger.observe('click', (function() {
          if(this.heartbeat) {
            this.heartbeat.stop();
            this.heartbeat = null;
          }
          this.move_out();
          this.index = index;
          this.move_in();
        }).bind(this));
      }).bind(this));
    }
  },

  transition: function() {
    if(this.options.get('condition')()) return;
    this.move_out();
    this.index++;
    if(this.index >= this.elements.length) this.index = 0;
    this.move_in();
  },

  move_out: function() {
    this.elements[this.index].setStyle({zIndex: 0});
    Effect[Effect.PAIRS[this.options.get('effect')][1]](
      this.elements[this.index],
      {duration: this.options.get('duration')});
  },

  move_in: function() {
    if(this.in_effect) this.in_effect.cancel();
    this.elements[this.index].setStyle({zIndex: 1});
    if(this.controls) this.controlTrigger();
    this.in_effect = Effect[Effect.PAIRS[this.options.get('effect')][0]](
      this.elements[this.index], {
        duration: this.options.get('duration'),
        onFinish: (function() {this.in_effect = null}).bind(this)
      });
  },

  observing_mouse: false,
  last_x: 0,
  last_y: 0,
  over_element: function() {
    if(!this.observing_mouse) {
      this.observing_mouse = true;
      Event.observe(document.body, 'mouseover', (function(e) {
        this.last_x = e.pointerX();
        this.last_y = e.pointerY();
      }).bindAsEventListener(this));
    }
    return Position.within(this.element, this.last_x, this.last_y);
  },

  controlTrigger: function() {
    this.controls.select('.trigger').invoke('removeClassName', 'active');
    this.controls.down('.trigger', this.index).addClassName('active');
  }

});

