SliderBox = Class.create();
SliderBox.prototype = {
  initialize: function(element, options) {
    options = (options || {});
    this.element = $(element);
    this.width = options.width || 200;
    this.height = options.height || 120;
    this.delay = options.delay || 7;
    this.direction = options.direction || 'right';
    this.currentItem = null;
    this.paused = false;

    this.element.setStyle({
      position: 'relative',
      overflow: 'hidden',
      width: this.width + 'px',
      height: this.height + 'px'
    });
    
    this.setupItems(this.element.immediateDescendants());
    this.play();
  },
  
  getPlayerFor: function(element) {
    elements = element.immediateDescendants();
    if(elements.length == 1 && elements[0].tagName == 'EMBED') {
      return elements[0];
    } else {
      return null;
    }
  },
  
  setupItems: function(elements) {
    sliderbox = this;
    sliderbox.items = elements.map(function(element) {
      element = $(element);
      element.setStyle({
        position: 'absolute',
        overflow: 'hidden',
        width: sliderbox.width+'px',
        height: sliderbox.height+'px',
        left: -sliderbox.width+'px'
      });
      
      if(sliderbox.getPlayerFor(element)) {
        return new SliderVideoItem(element, sliderbox);
      } else {
        return new SliderItem(element, sliderbox);
      }
    });
  },

  resetAllItemsExcept: function(except) {
    sliderbox = this;
    
    sliderbox.items.without(except).each(function(item) {
      item.reset();
    });
  },
  
  transitionTo: function(item, options) {
    options = (options || {});
    sliderbox = this;
    width = this.width;
    from = this.currentItem;
    direction = options['direction'] || 'right';

    // Don't do anything if we're transitioning to the same item
    if(from && item == from) { return; }
    
    // pre-transition
    if(from) { from.preOut(direction); }
    item.preIn(direction);
    
    // transition
    if(from) { from.doOut(direction); }
    item.doIn(direction);
    
    // post-transition
    new Effect.Event({afterFinish:function() {
      if(from) { from.postOut(direction); }
      item.postIn(direction);
    }, queue: 'end'});
    
    // clean up
    new Effect.Event({afterFinish:function() {
      sliderbox.resetAllItemsExcept(item);
    }, queue: 'end'});
    
    this.currentItem = item;
  },
  
  getNextItem: function() {
    nextIndex = this.items.indexOf(this.currentItem) + 1;
    if(nextIndex >= this.items.length) {
      return this.items[0];
    } else {
      return this.items[nextIndex];
    }
  },
  
  getPreviousItem: function() {
    previousIndex = this.items.indexOf(this.currentItem) - 1;
    if(previousIndex < 0) {
      return this.items.last();
    } else {
      return this.items[previousIndex];
    }
  },
  
  next: function() {
    if(this.items.length > 0) {
      this.resetTimer();
      this.transitionTo(this.getNextItem(), {direction: this.direction});
    }
  },
  
  previous: function() {
    if(this.items.length > 0) {
      this.resetTimer();
      this.transitionTo(this.getPreviousItem(), {direction: this.oppositeDirection()});
    }
  },
  
  pause: function() {
    this.paused = true;
    if(this.automaticAdvance) {
      this.automaticAdvance.stop();
      this.automaticAdvance = null;
    }
  },
  
  play: function() {
    this.pause();
    this.next();
    this.paused = false;
    if(this.delay && this.items.length > 1) {
      this.__createAutomaticAdvance();
    }
  },
  
  resetTimer: function() {
    sliderbox = this;
    if(this.automaticAdvance) {
      this.automaticAdvance.stop();
      this.automaticAdvance = null;
      this.__createAutomaticAdvance();
    }
  },
  
  __createAutomaticAdvance: function() {
    sliderbox = this;
    this.automaticAdvance = new PeriodicalExecuter(function() {
      if(!(sliderbox.currentItem && sliderbox.currentItem.hold && sliderbox.currentItem.hold())) {
        sliderbox.next();
      }
    }, Math.max(2, this.delay));
  },
  
  oppositeDirection: function() {
    switch(this.direction) {
    case 'right': return 'left';
    case 'left':  return 'right';
    case 'down':  return 'up';
    case 'up':    return 'down';
    }
  }
};

SliderItem = Class.create();
SliderItem.prototype = {
  initialize: function(element, sliderbox, options) {
    this.element = $(element);
    this.sliderbox = sliderbox;
  },
  
  reset: function() {
    this.element.setStyle({
      left: -sliderbox.width+'px',
      top: '0px'
    });
  },
  
  preIn:   function(direction) {
    switch(direction) {
    case 'right':
      this.element.setStyle({left: -this.sliderbox.width+'px'}); break;
    case 'left':
      this.element.setStyle({left: this.sliderbox.width+'px'}); break;
    case 'down':
      this.element.setStyle({left: '0px', top: -this.sliderbox.height+'px'}); break;
    case 'up':
      this.element.setStyle({left: '0px', top: this.sliderbox.height+'px'}); break;
    case 'none':
      this.element.hide(); this.element.setStyle({left: '0px', top: '0px'}); break;
    }
  },
  
  doIn:    function(direction) {
    new Effect.Appear(this.element, {duration: 1});
    switch(direction) {
    case 'right':
      new Effect.Move(this.element, {x:this.sliderbox.width, duration: 1}); break;
    case 'left':
      new Effect.Move(this.element, {x:-this.sliderbox.width, duration: 1}); break;
    case 'down':
      new Effect.Move(this.element, {y:this.sliderbox.height, duration: 1}); break;
    case 'up':
      new Effect.Move(this.element, {y:-this.sliderbox.height, duration: 1}); break;
    }
  },
  
  postIn:  function(direction) {
    
  },
  
  preOut:  function(direction) {
    this.element.setStyle({left: '0px', top: '0px'});
  },
  
  doOut:   function(direction) {
    new Effect.Fade(this.element, {duration:1});
    switch(direction) {
    case 'right':
      new Effect.Move(this.element, {x: this.sliderbox.width, duration: 1}); break;
    case 'left':
      new Effect.Move(this.element, {x: -this.sliderbox.width, duration: 1}); break;
    case 'down':
      new Effect.Move(this.element, {y: this.sliderbox.height, duration: 1}); break;
    case 'up':
      new Effect.Move(this.element, {y: -this.sliderbox.height, duration: 1}); break;
    }
  },
  
  postOut: function(direction) {
    this.reset();
  }
};

SliderVideoItem = Class.create();
Object.extend(Object.extend(SliderVideoItem.prototype, SliderItem.prototype), {
  initialize: function(element, sliderbox, options) {
    this.element = $(element);
    this.sliderbox = sliderbox;
    
    me = this;
    player = this.player();
    player.playerUpdate = function(type, param1, param2) {
        me.updateFromPlayer(type, param1, param2);
    }
  },
  
  player: function() {
    return this.element.down('embed', 0);
  },
  
  hold: function() {
    return true;
  },

  send: function(message, param) {
    this.__send(message, param, 8);
  },
  
  __send: function(message, param, triesleft) {
    if(this.player().sendEvent) {
      this.player().sendEvent(message, param);
    } else if(triesleft > 0) {
      me = this;
      setTimeout(function() { me.__send(message, param, triesleft - 1); }, 300);
    }
  },
  
  updateFromPlayer: function(type, param1, param2) {
    if(type == 'time' && Math.round(param1) > 0 && Math.round(param2) == 0) {
      this.onPlayerStop();
    }
  },
  
  onPlayerStop: function() {
    if(this.sliderbox.currentItem == this && !sliderbox.paused) {
      this.sliderbox.next();
    }
  },

  reset: function() {
    this.send('stop');
    this.element.setStyle({
      left: -sliderbox.width+'px',
      top: '0px'
    });
    this.element.hide();
  },

  preIn:   function(direction) {

  },
  
  doIn:    function(direction) {

  },
  
  postIn:  function(direction) {
    this.element.setStyle({
      left: '0px',
      top: '0px'
    });
    this.element.show();
    this.send('playpause');
  },

  preOut:  function(direction) {
    this.send('stop');
  },
  
  doOut:   function(direction) {
    this.element.hide();
  },
  
  postOut: function(direction) {
    this.reset();
  }
  
});

