/**
 * Image rotator in carousel like movement
 * Even number positions are on left, odd number postions are on right
 * e.g.
 *       4   5
 *        2 3
 *         1
 */
var Carousel = Class.create();
var carousels = [];

Carousel.prototype = {
    images : [],
    currentIndex : 0,
    timer : null,
    containerWidth : 0,
    imageContainerWidth : 0,
    isRunning : false,
    inTransition : false,
    currentThumbnailPage : 1,
    dimensions : {},
    positions : [],
    maxLeft : 0,
    maxRight : 0,
    dragging : false,
    doText : true,
    
    initialize : function(options) {
        this.options = Object.extend( {
            interval : 5, //interval between changing images
            mainContainer : 'Carousel',
            textContainer : 'CarouselText',
            testing : false,
            imageSelectedClass : 'selected',
            textClass : 'carousel-text',
            maxImages : 8,
            imageOffset : 0.3,
            imageDegradation : 0.6,
            transitionDuration : 0.4,
            transitionDuration2 : 0.4,
            enableDragging : false,
            useOpacity : false
        }, options || {});

        carousels[this.options.mainContainer] = this;

        this._setup();
    },


    move : function() {
        var nextIndex = this.currentIndex + 1;
        if (nextIndex >= this.images.length) {
            nextIndex = 0;
        }
        this.changeImage(nextIndex);
    },

    changeImage : function(nextIndex, event) {
       
        if (this.dragging || this.inTransition) {
            return;
        }

        this.inTransition = true;
        var _self = this;

        if (this.doText) {
            this.changeText(nextIndex);
        }
        
        var moveAmount = Math.ceil(
            Math.abs(
                this.images[this.currentIndex].position - this.images[nextIndex].position
            ) / 2
        ) * 2;

        if (this.options.testing) {
            $('testing').insert({
                'bottom' :
                    'Position to front: ' + this.images[nextIndex].position + '<br /><br />'
            });
        }

        var moveDirection = this._getDirection(this.images[nextIndex].position);

        this.images.each(function(image){
            _self.moveImage(image, moveAmount, moveDirection);
        });

        $(this.images[this.currentIndex].id).removeClassName(this.options.imageSelectedClass);
        $(this.images[nextIndex].id).addClassName(this.options.imageSelectedClass);

        this.currentIndex = nextIndex;
        
    },

    moveImage : function(image, moveAmount, moveDirection) {

        var _self = this;

        if (this.options.testing) {
            $('testing').insert({
                'bottom' :
                    'Move Amount: ' + moveAmount + '<br />' +
                    'Move Direction: ' + moveDirection + '<br />' +
                    'Initial Position: ' + image.position + '<br />'
            });
        }

        var newPosition = this._calculatePosition(image.position, moveAmount, moveDirection);

        if (this.options.testing) {
            $('testing').insert({
                'bottom' :
                    'Final Position: ' + newPosition + '<br /><br />'
            });
        }

        var percentage = this.positions[newPosition].height / this.positions[image.position].height;

        if (this.options.testing) {
            $('testing').insert({
                'bottom' :
                    'Actual Height: ' + $(image.id).getHeight() + '<br />' +
                    'Original Height: ' + this.positions[image.position].height + '<br />' +
                    'New Height: ' + this.positions[newPosition].height + '<br />' +
                    'Percentage: ' + percentage + '<br /><br />'
            });
        }

        if (this.options.useOpacity) {
            if (newPosition != 1) {
                var opacity = 1 - (Math.floor(newPosition / 2) / 5);
                if (opacity < 0.1) {
                    opacity = 0.1;
                }
                $(image.id).setOpacity(opacity);
                
            } else {
                $(image.id).setOpacity(1);
            }
        }
        
        //stage z-index change
        var zIndexChange = _self.positions[newPosition].zIndex - _self.positions[image.position].zIndex;
        var absZIndex = Math.abs(zIndexChange);
        var period = _self.options.transitionDuration / absZIndex;
        var multiplier = (zIndexChange < 0) ? -1 : 1;

        if (this.options.testing) {
            $('testing').insert({
                'bottom' :
                    'Original zIndex: ' + _self.positions[image.position].zIndex + '<br />' +
                    'New zIndex: ' + _self.positions[newPosition].zIndex + '<br /><br />'
            });
        }


        //change layer at start of move
        $(image.id).setStyle({
            zIndex : (_self.positions[image.position].zIndex + multiplier)
        });

        //keep changing layer as it progresses until it gets to correct layer
        for (var i = 2; i <= absZIndex; i++) {
            setTimeout('$("' + image.id + '").setStyle({zIndex : ' + (_self.positions[image.position].zIndex + multiplier * i) + '});', period * i * 1000);

            if (this.options.testing && i == absZIndex) {
                $('testing').insert({
                    'bottom' :
                        'Final zIndex: ' + (_self.positions[image.position].zIndex + multiplier * i) + '<br /><br /><br /><br />'
                });
            }
        }

        //$(image.id).setStyle({zIndex : _self.positions[newPosition].zIndex});

        new Effect.Scale(image.id, percentage * 100.00,{
            duration : _self.options.transitionDuration2,
            afterFinish : function() {
                _self.inTransition = false;
            }
        });
        
        new Effect.Move(image.id, {
            mode : 'absolute',
            duration : _self.options.transitionDuration,
            x : this.positions[newPosition].left,
            y : this.positions[newPosition].top
        });

        this.images[image.number - 1].position = newPosition;
    },

    changeText : function(nextIndex) {
        $(this.options.textContainer).update(this.images[nextIndex].text);
    },

    _setup : function() {
        //check if there is a text container
        if (!$(this.options.textContainer)) {
            this.doText = false;
        }

        this._processImages();

        if (this.doText) {
            $(this.options.textContainer).update(this.images[0].text);
        }
        
        this._bindControls();

        //calculate max positions
        var max = this.images.length;

        if (!this._isEven(max)) {
            this.maxLeft = max - 1;
            this.maxRight = max;
        } else {
            this.maxLeft = max;
            this.maxRight = max - 1;
        }
        
        if (this.options.testing) {
            Element.insert(document.body, {bottom : '<div id="testing" style="border:1px inset #000;background-color:#FFF;width:500px;padding:20px;"></div>'});
        }
    },

    _processImages : function() {
        var imageCounter = 0;
        var _self = this;

        $(this.options.mainContainer).setStyle({
            'position' : 'relative'
        });

        this.dimensions = $(this.options.mainContainer).getDimensions();

        //grab everything from content container by default, allows fall back content,
        //otherwise use main carousel container
        var container = (this.doText) ? this.options.textContainer : this.options.mainContainer;

        $$('#' + container + ' li').each(function(imageListElement){
            imageCounter++;

            var image = {};

            //get image elements
            imageListElement.descendants().each(function(item){

                switch (item.tagName.toLowerCase()) {
                    case 'a' :
                        image.url = item.href;
                        break;
                    case 'img' :
                        image.src = item.src;
                        image.width = item.width;
                        image.height = item.height;
                        break;
                    case 'div' :
                        if (item.className === _self.options.textClass) {
                            image.text = item.innerHTML;
                            break;
                        }
                }
            });

            if (!image.text) {
                image.text = '';
            }

            image.id = 'image_' + imageCounter;
            image.number = imageCounter;
            image.position = imageCounter;
            
            _self.images.push(image);

        });

        //clear image container
        $(this.options.mainContainer).update('');

        var zIndex = this.images.length;
        var firstImage = null;
        var previousLeft = null;
        var previousRight = null;
        
        //insert new elements
        this.images.each(function(image){
            image.currentZIndex = zIndex;

            //calculate position
            var left = (_self.dimensions.width / 2) - (image.width / 2);
            var top = (_self.dimensions.height / 2) - (image.height / 2);

            var dimensions = image;
            
            //add offset for other images
            if (firstImage) {

                var previousImage = null;
                var isLeft = false;
                var startPosition = left;
                var offset = 0.5;
                
                dimensions = _self._caculateImageSize(image.width, image.height, image.number);

                //determine and setup left or right
                //if first image on this side, use first image
                if (_self._isEven(zIndex)) {
                    isLeft = true;
                    previousImage = (previousLeft) ? previousLeft : firstImage;
                    startPosition = previousImage.left;
                    offset = _self.options.imageOffset;
                } else {
                    isLeft = false;
                    previousImage = (previousRight) ? previousRight : firstImage;
                    startPosition = previousImage.left + previousImage.width;
                    offset = 1 - _self.options.imageOffset;
                }

                //calculate position based on previous image on this side
                left = startPosition - (dimensions.width * offset);
                top = (_self.dimensions.height / 2) - (dimensions.height / 2);

                //keep track of previous images for future calculations
                if (isLeft) {
                    previousLeft = {'width' : dimensions.width, 'left' : left, 'top' : top};
                } else {
                    previousRight = {'width' : dimensions.width, 'left' : left, 'top' : top};
                }
            }

            if (!previousLeft && !previousRight) {
                firstImage = {'width' : dimensions.width, 'left' : left, 'top' : top};
            }
            
            var imageElement = new Element('img',{
                'id' : image.id,
                'src' : image.src,
                'alt' : '',
                'title' : '',
                'className' : (image.number == 1) ? _self.options.imageSelectedClass : '',
                'style' : 'position:absolute; left:' + left + 'px; top:' + top + 'px; z-index:' + zIndex + '; cursor:pointer; width:' + dimensions.width + 'px; height:' + dimensions.height + 'px'
            });

            //store values for when we move them later
            _self.positions[image.number] = {'left' : left, 'top' : top, 'width' : dimensions.width, 'height' : dimensions.height, 'zIndex' : zIndex};

            $(_self.options.mainContainer).insert({'bottom' : imageElement});
            zIndex--;
        });

    },

    _caculateImageSize : function(width, height, order) {

        var multiplyer = Math.floor(order / 2);
        
        var percentage = Math.pow(this.options.imageDegradation, multiplyer);

        var newWidth = width * percentage;
        var newHeight = height * percentage;

        return {'width' : newWidth, 'height' : newHeight};
    },

    _calculatePosition : function(currentPosition, amount, direction) {

        var side = this._getSide(currentPosition);

        //alert(currentPosition);
        //no more moves necessary
        if (amount == 0) {
            //alert('Final: ' + currentPosition);
            return currentPosition;
        }

        var moveAmount = 2;

        //if first image on left and moving right, move from 2 -> 1
        if (currentPosition == 2 && direction == 'right') {
            moveAmount = 1;
        }

        //if current image and moving left, move from 2 -> 1
        if (currentPosition == 1 && direction == 'left') {
            moveAmount = 1;
        }

        //whether it is increasing or decreasing
        if (currentPosition != 1) {
            moveAmount = ( (side == 'left' && direction == 'right') || (side == 'right' && direction == 'left') ) ? moveAmount * -1 : moveAmount;
        }
        
        var nextPosition = currentPosition + moveAmount;

        //wrapping
        if (side == 'right' && nextPosition > this.maxRight) {
            nextPosition = this.maxLeft;
        }
        else if (side == 'left' && nextPosition > this.maxLeft) {
            nextPosition = this.maxRight;
        }

        if (this.options.testing) {
            $('testing').insert({
                'bottom' :
                    'Side: ' + side + '<br />' +
                    'Move Amount: ' + amount + '<br />' +
                    'Move Direction: ' + direction + '<br />' +
                    'Next Position: ' + nextPosition + '<br />'
            });
        }

        return this._calculatePosition(nextPosition, amount - 2, direction);
    },

    _bindControls : function() {
        var _self = this;

        this.images.each(function(image) {
            Event.observe(image.id, 'click', _self.changeImage.bind(_self, image.number - 1));

            if (_self.options.enableDragging) {
                new Draggable(image.id, {
                    revert : true,
                    starteffect : null,
                    endeffect : null,
                    onStart : function() {
                        _self.dragging = true;
                    },
                    onEnd : function() {
                        _self.dragging = false;
                    }
                });
                }
        });
    },

    _isEven : function(number) {
        return number % 2 == 0;
    },

    /**
     * Even positions are right, odd positions are left, 1 at front
     */
    _getSide : function(position) {
        if (this._isEven(position)) return 'left';
        else return 'right';
    },

    /**
     * if on left, move to right, if on right, move to left
     */
    _getDirection : function(position) {
        if (this._getSide(position) == 'right') return 'left';
        else return 'right';
    }
}
