// Copyright (c) 2006 Sébastien Gruhier (http://xilinus.com, http://itseb.com)
// 
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// VERSION 0.15
// Later changes by Tomasz Meka, www.gildia.pl


var Carousel = Class.create();
Carousel.prototype = {
  // Constructor
  initialize: function(carouselElemID, instanceName, options) {
    this.carouselElemID = carouselElemID;
    this.instanceName = instanceName;
    
    this.options = Object.extend({
      numVisible:           4,
      scrollInc:            3,
      animParameters:      {},
      animHandler:         null,
      queue:               "carousel",
      size:                0,
      prevElementID:       "prev-arrow",
      nextElementID:       "next-arrow",
      ajaxParameters:      null,
      numbers:             null,
      timeout:             15*1000 //15 seconds
      }, options || {});

      this.initDone = false;
      this.animRunning = "none";

      // add afterFinish options to animParameters (store old function)
      this.animAfterFinish = this.options.animParameters.afterFinish;
      Object.extend(this.options.animParameters, {afterFinish:  this._animDone.bind(this), queue: { position:'end', scope: this.options.queue }});
     
      // Event bindings
      this.prevScroll = this._prevScroll.bindAsEventListener(this);
      this.nextScroll = this._nextScroll.bindAsEventListener(this);

      Event.observe(this.options.prevElementID, "click", this.prevScroll);
      Event.observe(this.options.nextElementID, "click", this.nextScroll);

      //links to the potions of the carousel
      if (this.options.numbers) {
        this.numbers = $A($(this.options.numbers).getElementsByTagName('a'));
        for (var i = 0; i < this.numbers.length; i++) {
          this.numbers[i].onclick = this._numberClick.bindAsEventListener(this);
        }
      }
      
      // Get DOM UL element
      var carouselListClass = "carousel-list";
      this.carouselList = document.getElementsByClassName(carouselListClass, $(carouselElemID))[0]
      
      // Init data
      this._init();
      this.autoScroll(true);
  },

  stopAutoPlay: function() {
    if (this.timeoutId) {
      clearTimeout(this.timeoutId);
    }
  },

  autoScroll: function(firstTime) {
    if (!firstTime) {
      this._nextScroll();
    }
    this.timeoutId = setTimeout(this.instanceName + ".autoScroll()", this.options.timeout);
  },

  // Destructor
    destroy: function() {
     Event.stopObserving(this.options.prevElementID, "click", this.prevScroll);
     Event.stopObserving(this.options.nextElementID, "click", this.nextScroll);
   },
   
  /* "Private" functions */
  _init: function() {
    this.currentIndex = 0;
    
    this._getLiElementSize();
  },

  _numberClick: function(event) {
     this.stopAutoPlay();
     var idx = new Number(Event.element(event).innerHTML) - 1; //beacuse 1-element is 0-index
     var positionToJump = idx * this.options.scrollInc;
     var delta = this.currentIndex - positionToJump;
     return this._scroll(delta);
  },
  
  _prevScroll: function(event) {
    if (event) {
      this.stopAutoPlay();
    }
    if (this.animRunning != "none") {
      return;
    }

    if (this.currentIndex == 0) {
      return this._scroll(-this.options.size + this.options.numVisible);
    }

    var inc = this.options.scrollInc;

    if (this.currentIndex - inc < 0) {
      inc = this.currentIndex;
    }

    return this._scroll(inc)        
  },
  
  _nextScroll: function(event) { 
    if (event) {
      this.stopAutoPlay();
    }
    if (this.animRunning != "none") {
      return false;
    }
            
    // Check if there are enough elements in cache
    if (this.currentIndex + this.options.numVisible + this.options.scrollInc <= this.options.size)  {
      return this._scroll(-this.options.scrollInc);
    } else {
      return this._scroll(this.currentIndex); //scroll to the beginning
    }
  },
  
  _animDone: function(event){   
    if (this.options.animHandler)
      this.options.animHandler(this.carouselElemID, "after", this.animRunning);
     
    this.animRunning = "none";
    // Call animAfterFinish if exists
    if (this.animAfterFinish)
      this.animAfterFinish(event);
  },
  
  _scroll: function(delta, forceDisableNext) {
    this.animRunning = delta > 0 ? "prev" : "next";
    
    if (this.options.animHandler)
      this.options.animHandler(this.carouselElemID, "before", this.animRunning);

    new Effect.MoveBy(this.carouselList, 0, delta * this.elementSize, this.options.animParameters);

    if (this.numbers) {
      Element.removeClassName(this.numbers[this.currentIndex / this.options.scrollInc], "active");
    }
    this.currentIndex -= delta;
    if (this.numbers) {
      Element.addClassName(this.numbers[this.currentIndex / this.options.scrollInc], "active");
    }
    return false;
  },
  
  _getLiElementSize: function() {
    var li = $(this.carouselList.getElementsByTagName("li")[0]);
      this.elementSize = li.getDimensions().width + parseFloat(li.getStyle("margin-left")) + + parseFloat(li.getStyle("margin-right"));
  }
}
   



