/*
 * MooTools based slideshow
 * Copyright (C) Nick Wellnhofer, 2009
 * wellnhofer@aevum.de
 */

var AESlideshow = new Class({
    Implements: [ Options, Events ],
    options: {
        transition: {
            type: 'slide'
        },
        createLinks: true,
        autoDelay: 0
    },
    transitions: {
        slide: new Class({
            Implements: [ Options ],
            options: {
                fps: 50,
                duration: 1000,
                transition: Fx.Transitions.Quad.easeInOut,
                direction: 'left'
            },
            initialize: function(slideshow, options) {
                this.slideshow = slideshow;
                this.setOptions(options);
                
                var dir = this.options.direction;
                
                if(dir == 'top' || dir == 'bottom') {
                    this.fxProperty = 'top';
                    this.size = slideshow.size.y;
                    this.switchMode = dir == 'bottom' ? 1 : 0;
                }
                else {
                    this.fxProperty = 'left';
                    this.size = slideshow.size.x;
                    this.switchMode = dir == 'right' ? 1 : 0;
                }
                
                this.fx = new Fx.Tween(slideshow.container, {
                    property: this.fxProperty,
                    unit: 'px',
                    fps: this.options.fps,
                    duration: this.options.duration,
                    transition: this.options.transition,
                    onComplete: this.complete.bind(this)
                });
            },
            start: function(mode, oldItem, newItem) {
                var newPos = this.size;
                if((mode == 'prev' ? 1 : 0) ^ this.switchMode)
                    newPos = -newPos;
                
                newItem.setStyle(this.fxProperty, newPos + 'px');
                this.fx.start(0, -newPos);
                
                this.oldItem = oldItem;
                this.newItem = newItem;
            },
            complete: function() {
                var slideshow = this.slideshow;
                
                this.oldItem.dispose();
                this.newItem.setStyle(this.fxProperty, '0');
                slideshow.container.setStyle(this.fxProperty, '0');
                
                slideshow.endAnimation();
            }
        }),
        fade: new Class({
            Implements: [ Options ],
            options: {
                fps: 50,
                duration: 1000,
                transition: Fx.Transitions.Sine.easeInOut
            },
            initialize: function(slideshow, options) {
                this.slideshow = slideshow;
                this.setOptions(options);
            },
            start: function(mode, oldItem, newItem) {
                newItem.setStyle('opacity', '0');
                
                new Fx.Tween(newItem, {
                    property: 'opacity',
                    fps: this.options.fps,
                    duration: this.options.duration,
                    transition: this.options.transition,
                    onComplete: this.complete.bind(this)
                }).start(0, 1);
                
                this.oldItem = oldItem;
            },
            complete: function() {
                this.oldItem.dispose();
                this.slideshow.endAnimation();
            }
        })
    },
    initialize: function(slideshow, options) {
        this.slideshow = $(slideshow);
        this.setOptions(options);
        
        this.slideshow.getElement('.noscript').setStyle('display', 'none');
        
        this.items = [];
        this.itemSpecs = this.slideshow.getElements('.item-spec');
        this.allowInput = true;
        this.size = this.slideshow.getSize();
        this.pos = 0;
        
        this.container = new Element('div', {
            styles: {
                position: 'absolute'
            }
        }).inject(this.slideshow);
        
        if(this.options.createLinks) {
            new Element('a', {
                'class': 'left',
                events: {
                    mousedown: this.prev.bind(this)
                }
            }).inject(this.slideshow);
            
            new Element('a', {
                'class': 'right',
                events: {
                    mousedown: this.next.bind(this)
                }
            }).inject(this.slideshow);
        }
        
        var transOptions = this.options.transition;
        var tclass = this.transitions[transOptions.type];
        this.transition = new tclass(this, transOptions);
        
        this.load(0);
        this.items[0].inject(this.container);
        
        this.startTimer();
    },
    normalizePos: function(pos) {
        var len = this.itemSpecs.length;
        
        if(pos < 0) pos += len;
        else if(pos >= len) pos -= len;
        
        return pos;
    },
    load: function(pos) {
        pos = this.normalizePos(pos);
        if(this.items[pos]) return;
        
        var item = new Element('div', {
            'class': 'item',
            styles: {
                position: 'absolute',
                left: '0',
                top: '0',
                width: this.size.x + 'px',
                height: this.size.y + 'px'
            }
        });
        this.populateItem(item, this.itemSpecs[pos]);
        this.items[pos] = item;
    },
    populateItem: function(item, spec) {
        spec.getChildren().inject(item);
    },
    prev: function(event) {
        if(event) event.stop();
        this.jump(this.pos - 1, 'prev');
    },
    next: function(event) {
        if(event) event.stop();
        this.jump(this.pos + 1, 'next');
    },
    jump: function(newPos, mode) {
        if(!this.allowInput) return;
        this.allowInput = false;
        this.animationCount = 1;
        $clear(this.autoTimer);
        
        newPos = this.normalizePos(newPos);
        this.load(newPos);
        
        var oldItem = this.items[this.pos];
        var newItem = this.items[newPos];
        newItem.inject(this.container);
        this.transition.start(mode, oldItem, newItem);
        
        this.fireEvent('transition', [ mode, newPos ]);
        
        this.pos = newPos;
    },
    beginAnimation: function() {
        ++this.animationCount;
    },
    endAnimation: function() {
        --this.animationCount; 
        
        if(this.animationCount == 0) {
            this.allowInput = true;
            this.startTimer();
        }
    },
    startTimer: function() {
        var autoDelay = this.options.autoDelay;
        if(autoDelay)
            this.autoTimer = this.next.delay(autoDelay, this);
    }
});
    
AESlideshow.Preloaded = new Class({
    Extends: AESlideshow,
    options: {
        preloadCount: 1
    },
    initialize: function(slideshow, options) {
        this.parent(slideshow, options);
        this.setOptions(options);
        
        this.preloadSiblings(null, this.pos);
        this.addEvent('transition', this.preloadSiblings.bind(this));
    },
    preloadSiblings: function(mode, newPos) {
        for(var i=1; i<=this.options.preloadCount; ++i) {
            this.load(newPos + i);
            this.load(newPos - i);
        }
    },
    populateItem: function(item, spec) {
        var a = spec.getElement('a.image');
        new Asset.image(a.href).inject(item);
    }
});

AESlideshow.Slave = new Class({
    Extends: AESlideshow,
    setMaster: function(master) {
        this.master = master;
        master.addEvent('transition', this.masterTransition.bind(this));
    },
    masterTransition: function(mode, newPos) {
        this.master.beginAnimation();
        if(mode == 'prev') this.prev();
        else if(mode == 'next') this.next();
    },
    endAnimation: function() {
        this.parent();
        this.master.endAnimation();
    }
});
