﻿
/****************************************************
* Script: DarkCarousel
* Date: (October 15th 2008)
* Author: Dimitri Troncquo
* Contact: dimi3.t@gmail.com
* Description: 
* Creates a scrolling carousel
* of elements within a page.
*
* Requirements:
*  - Prototype framework
*  - script.aculo.us framework
*  - drk_carousel.css (or equivalent css)
****************************************************/

var DarkCarousel = Class.create({
  initialize: function(carouselContainer, elementType, elementWidth, numberShowing, trailingSize) {
    var initError;
    this._carouselContainer = $(carouselContainer);
    if(this._carouselContainer){        
        this._loadCarouselItems(elementType || "div");        
        if(this._scrollingElementPointers && this._scrollingElementPointers[0]){
            this._numberShowing = numberShowing || 1;
            if(this._scrollingElementPointers.length > numberShowing){
                this._currentIndex = 0;
                this._trailingSize = trailingSize || 10;
                this._moveBy = elementWidth || this._scrollingElementPointers[0].width || this._scrollingElementPointers[0].style.width || 0;                
                this._isMoving = false;
                this.lastOperation = 0;
            }else
                initError = "The number of carousel items must be greater than the number of items shown."
        }else
            initError = "One or more carousel items not found or invalid."
    }else
        initError = "Carousel container not found or invalid."
    if (initError)
        alert(initError);
        
  },
  _loadCarouselItems: function(elementType){
	this._scrollingElementPointers = [];
	for(var i=0; i<this._carouselContainer.childNodes.length;i++){
	if(this._carouselContainer.childNodes[i].nodeName.toLowerCase() == elementType.toLowerCase())
		this._scrollingElementPointers.push(this._carouselContainer.childNodes[i]);
	}
  },
  _move: function(direction){
    if(this._scrollingElementPointers && this._moveBy > 0 && !this._isMoving){ 
        this._regroupItems(direction);
        this._isMoving = true;
		
		function doSlide(currentInstance, backEffect){
			function doEffect(currentInstance){				
		        var moveEffect = new Effect.Move(currentInstance._carouselContainer, { x: (currentInstance._moveBy * direction) + (currentInstance._trailingSize * direction), y: 0 });
		        function resetSate(currentInstance){ 
		            setTimeout(function() {currentInstance._isMoving = false;}, moveEffect.options.duration*1000);
		        }
		        resetSate(currentInstance);
			} 
			setTimeout(function(){ doEffect(currentInstance)}, backEffect.options.duration*1000);
		}
		doSlide(this, new Effect.Move(this._carouselContainer, { x: -1 * (this._trailingSize * direction), y: 0, duration: 0.25 }));
        this.lastOperation = direction;
    }
  },
  _regroupItems: function(direction){
    var indexSet = false;

    if(direction < 0){
        if(this._currentIndex == 0)
            this._resetToOriginalSequence();    
        if(this._currentIndex - direction + this._numberShowing > this._scrollingElementPointers.length){            
            this._currentIndex = (this._currentIndex - direction > this._scrollingElementPointers.length-1)?0:this._currentIndex - direction;
            indexSet = true;
            if(this._currentIndex == 0 && this.lastOperation == direction)
                this._resetToOriginalSequence(true);
            else if(this.lastOperation == direction){
				var move = 0;
				while(move > direction){
					this._carouselContainer.appendChild(this._getFirstScrollingElement());
					
					this._carouselContainer.setStyle({
	                    left: (this._moveBy + parseFloat(this._carouselContainer.getStyle("left") || 0)).round() + "px"
	                });
					this._currentIndex--;
					move--;
				}                
            }
                 
        }
    }else if(direction > 0){
        this._currentIndex = (this._currentIndex - direction < 0 )?this._scrollingElementPointers.length-1:this._currentIndex - direction;
        indexSet = true;
        if(this._currentIndex == this._scrollingElementPointers.length-1 && this.lastOperation != 0 && this.lastOperation != direction)
            this._resetToOriginalSequence(true, true);
        else if(this.lastOperation == direction || this.lastOperation == 0){
			var move = 0;
			while(move < direction){
				this._carouselContainer.insertBefore(this._getLastScrollingElement(), this._getFirstScrollingElement());				
				this._carouselContainer.setStyle({
	                left: (-1 * this._moveBy) + parseFloat(this._carouselContainer.getStyle("left") || 0) + "px"
	            });
				this._currentIndex++;
				move++;
			}                           
        }            
    }  
    if(!indexSet)
        this._currentIndex -= direction; 
  },
  _getFirstScrollingElement: function(){
    for(var i=0;i<this._carouselContainer.childNodes.length;i++){
        if(this._scrollingElementPointers.indexOf(this._carouselContainer.childNodes[i]) >= 0)
            return this._carouselContainer.childNodes[i];        
    }
    return null;        
  },
  _getLastScrollingElement: function(){
    for(var i=this._carouselContainer.childNodes.length-1;i>=0;i--){
        if(this._scrollingElementPointers.indexOf(this._carouselContainer.childNodes[i]) >= 0)
            return this._carouselContainer.childNodes[i];
    }
    return null;        
  },
  _resetToOriginalSequence: function(keepLast, isBackwards){
    var ceiling = (keepLast)?this._scrollingElementPointers.length - 1 : this._scrollingElementPointers.length; 
    for(var i=0; i<ceiling;i++)
        this._carouselContainer.appendChild(this._scrollingElementPointers[i]);
    this._carouselContainer.setStyle({
        left: (isBackwards)?(-1 * this._moveBy)+"px":"0px"
    });    
  },
  moveLeft: function(steps){
    if(steps && steps > 3)
        alert("Moving by more then 3 steps is currently not supported.");
    else
        this._move(-1 * (steps || 1));
  },
  moveRight: function(steps){
    if(steps && steps > 3)
        alert("Moving by more then 3 steps is currently not supported.");
    else
        this._move(steps || 1);
  },
  reset: function(){
    this._carouselContainer.setStyle({ left: "0px" }); 
    this._scrollingElementPointers = this._carouselContainer = this._numberShowing = this._currentIndex = this._trailingSize = this._moveBy = this._isMoving = this.lastOperation = null;
  }  
});
