if(typeof(Prototype) == "undefined") throw "This carousel requires Prototype to be loaded.";


var Carousel = Class.create(
{
  
  initialize: function(carousel, options)
  {
    this.options = Object.extend({
      circular: false, // TODO
      carouselContentClassName: 'carousel-content',
      visibleItems: 0
    }, options || {});
    
    if( !$(carousel) ) throw "Carousel container not found";
    this.carousel = $(carousel);
    this.carouselContainer = this.carousel.select('.'+this.options.carouselContentClassName)[0];
    
    
    var left = 0;
    var i = 0;
    this.carousel.select('li').each( function(element)
    {
      element.absolutize();
      element.setStyle({left: left+'px'});
      
      if( !element.classNames().include('carousel-item') )
      {
        element.addClassName('carousel-nr-'+(i+1));
        element.addClassName('carousel-item');
      }
      element.writeAttribute('data-carousel-pos', i);
      
      i += 1;
      
      left += element.measure('margin-box-width');
      if(!this.elementWidth) this.elementWidth = left;
    }.bind(this));
    
    
    if( this.options.visibleItems == 0 ) this.options.visibleItems = Math.round(this.carousel.getWidth() / this.elementWidth);
    
    
    document.location.hash.split('#').each( function(raw)
    {
      if( (data = raw.split(':')).size() == 2 && this.carousel == $(data[0]) ) this.toItem(parseInt(data[1]));
    }.bind(this));
    
    
    this.carousel.select('a').each( function(link)
    {
      if( link.classNames().include('carousel-to') ) $(link).on('click', function(event, target) { this.toItem(target.readAttribute('data-carousel-nr')); }.bind(this));
    }.bind(this));
    
    this.carousel.on('click', '.carousel-next', function(event, target) { this.next(); }.bind(this));
    this.carousel.on('click', '.carousel-prev', function(event, target) { this.prev(); }.bind(this));
  },
  
  
  next: function()
  {
    if( parseInt(this.carouselContainer.select('li').last().readAttribute('data-carousel-pos')) < this.options.visibleItems || this.functionalityBlock ) return false;
    
    this.functionalityBlock = true;
    var parallel = [];
    
    this.carouselContainer.select('li').each( function(element)
    {
      var left = parseInt(element.getStyle('left')) - this.elementWidth;
      parallel.push(new Effect.Morph(element, {style: 'left: ' + left + 'px;', sync: true}));
      
      this._updateElementPos(element, parseInt(element.readAttribute('data-carousel-pos')) - 1);
    }.bind(this));
    
    new Effect.Parallel(parallel, { afterFinish: function() { this.functionalityBlock = false;}.bind(this) });
  },
  
  
  prev: function()
  {
    if( parseInt(this.carouselContainer.select('li').first().readAttribute('data-carousel-pos')) >= 0 || this.functionalityBlock ) return false;
    
    this.functionalityBlock = true;
    var parallel = [];
    
    this.carouselContainer.select('li').each( function(element)
    {
      var left = parseInt(element.getStyle('left')) + this.elementWidth;
      parallel.push(new Effect.Morph(element, {style: 'left: ' + left + 'px;', sync: true}));
      
      this._updateElementPos(element, parseInt(element.readAttribute('data-carousel-pos')) + 1);
    }.bind(this));
    
    new Effect.Parallel(parallel, { afterFinish: function() { this.functionalityBlock = false; }.bind(this) });
  },
  
  
  toItem: function(nr)
  {
    if( this.functionalityBlock ) return false;
    
    this.functionalityBlock = true;
    var parallel = [];
    
    elementsCount = this.carouselContainer.select('.carousel-item').size();
    targetElement = this.carouselContainer.down('.carousel-nr-'+nr);
    maxSlide = this.carouselContainer.select('.carousel-item')[ (elementsCount - this.options.visibleItems) ];
    
    for(var i = elementsCount; i > (elementsCount - this.options.visibleItems + 1); i--)
    {
      if( this.carouselContainer.select('.carousel-item')[i-1] == targetElement ) 
      {
        targetElement = maxSlide;
        break;
      }
    }
    
    
    
    diff = 0 - parseInt(targetElement.readAttribute('data-carousel-pos'));

    this.carouselContainer.select('li').each( function(element)
    {
      var left = parseInt(element.getStyle('left')) + (this.elementWidth * diff);
      parallel.push(new Effect.Morph(element, {style: 'left: ' + left + 'px;', sync: true}));
      
      this._updateElementPos(element, parseInt(element.readAttribute('data-carousel-pos')) + diff);
    }.bind(this));
    
    new Effect.Parallel(parallel, { afterFinish: function() { this.functionalityBlock = false; }.bind(this) });
  },
  
  
  _updateElementPos: function(element, new_pos)
  {
    element.writeAttribute('data-carousel-pos', new_pos);
  }
  
});




