Event.observe(window, 'load',
function() {

    if (Modernizr.csstransforms3d && BrowserDetect.browser != "Chrome") {
        Coverflow3D();
    } else {
        document.documentElement.removeClassName("csstransforms3d");
        $$('.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');
        }
    }
});



var Coverflow3D = function() {

    var images_cache,
    angle = 0;
    function carousel(a) {
        var images = images_cache || (images_cache = $$('.coverflow img')),
        len = images.length,
        radius = len * 19,
        d = Math.PI * 2 / len,
        xrad = radius * 2,
        yrad = radius * 2.5;

        if (a) {
            angle = a;
        }

        for (var i = len - 1; i >= 0; i--) {
            var img = images[i],
            x = Math.sin(angle) * xrad,
            y = Math.cos(angle) * yrad;

            img.setStyle({
                '-webkitTransform': 'translateX(' + (xrad * 0.26 + x) + 'px) translateZ(' + (y - yrad) + 'px)'
            });
            angle -= d;
        }
    }

    $('coverflow').removeClassName('loading');

    carousel();

    var startX,
    cancelClick,
    startAngle,
    pX,
    diff,
    supportsTouch = Modernizr.touch,
    dt,
    pDt,
    velocity,
    spinInterval;

    var start = function(e, pos) {
        cancelClick = false;
        clearInterval(spinInterval);
        startX = pos
        pX = startX;
        startAngle = angle;
        e.stop();
        pDt = new Date().getTime();
    },
    move = function(e, pos) {
        cancelClick = true;

        var now = new Date().getTime();
        dt = now - pDt;
        if (startX) {
            var x = pos;
            diff = (x - pX) * 0.01;
            pX = x;
            velocity = diff / dt;
            carousel(startAngle + (x - startX) * 0.001);
        }
        pDt = now;
        e.stop();
    },
    end = function(e) {
        if (cancelClick) {
            var now = new Date().getTime();
            dt = now - pDt;
            if (diff) {
                velocity = diff / dt;

                var spin = angle;
                spinInterval = setInterval(function() {
                    carousel(spin);
                    spin += velocity;
                    velocity *= 0.98;
                    if (velocity < 0.001 && velocity > -0.001)
                    clearInterval(spinInterval);
                },
                15);
            }
        } else {
            click.call(this, e);
        }
        startX = null;
        startAngle = 0;
    },
    click = function(e) {
        if (cancelClick) return;
        var img = e.element(),
        tmp = new Image(),
        position = img.getAttribute('coverflow:nextposition') || 'back',
        src = img.getAttribute('coverflow:card' + position);

        if (position == 'back')
        img.setAttribute('coverflow:cardfront', img.getAttribute('src'));

        tmp.onload = function() {
            var wrapper = img.insert({
                before: '<div><div><img class="front"><img class="back"></div></div>'
            }).previous();
            img.hide();
            var back = wrapper.down('.back');
            var front = wrapper.down('.front');
            var startingTransform = img.style.webkitTransform;
            wrapper.style.webkitTransform = startingTransform;
            back.src = src;
            front.src = img.src;

            setTimeout(function() {
                wrapper.addClassName('rotated');
                img.setAttribute('coverflow:nextposition', position == 'front' ? 'back': 'front');
                setTimeout(function() {
                    img.src = src;
                    img.show();
                    wrapper.remove();
                },
                1000);
            },
            100);
        };
        tmp.src = src;
    }
    
    if (supportsTouch) {
        $('coverflow').observe('touchstart',
        function(e) {
            start(e, e.touches[0].pageX);
        }).observe('touchmove',
        function(e) {
            move(e, e.touches[0].pageX);
        }).observe('touchend',
        function(e) {
            end(e);
        }).observe('touchcancel',
        function(e) {
            startX = null;
            startAngle = 0;
        })
    } else {
        $('coverflow').observe('mousedown',
        function(e) {
            start(e, e.pointerX());
        }).observe('mousemove',
        function(e) {
            move(e, e.pointerX());
        }).observe('mouseup',
        function(e) {
            end(e);
        })
    }
};

