// Toggle controller for showing and hiding elements in a set. Public methods are init, next, previous and jumpTo.
// Init takes two css selectors or collections. First is the elements to toggle, second is the actuators.
// next and previous are pretty self-explanatory.
// jumpTo takes a 0-based index and makes that item active.
function Toggler(img_selector, trigger_selector) {
    var that = this;
    this.init = function init(img_selector, trigger_selector) {
        // Number of actuators must == number of elements. Otherwise, things get wonky.
        this.elements = $$(img_selector);
        this.actuators = $$(trigger_selector);
        this.currentElement = this.elements[0];
        this.index = 0;
    }
    this.init(img_selector, trigger_selector);
    this.next = function next() {
        hideAll();
        this.index = getNextIndex();
        show(this.index);
        var offset = this.actuators[0].getPosition().y-20;
        if(document.body.getScroll().y > offset) {
            document.body.scrollTo(0, offset);
        }
        // return this.index;
        return false;
    }
    this.prev = function prev() {
        hideAll();
        this.index = getPrevIndex();
        show(this.index);
        var offset = this.actuators[0].getPosition().y-20;
        if(document.body.getScroll().y > offset) {
            document.body.scrollTo(0, offset);
        }
        // return this.index;
        return false;
    }
    this.jumpTo = function jumpTo(index) {
        var cleanIndex = index.limit(0, this.elements.length-1);
        hideAll();
        this.index = cleanIndex;
        show(this.index);
        return false;
        // return this.index;
    }
    
    function hideAll() {
        that.elements.each(function(el, i){
            if(el.getStyle('display') != 'none') {
                el.setStyle('display', 'none');
                that.actuators[i].removeClass('active');
            }
        });
    }
    function show(index) {
        that.elements[index].setStyle('display', 'block');
        that.actuators[index].addClass('active');
        adjustCenter();
    }
    
    function getNextIndex() {
        if(that.index+1 >= that.elements.length) {
            return that.index;
        } else {
            return that.index+1
        }
    }
    function getPrevIndex() {
        if(that.index-1 <= 0) {
            return 0;
        } else {
            return that.index-1;
        }
    }
}

// Smoothly fade one element into another in a slideshow fashion
function Slideshow() {
    var that = this;
    this.options = {
        duration: 1000,
        delay: 3000
    }
    this.current = -1;
    this.init = function init(selector) {
        this.elements = $$(selector);
        this.elements.each(function(el, i) {
            if(i == 0) {
                el.setStyles({'opacity':0, 'display':'block'});
                // el.setStyle('display', 'block');
            } else {
                el.setStyles({'opacity':0, 'display':'block'});
            }
        });
        // this.start.delay(this.options.delay/2, this);
        this.start();
    }
    this.start = function start() {
        // Only allow one fader to run at a time
        if(this.running) this.stop();
        if(this.elements.length > this.current+1) {
            var next = this.current+1;
        } else {
            var next = 0;
        }
        // console.log(this.current)
        // Run both animations at the same time for a cross-dissolve.
        var fade_out = new Fx.Tween(this.elements[this.current], {property: 'opacity', duration: this.options.duration});
        var fade_in = new Fx.Tween(this.elements[next], {property: 'opacity', duration: this.options.duration});
        if(this.current > -1) fade_out.start(0);
        fade_in.start(1);
        adjustCenter();
        // this.elements[this.current].fade('out');
        // this.elements[next].fade('in');
        this.current = next;
        this.running = this.start.delay(this.options.delay+this.options.duration, this);
    }
    this.stop = function stop() {
        $clear(this.running);
    }
}

// Given a set of elements, apply an animation to each in turn with a staggered delay, creating a "cascade" effect.
function Cascade(opts) {
    var that = this;
    this.id = Math.random().toString().substr(4, 5);
    this.options = $merge({
        // elements: '.something',
        // morph: {'opacity': [0,1]},
        delay: 90, // 12% of duration seems to work well
        duration: 750
    }, opts);
    this.completeCounter = 0;
    
    this.init = function init() {
        this.elements = $$(this.options.elements);
        // console.log("initing "+this.id)
        this.elements.each(function(el, i) {
            var animation = function() {
                var trans = new Fx.Morph(el, {duration:that.options.duration, transition:Fx.Transitions.Linear, onComplete:that.onComplete.bind(that)});
                trans.start(that.options.morph);
            }
            el.store(that.id+'_cascade:delay', that.options.delay * i);
            el.store(that.id+'_cascade:start', animation.bind(el));
        });                                                                                                                                           
    }
    this.start = function start() {
        if(this.elements.length == 0){
            // console.log(this.id + " is empty")
            this.onComplete();
            return;
        }
        // TODO: don't start if already running.
        this.elements.each(function(el) {
            el.retrieve(that.id+'_cascade:start').delay(el.retrieve(that.id+'_cascade:delay'));
        });
    }
    this.onComplete = function onComplete() {
        if(this.elements.length > 0 && this.completeCounter < this.elements.length-1){
            this.completeCounter++;
        } else {
            // Cascade is complete
            // TODO: Make this fire immediately when elements length is 0
            if(this.complete) {
                // console.log(this.id+" complete")
                this.complete();
                // this.fireEvent('navLoaded', {cascadeId: this.id});
            }
        }
    }
    this.init();
}

function adjustCenter() {
    // Adjust content so it stays consistent when the scrollbar appears
    if(Browser.Engine.webkit){
        var scroll = document.body.scrollHeight;
    } else {
        var scroll = document.body.getScrollHeight();
    }
    if(scroll > window.getSize().y) {
        // console.log('clearing padding')
        document.body.setStyle('marginRight', '0');
    } else {
        // console.log('padding')
        // document.body.setStyle('paddingRight', '16px');
        document.body.setStyle('marginRight', '16px');
    }
}
if(!Browser.Engine.trident) {
    window.addEvent('domready', adjustCenter);
    window.addEvent('resize', adjustCenter);
}

