var Slide = new Class({
    /**
     * Slide - an item in a slideshow
     */
    'Implements': [Options],
    'options': {},
    'initialize': function init (element, slideshow, options) {
        this.setOptions(options);
        this.slideshow = slideshow;
        this.element = $(element);

        this.fadeEffect = new Fx.Tween (
            this.element, {
                property: 'opacity',
                onComplete: this.slideshow.callChain.bind(this.slideshow)
            });

        this.effect = new Fx.Tween(
            this.element.getElement('.details'), {
                property: 'left',
                onComplete: this.slideshow.callChain.bind(this.slideshow)
            });

        this.effect.set(0);
    },

    shut: function () { this.effect.start(0); },

    open: function () { this.effect.start(380); },

    wait: function (time) {
        return this.slideshow.callChain.delay(time, this.slideshow);
    },

    toLayer: function (z) {
        this.element.setStyle('z-index', z);
    },

    fade: function (arg) {
        if (arg == 'out') {
            this.fadeEffect.start(1, 0);
        } else if (arg == 'in') {
            this.fadeEffect.start(0, 1);
        }
    }
 });

window.addEvent('domready', function() {

    var Slideshow = new Class({
        Implements: [Chain, Options],

        options: {
            openTime: 4000, // time each slide will remain open (ms)
            closedTime: 500 // time each slide will remain closed (ms)
        },

        initialize: function(elements, options){
            this.setOptions(options);

            this.slides = $$(elements).map(
                function (element) {
                    return new Slide(element, this, {});
                }, this);

            this.orderSlides();
        },

        orderSlides: function () {
            // sets z-index on each slide according to its position
            // in the list
            this.slides.each(
                function (slide, index, ls) {
                    var z = (ls.length - index) + 2;
                    slide.toLayer(z);
                });
        },

        animation: function(){
            this.slides.each(
                function(slide){
                    var link = function(name, args){
                        args = $splat(args);
                        return function () {
                            return slide[name].apply(slide, args);
                        };
                    };

                    var toBack = function () {
                        // send the first slide to the back
                        this.slides.push(this.slides.shift());
                        this.orderSlides();
                        this.callChain();
                    };

                    this.chain(
                        link('open'),
                        link('wait', this.options.openTime),
                        link('shut'),
                        link('wait', this.options.closedTime),
                        link('fade', 'out'),
                        toBack,
                        link('fade', 'in')
                        // using Fx.Tween.start instead of Fx.Tween.set
                        // "fixes" an IE timing bug
                    );
                }, this);

            this.chain(this.animation);
            this.callChain();
        }
    });

    var show = new Slideshow('.slideshow li');
    show.animation();
});
