Event.observe(window, 'load', function() { 
    $$('.coverflow').each(function(element) {
        new Coverflow(element);
    });
});

var Coverflow = Class.create({    
    initialize: function(element, options) {    
        this.element = $(element);
        this.options = Object.extend({ scale: 0.6, transition: 'flip' }, options || { }); 
        this.container = element.identify();
        this.initAnimation();
        this.initContainer();
        this.attachEvents();
        this.initImages();
        if (this.images.size() < 1) {
            throw new Error('No images to flow');
        }
        this.element.removeClassName('loading');
        this.selectImage.bind(this).delay(0.5, this.images[parseInt(this.images.size() / 2, 10)], true);
    },

    initAnimation: function() { 
        this.effectQueue = new Effect.Queue();
        if (!Effect.queues) {
            Effect.initialize();
        }     
        Effect.queues.push(this.effectQueue);
    },
    
    initContainer: function() {
        var images = $(this.container)
            .setStyle('margin:auto;position:relative;overflow:hidden;display:block;height:450px;width:100%;white-space:nowrap')
            .select('img');

        images.invoke('addClassName', 'sourceImage');
        images.invoke('setStyle', 'margin:auto;left:0px;top:0px');

        // Add some space before and after images to allow for scrolling first and last images to middle of page
        var width = $(this.container).getWidth();
        images.first().setStyle('margin-left:' + (width / 2) + 'px');
        images.last().setStyle('margin-right:' + (width / 2) + 'px');
    },
    
    initImages: function() {
        this.images = this.element.select('.sourceImage');
        this.originalWidth = this.images.first().getWidth();
        this.originalHeight = this.images.first().getHeight();
        this.images.each(function(image) {
            image.setStyle({
                width:  (this.originalWidth * this.options.scale) + 'px',
                height: (this.originalHeight * this.options.scale) + 'px'
            });
        }.bind(this));
    },
           
    attachEvents: function() {
        var container = $(this.container);
        
        // Clicking on image
        container.observe('mousedown', function(event) {
            event.stop();
            var i = event.findElement('img');
            if (i) {
                this.selectImage(i);             
            }                
        }.bindAsEventListener(this));
        
        // Keyboard left and right arrows
        Event.observe(document, 'keydown', function(event) {
           if (event.keyCode == Event.KEY_LEFT && this.currentImage > 0) {
               this.selectImage(this.currentImage - 1);
           } else if (event.keyCode == Event.KEY_RIGHT 
               && (this.currentImage + 1) < container.select('.sourceImage').size()) {
               this.selectImage(this.currentImage + 1);
           } else if (event.keyCode == Event.KEY_UP || event.keyCode == Event.KEY_DOWN) {
               event.stop();
               this.showMore(container.select('.sourceImage')[this.currentImage]);
           }  
        }.bindAsEventListener(this));
    },
    
    
    selectImage: function(img, popAfterScroll) {
        var container = $(this.container);
        
        if (Object.isNumber(img)) {
            if (this.currentImage == img) {
                this.showMore(container.select('.sourceImage')[img]);
                return;
            }
            this.currentImage = img;            
            img = container.select('.sourceImage')[img];
        } else {
            if (img.hasClassName('expanded')) {
                img = img.next();
            }
            var newImageIndex = container.select('.sourceImage').indexOf(img);
            if (this.currentImage == newImageIndex) {
                this.showMore(img);
                return;
            }
            this.currentImage = newImageIndex;
        }

        if (img) {
            var targetLeft = document.viewport.getDimensions().width / 2 - (img.getWidth() / 2);
            var actualLeft = img.viewportOffset().left;
            var from = container.scrollLeft;
            var to = container.scrollLeft - parseInt(targetLeft - actualLeft, 10);
            var queue = this.effectQueue;
            
            queue.effects.each(function(effect) {
                queue.remove(effect);
            });
                        
            container.select('.expanded').each(function(expanded) {
                var image = expanded.next();
                // Flip back
                // if (image.getAttribute('coverflow:nextCardPosition') == 'Front') {
                //                     this.showMore(image);
                //                 }                                
                expanded.morph('width:#{width}px;height:#{height}px;left:#{left}px;top:#{top}px'.interpolate({
                    width: image.getWidth(),
                    height: image.getHeight(),
                    left: image.positionedOffset().left,
                    top: 0
                }), { duration: 0.3, queue: queue, after:function() { expanded.style.zIndex=0; } });
            }.bind(this));

            var previous = img.previous();
            if (!previous || !previous.hasClassName('expanded')) {
                previous = this.cloneAbsolute(img, 'sourceImage', 'expanded');
            }
            
            img.setStyle('visibility: hidden');
            
            
            var scroll = function() {new Effect.Attribute(container, from, to, { duration: 0.75, queue: queue }, 'scrollLeft').play();};
            var pop = function() {
                this.originalLeft = img.positionedOffset().left - (this.originalWidth / 2 - img.getWidth() / 2);
                previous.morph('width:#{width}px;height:#{height}px;left:#{left}px;top:#{top}px'.interpolate({
                    'width': this.originalWidth,
                    'height': this.originalHeight,
                    'left': this.originalLeft,
                    'top': 10
                }), { duration: 0.6, position: 'end', queue: queue, transition: 'swingTo', before: function() { previous.style.zIndex = 1; }});                        
            }.bind(this);
            
            if (popAfterScroll) {
                scroll();pop();
            } else {
                pop();scroll();
            }
        }
    },
    
    cloneAbsolute: function(cloneNode, removeClass, addClass) {
        var cloned = cloneNode.cloneNode(true).removeClassName(removeClass);
        cloneNode.insert({'before': cloned});
        cloned.absolutize();
        cloned.setStyle({
            left: cloneNode.positionedOffset().left + 'px',
            top: cloneNode.positionedOffset().top + 'px',
            width: cloneNode.getWidth() + 'px',
            height: cloneNode.getHeight() + 'px',
            margin: 0
        });
        cloned.addClassName(addClass);
        return cloned;
    },
    
    showMore: function(img) {
        img = img.match('.sourceImage') ? img : img.next('.sourceImage');
        var oldSource = img.src;
        var position = (img.getAttribute('coverflow:nextCardPosition') || 'Back');
                
        if (!img.hasAttribute('coverflow:cardFront')) {
            img.setAttribute('coverflow:cardFront', img.src);
        }
        
        this.backTransitions[this.options.transition].call(this, img, img.previous(), position);
    },
    
    backTransitions: {
        
        slide: function(actualImg, expandedImg, position) {
            var top = expandedImg.positionedOffset().top;
            expandedImg.morph('top:-' + this.originalHeight + 'px', {
                duration: 0.4,
                queue: this.effectQueue, 
                position: 'end',
                after: function() {
                    expandedImg.onload = function() {
                        expandedImg.morph('top:' + top + 'px', {
                            duration: 0.4,
                            queue: this.effectQueue, 
                            position: 'end'
                        });
                    }.bind(this);                
                    expandedImg.src = actualImg.getAttribute('coverflow:card' + position);
                    actualImg.setAttribute('coverflow:nextCardPosition', position == 'Front' ? 'Back' : 'Front');
                }.bind(this)
            });            
        },
      
        flip: function(actualImg, expandedImg, position) {
            var width = this.originalWidth;
            var left = this.originalLeft;                        
            var tmp = new Image();
            var src = actualImg.getAttribute('coverflow:card' + position);
            
            tmp.onload = function() {
                expandedImg.morph('left:' + (width / 2 + left) + 'px;width:1px', {
                    duration: 0.2,
                    queue: this.effectQueue, 
                    position: 'end',
                    after: function() {
                        expandedImg.src = src;
                        expandedImg.morph('left:' + left + 'px;width:' + width + 'px;', {
                            duration: 0.2,
                            queue: this.effectQueue, 
                            position: 'end'
                        });                        
                    }.bind(this)
                });
            }.bind(this);                
            tmp.src = src;
            actualImg.setAttribute('coverflow:nextCardPosition', position == 'Front' ? 'Back' : 'Front');            
        }
    }
});
