
if(!CBI) var CBI = {};

CBI.Slideshow = Class.create({
    initialize: function(element, options){
        this.element = $(element);
        this.options = Object.extend({
            url:'', 
            slideshow: {}, 
            quotes: {
                start_delay: .5, 
                special_events: "/news/events"
            }, 
            is_home: false, 
            is_mobile: false
        }, options || {});
        
        new Ajax.Request(this.options.url, {
            method:'get', 
            onSuccess: function(response){
                this.data = new CBI.Slideshow.Data(response.responseXML);
                this.build();
            }.bind(this)
        });
    }, 
    
    build: function(){
        this.slideshow = new CBI.Slideshow.Base(
            this.data.get_slides(), this.options.slideshow);
        this.element.insert(this.slideshow);
        
        if(this.options.is_home){
            this.element.addClassName('home');
            this.quotes = new CBI.Slideshow.Quotes(
                this.data.get_quotes(), this.options.quotes);
            this.element.insert(this.quotes);
        }
        else {
           this.element.insert(new CBI.Slideshow.Selector(this.slideshow));
        }
        
        if(!this.options.is_mobile){
            new CBI.Slideshow.DreamVacation(this.element, {
                is_home: this.options.is_home
            });
        }
    }
});


CBI.Slideshow.callbacks = {
    dream_vacation: {
        shown: function(){ $(document).fire('cbi:slideshow:dream_vacation:shown'); }, 
        hidden: function(){ $(document).fire('cbi:slideshow:dream_vacation:hidden'); }
    }
};


CBI.Slideshow.Timer = Class.create(PeriodicalExecuter, {
    start: function(){
        if(!this.timer) this.registerCallback();
    }, 
    
    reset: function(){
        this.stop();
        this.start();
    }
});


CBI.Slideshow.Base = Class.create({
    initialize: function(data, options){
        this.data = data;
        this.options = Object.extend({
            wait_duration: 5, 
            transition_duration: 1, 
            start_delay: 0, 
            autoplay: true
        }, options || {});
        this.executor;
        this.current_frame = 0;
        this.playing = false;
        
        this.build();
        if(this.options.autoplay && this.data.length > 1){
            setTimeout(function(){
                this.play();
            }.bind(this), this.options.start_delay * 1000);
        }
    }, 
    
    build: function(){
        this.frames = this.data.map(function(image, i){
            var frame = new Element('li').update(
                new Element('img', { src: image }));
            return (i > 0)? frame.hide() : frame;
        });
        this.element = new Element('ul', {'class':'slides'})
            .insertCollection(this.frames);
    }, 
    
    toElement: function(){
        return this.element;
    }, 
    
    play: function(){
        if(!this.playing) this.advance_after_delay();
        this.playing = true;
    }, 
    
    pause: function(){
        if(this.playing) this.executor.stop();
        this.playing = false;
    }, 
    
    advance_after_delay: function(){
        this.executor = new CBI.Slideshow.Timer(this.advance_frame.bind(this), 
            this.options.wait_duration + this.options.transition_duration);
    }, 
    
    advance_frame: function(index){
        var options = { duration: this.options.transition_duration };
        new Effect.Fade(this.frames[this.current_frame], options);
        
        this.current_frame = this.normalize_frame_number(
            // Filter out callback function from the PeriodicalExecutor.
            // + 1 because we have a 0-based index and "== NaN" doesn't work.
            (parseInt(index) + 1)? index : (this.current_frame + 1));
        
        new Effect.Appear(this.frames[this.current_frame], options);
        $(document).fire('cbi:slideshow:advance_frame', this.current_frame);
    }, 
    
    normalize_frame_number: function(frame){
        if(frame < 0) return (this.frames.length - 1);
        if(frame > (this.frames.length - 1)) return 0;
        return frame;
    }
});


CBI.Slideshow.Quotes = Class.create(CBI.Slideshow.Base, {
    build: function(){
        this.frames = this.data.map(function(quote, i){
            var frame = new Element('li')
                .update(new Element('a', { href: quote.href, target: quote.target })
                    .update(new Element('img', { src: quote.src })))
                .setStyle({ top: px(quote.y), left: px(quote.x) });
            return (i > 0)? frame.hide() : frame;
        });
        var container = new Element('ul').insertCollection(this.frames);
        var special_events = new Element('a', {'class':'special-events', href: this.options.special_events })
            .update('<span>Special Events</span>');
        this.element = new Element('div', {'class':'quotes'})
            .insertCollection([container, special_events]);
        
        $(document).observe('cbi:navigation:shown', function(){
            container.hide(); 
            special_events.fade({ duration: .2 });
        }.bind(this));
        $(document).observe('cbi:navigation:hidden', function(){
            container.show(); 
            special_events.appear({ duration: .2 });
        }.bind(this));
    }, 
    
    advance_frame: function(){
        new Effect.Fade(this.frames[this.current_frame], {
            duration: this.options.transition_duration / 2
        });
        
        this.current_frame = this.normalize_frame_number(this.current_frame + 1);
        
        var frame = this.frames[this.current_frame];
        new Effect.Move(frame, {
            x: -150, 
            mode: 'relative', 
            duration: 0
        });
        new Effect.Parallel([
            new Effect.Appear(frame, {
                duration: this.options.transition_duration
            }), 
            new Effect.Move(frame, {
                x: 150, 
                mode: 'relative', 
                duration: this.options.transition_duration, 
                transition: Effect.Transitions.Quart.easeOut
            })
        ]);
    }
});


CBI.Slideshow.Selector = Class.create({
    initialize: function(slideshow){
        this.slideshow = slideshow;
        this.selectors = $R(1, this.slideshow.frames.length).map(function(i){
            var selector = new Element('li')
                .update(i)
                .observe('click', function(){
                    this.slideshow.advance_frame(i - 1);
                    // Reset the timer to avoid jumping.
                    this.slideshow.executor.reset(); 
                }.bind(this));
            if(i == 1) selector.addClassName('active');
            return selector;
        }.bind(this));
        this.element = new Element('ul', {'class':'selector'})
            .insertCollection(this.selectors);
        
        this.effect;
        $(document).observe('cbi:slideshow:advance_frame', function(event){
            this.selectors.invoke('removeClassName', 'active');
            this.selectors[parseInt(event.memo) || 0].addClassName('active');
        }.bind(this));
        $(document).observe('cbi:slideshow:dream_vacation:shown', function(event){
            if(this.effect) this.effect.cancel();
            this.effect = new Effect.Fade(this.element, { 
                duration: .2
            });
        }.bind(this));
        $(document).observe('cbi:slideshow:dream_vacation:hidden', function(event){
            if(this.effect) this.effect.cancel();
            this.effect = new Effect.Appear(this.element, { 
                duration: .2, 
                delay: .2
            });
        }.bind(this));
    }, 
    
    toElement: function(){
        return this.element;
    }
});


CBI.Slideshow.DreamVacation = Class.create({
    initialize: function(container, options){
        this.container = $(container);
        this.options = Object.extend({
            swf:'/images/dream_vacation.swf', 
            express_install:'/images/express-install.swf', 
            xml:'/xml/dream_vacation.xml', 
            is_home: false
        }, options || {});
        
        this.element = new Element('div');
        this.container.insert({ top: 
            new Element('div', {'class':'dream-vacation'}).update(this.element) 
        });;
        
        var id = this.element.identify();
        swfobject.embedSWF(this.options.swf, id, "956", "372", "9.0.45", this.options.express_install, {
            isSubpage: (this.options.is_home)? 'false':'true', 
            dreamVacationXML: this.options.xml
        }, {
            menu:'false', 
            wmode:'transparent'
        }, {});
        this.element = $(id); // Reconnect with the real element.
    }
});


CBI.Slideshow.Data = Class.create({
    initialize: function(xml_data){
        this.data = xml_data;
        this.document = this.data.documentElement;
    }, 
    
    get_content: function(node){
        return node.textContent || node.text;
    }, 
    
    get_slides: function(){
        return $A(this.document.getElementsByTagName('jpg')).map(function(image){
            return this.get_content(image);
        }.bind(this));
    }, 
    
    get_quotes: function(){
        return $A(this.document.getElementsByTagName('quote')).map(function(quote){
            return {
                x: this.get_content(quote.attributes.getNamedItem('x')), 
                y: this.get_content(quote.attributes.getNamedItem('y')), 
                src: this.get_content(quote.getElementsByTagName('png')[0]), 
                href: this.get_content(quote.getElementsByTagName('link')[0]), 
                target: this.get_content(quote.getElementsByTagName('link')[0].attributes.getNamedItem('target'))
            };
        }.bind(this));
    }
});



