Gondola = Class.create(Abstract, {
    initialize: function (scroller, slides, controls, options) {
            this.scrolling	= false;
            this.scroller	= $(scroller);
            this.slides		= slides;
            this.controls	= controls;
            this.interval       = false;
            this.rightBtnWrap   = $("gondola-arrow-right-wrapper");
            this.leftBtnWrap    = $("gondola-arrow-left-wrapper");
            this.rightBtn       = $("gondola-arrow-right");
            this.leftBtn        = $("gondola-arrow-left");

            this.options    = Object.extend({
            duration:           1,
            auto:               false,
            frequency:          3,
            visibleSlides:      1,
            carouselJumper:     'gondola-jumper-',
            jumperClassName:    'gondola-jumper',
            disabledClassName:  'carousel-disabled',
            inactiveClassName:  'carousel-inactive',
            selectedClassName:  'carousel-selected',
            circular:           false,
            step:               1,
            wrap:               'carousel-wrap',
            imgToPreload:       1,
            imgURLs:            {}
        }, options || {});

        this.scroller.observe('mouseover',    this.mouseOver.bindAsEventListener(this));
        this.scroller.observe('mouseout',     this.mouseOut.bindAsEventListener(this));
        this.rightBtnWrap.observe('mouseout', this.mouseOut.bindAsEventListener(this));
        this.leftBtnWrap.observe('mouseout',  this.mouseOut.bindAsEventListener(this));
        this.rightBtn.observe('click',        this.clickNext.bindAsEventListener(this));
        this.leftBtn.observe('click',         this.clickPrev.bindAsEventListener(this));
        window.gondolaManager = this;

        if (this.options.effect == 'fade') {
            this.options.circular = true;
        }

        this.slides.each(function(slide, index) {
            slide._index = index;
        });

        if (this.controls) {
            this.controls.invoke('observe', 'click', this.click.bind(this));
        }

        if (this.options.auto) {
            this.start();
        }
        this.ensureImagesLoaded();
    },

    mouseOver: function() {
        this.stop();
        this.showWithFade(this.leftBtnWrap, 0.2);
        this.showWithFade(this.rightBtnWrap, 0.2);
    },

    mouseOut: function(event) {
        if (!event) {
            event = window.event;
        }
        var reltarget = (event.relatedTarget) ? event.relatedTarget : event.toElement
        if (reltarget && $(reltarget).up(0)) {
            if (($(reltarget).up(0).id == 'gondola') || ($(reltarget).up(0).hasClassName('arrow-wrapper'))) return;
        }
        

        this.hideWithFade(this.leftBtnWrap, 0.2);
        this.hideWithFade(this.rightBtnWrap, 0.2);
        this.start();
    },

    clickNext: function(event) {
        if (!event) {
            event = window.event;
        }
        this.stop();
        var element = event.findElement('a');
        if (element.hasClassName(this.options.disabledClassName)) {
            return false;
        }
        this.deactivateControls();
        event.stop();
        this.interval = false;
        var nextIndex = this.getNextIndex();
        this.moveTo(this.slides[nextIndex]);
        this.start();
    },

    clickPrev: function(event) {
        if (!event) {
            event = window.event;
        }
        this.stop();
        var element = event.findElement('a');
        if (element.hasClassName(this.options.disabledClassName)) {
            return false;
        }

        this.deactivateControls();
        event.stop();
        this.interval = false;
        var prevIndex = this.getPrevIndex();
        this.moveTo(this.slides[prevIndex]);
        this.start();
    },

    click: function (event) {
        if (!event) {
            event = window.event;
        }
        event.stop();
        this.stop();

        var element = event.findElement('a');
        if (element.hasClassName(this.options.disabledClassName)) {
            return false;
        }
        if (element.hasClassName(this.options.selectedClassName)) {
            return false;
        }

        if (!element.hasClassName(this.options.disabledClassName)) {
            if (element.hasClassName(this.options.jumperClassName)) {
                this.moveTo(element.rel);
                if (this.options.selectedClassName) {
                    this.controls.invoke('removeClassName', this.options.selectedClassName);
                    element.addClassName(this.options.selectedClassName);
                }
            }
        }
        this.deactivateControls();
        this.interval = setTimeout(this.periodicallyUpdate.bind(this), this.options.frequency * 1000);
    },

    moveTo: function (element) {
        this.previous = this.current ? this.current : this.slides[this.slides.length-1];
        this.current  = $(element);

        var items = new Array();
        for(c=i=0;i<this.scroller.childNodes.length;i++){
            if (this.scroller.childNodes[i].tagName=="A"){
                items[c++] = this.scroller.childNodes[i];
            }
        }
        var last = items[items.length-1];
        this.checkJumper(last._index+1, this.current._index+1);
        this.current.show();
        this.hideWithFade(last, 0.3, true);
        return false;
    },

    animate: function() {
        var items = [];
        for(c=i=0;i<this.scroller.childNodes.length;i++){
            if (this.scroller.childNodes[i].tagName=="A"){
                if(this.scroller.childNodes[i]._index == this.current._index) {
                    var nextIndex = c;
                }
                items[c++] = this.scroller.childNodes[i];
            }
        }
        var first = items[0];
        for(var i=items.length-1; i > nextIndex; i--) {
            var l = items[i]
            var tmp = l;
            this.scroller.removeChild(l);
            this.scroller.insertBefore(tmp,first);
            first = tmp;
        }
        this.activateControls();
    },
    getNextIndex: function() {
        var currentIndex = this.slides.length -1;
        var nextIndex    = this.options.step;
        if (this.current) {
            currentIndex = this.current._index;
        }
        nextIndex = (currentIndex - this.options.step < 0) ?  this.slides.length -1 : currentIndex - this.options.step;
        return nextIndex;
    },

    getPrevIndex: function() {
        var currentIndex = this.slides.length -1;
        var prevIndex = 0;
        if (this.current) {
            currentIndex = this.current._index;
        }
        prevIndex = (this.slides.length - 1 == currentIndex) ? 0 : currentIndex + this.options.step;
        return prevIndex;
    },

    checkJumper: function(current, next) {
        if ($(this.options.carouselJumper + current)) {
            $(this.options.carouselJumper + current).removeClassName('carousel-selected');
        }
        if ($(this.options.carouselJumper + next)) {
            $(this.options.carouselJumper + next).addClassName('carousel-selected');
        }
    },
    stop: function () {
        if (this.interval) {
            clearTimeout(this.interval);
            this.interval = false;
        }
    },

    start: function () {
        this.stop();
        this.interval = window.setInterval(this.periodicallyUpdate.bind(this), this.options.frequency * 1000 );
    },

    pause: function () {
        this.stop();
        this.activateControls();
    },

    periodicallyUpdate: function () {
        var nextIndex = this.getNextIndex();
        this.moveTo(this.slides[nextIndex]);
    },

    deactivateControls: function () {
        this.controls.invoke('addClassName', this.options.disabledClassName);
        this.rightBtn.addClassName(this.options.disabledClassName);
        this.leftBtn.addClassName(this.options.disabledClassName);
    },

    activateControls: function () {
        this.controls.invoke('removeClassName', this.options.disabledClassName);
        this.rightBtn.removeClassName(this.options.disabledClassName);
        this.leftBtn.removeClassName(this.options.disabledClassName);
    },

    ensureImagesLoaded: function() {
        for ( var i = 0; i < this.slides.length; i++ ) {
            var img = this.slides[ i ].getElementsBySelector('img').first();
            if ( this.options.imgURLs[ img.id ] && img.src != this.options.imgURLs[ img.id ] )
                img.src = this.options.imgURLs[ img.id ];
        }
    },

    showWithFade: function(elem, duration) {
        var elem = $(elem);
        if (!elem.visible() || elem.hiding) {
            elem.hiding = false;
            if (elem.effect)
                elem.effect.cancel();
            if (Prototype.Browser.IE) {
                elem.addClassName('suppress_shadow');
                elem.effect = new Effect.Appear(elem, {duration: duration, afterFinish: function() {elem.removeClassName('suppress_shadow');}} );
            } else {
                elem.effect = new Effect.Appear(elem, {duration: duration});
            }
        }
    },

    hideWithFade: function (elem, duration, callback) {
        var elem = $(elem);
        if (elem.visible() && !elem.hiding) {
            if (elem.effect && !elem.hiding)
                elem.effect.cancel();
            elem.hiding = true;

            if (Prototype.Browser.IE) {
                elem.addClassName('suppress_shadow');
            }
            if (callback) {
                elem.effect = new Effect.Fade(elem, {duration: duration, afterFinish: function() {elem.hiding=false;window.gondolaManager.animate();}});
            } else {
                elem.effect = new Effect.Fade(elem, {duration: duration});
            }
        }
    }

});
