/*
Script: RokFlow.js

Author: 
        Olmo Maldonado, <http://olmo-maldonado.com/>

License:
        MIT
*/

var RokFlow = new Class({
        
        options: {
                show: 5,
                mouseAcceleration: Fx.Transitions.Cubic.easeIn,
                constantAt: 0,
                rate: 50,
                arrows: false,
                loader: 'loader',
                RokBox: true,
                flow: {
                        shrink: 0.25,
                        spacing: 25,
                        duration: 1000
                }
        },
        
        initialize: function(holder, options) {
                this.setOptions(options);
                
                if(this.options.loader) $(this.options.loader).remove();
                this.holder = $(holder).setStyle('background-image', 'none');                
                
                this.build();
                
                this.flow = new Fx.Flow(this.container.getFirst(), $merge(this.options.flow, {
                        RokBox: this.options.RokBox 
                })).moveTo(1, this.options.show);
                
                this.setEvents();
        },
        
        build: function() {
                this.middle = this.holder.getCoordinates().left + this.holder.offsetWidth / 2;
                this.max = this.compute(this.options.constantAt);
                this.options.rate *= (window.webkit) ? 0.5 : 1;
                
                var children = this.holder.getChildren();
                var trash;
                children.each(function(el) {
                        trash = new Element('h3').setHTML(el.getElement('img').title || '&nbsp;').injectTop(el);
                });
                
                this.container = new Element('div').setStyles({
                        'width': this.holder.offsetWidth,
                        'height': this.holder.offsetHeight,
                        'overflow': 'hidden'
                }).adopt(new Element('div').adopt(children)).inject(this.holder);
                
                this.holder.setStyles({
                        'overflow': 'hidden',
                        'cursor': 'default'
                });
                
                this.buildArrows();
        },
        
        setEvents: function() {
                this.moveEvents = {
                        mousemove: function(e) {
                                e = new Event(e);
                                this.flow.move(((e.client.x < this.middle) ? 1 : -1) * (this.options.rate * this.compute(e.client.x).limit(0, this.max)) | 0);
                                
                                if(this.delay) $clear(this.delay);
                                this.delay = (function() {
                                        this.container.fireEvent('mousemove', [e]);
                                }).delay(30, this);
                        }.bind(this),
                        
                        mouseleave: function() {
                                $clear(this.delay);
                        }.bind(this)
                };
                
                this.container.addEvents(this.moveEvents);
                
                if(this.options.arrows) {
                        this.larrow.addEvents({
                                'click': this.flow.moveLeft.bind(this.flow),                        
                                'mouseenter': function() {
                                        if(!this.hasClass('hover')) this.addClass('hover');
                                },
                                'mouseleave': function() {
                                        if(this.hasClass('hover')) this.removeClass('hover');        
                                }
                        });
                        
                        this.rarrow.addEvents({
                                'click': this.flow.moveRight.bind(this.flow),
                                'mouseenter': function() {
                                        if(!this.hasClass('hover')) this.addClass('hover');
                                },
                                'mouseleave': function() {
                                        if(this.hasClass('hover')) this.removeClass('hover');        
                                }
                        });
                }
                
                if(this.options.flow.RokBox && RokBox) {
                        RokBox.addEvents({
                                'onClick': function() {
                                        this.container.removeEvent('mousemove', this.moveEvents.mousemove);
                                }.bind(this),
                                
                                'onClose': function() {
                                        this.container.addEvent('mousemove', this.moveEvents.mousemove);
                                }.bind(this)
                        });
                }
        },
        
        compute: function(pos) {
                return this.options.mouseAcceleration(Math.abs(pos - this.middle) / this.middle);
        },
        
        buildArrows: function() {
                if(this.options.arrows) {
                        this.larrow = new Element('div', {
                                'class': 'arrow left'
                        }).adopt(
                                new Element('a', {
                                        'href': '#'
                                }).setHTML('&larr')
                        ).injectTop(this.holder);
                        
                        this.rarrow = this.larrow.clone().set({ 'class': 'arrow right' }).inject(this.holder);
                        this.holder.adopt(new Element('div', { styles: { clear: 'both' }}));
                        this.rarrow.getElement('a').setHTML('&rarr;');
                        this.container.setStyles({
                                'width': this.holder.offsetWidth - 2 * this.larrow.offsetWidth
                        });
                }
        }
        
});

RokFlow.implement(new Options, new Events);

Fx.Flow = Fx.Elements.extend({
        
        options: {
                RokBox: false,
                shrink: 0.50,
                offset: 60,
                axis: 0.5,
                spacing: 25,
                transition: Fx.Transitions.linear,
                wait: false
        },
        
        initialize: function(el, options) {
                this.options = $merge(this.options, options);
                
                this.container = el.getParent();
                this.count = el.childNodes.length;
                
                this.setup(el, options);
                
                this.lefts = [];
                this.elements.each(function(el, i) {
                        this.lefts[i] = (this.elements[1].getLast().offsetLeft + this.elements[1].getLast().offsetWidth) * (i - 1);
                        el.set({
                                id: 'flow-' + i,
                                styles :{
                                        'position': 'absolute',
                                        'left': this.lefts[i]
                                }
                        });
                }, this);
                
                this.middle = this.container.offsetWidth / 2;
                this.right = this.container.offsetLeft + this.container.offsetWidth;
                this.move(0);
                
                this.current = [1,0];
        },
        
        setup: function(el, options) {
                this.min = [];
                this.diff = [];
                this.imgs = el.getElements('img');
                this.imgWidth = this.imgs[0].offsetWidth;
                
                this.imgs.each(function(img, i) {
                        var max = {
                                'width': img.offsetWidth,
                                'height': img.offsetHeight
                        };
                        
                        this.min[i] = {
                                width: max.width * this.options.shrink,
                                height: max.height * this.options.shrink
                        };
                        
                        this.diff[i] = {
                                width: max.width - this.min[i].width,
                                height: max.height - this.min[i].height
                        };
                        img.setStyles(this.min[i]);
                }, this);
                
                this.divs = el.getChildren();
                this.count = this.divs.length;
                
                this.divs.each(function(child, i) {
                        child.setStyles({
                                'position': 'absolute',
                                'left': child.offsetWidth * i,
                                'top':  this.container.offsetHeight * this.options.axis - child.offsetHeight / 2 + 0.5 * this.options.offset
                        });
                }, this);
                
                this.elements = [el, el.clone(), el.clone()];
                this.container.adopt(this.elements[1], this.elements[2]);
                this.parent(this.elements, options);
                this.spacing();        
                
                this.imgs.each(function(img, i) {
                        this.min[i].left = img.offsetLeft;
                        this.min[i].top = el.childNodes[i].offsetTop;
                }, this);
                
                if(this.options.RokBox && RokBox) {
                        this.container.getElements('a').each(function(a) {
                                a.rel = 'rokbox';
                        });
                        
                        //RokBox.getLinks();
                }
        },
        
        moveTo: function(index, to) {
                var that = this,
                        parsed = {},
                        divs = this.elements[index].childNodes,
                        by = this.middle - (this.elements[index].offsetLeft + divs[to].offsetLeft + 0.5 * (this.diff[to].width + this.min[to].width));
                        
                (3).times(function(i) {
                        parsed[i] = {
                                left: [ that.elements[i].offsetLeft, that.elements[i].offsetLeft + by]
                        };
                });
                
                this.start(parsed);
                this.current = [index, to];
                
                return this;
        },
        
        moveLeft: function() {
                this.current[1]--;
                if(this.current[1] < 0) {
                        this.current[1] += this.count;
                
                }
                
                return this.moveTo.apply(this, this.current);
        },
        
        moveRight: function() {
                this.current[1]++;
                if(this.current[1] >= this.count) {
                        this.current[1] -= this.count;
                
                }
                
                return this.moveTo.apply(this, this.current);        
        },
        
        move: function(by) {
                var parsed = {},
                        that = this;
                        
                (3).times(function(i) {
                        parsed[i] = {
                                left: that.elements[i].offsetLeft + (isNaN(by) ? 0 : by)
                        };
                });
                
                this.set(parsed);
        },
        
        reset: function() {
                var parsed = {},
                        that = this;
                        
                (3).times(function(i) {
                        parsed[i] = {
                                left: that.lefts[i]
                        };
                });
                
                this.set(parsed);
        },
        
        increase: function() {
                this.parent();
                
                this.carousel();
                this.grow();
                this.spacing();
        },
        
        carousel: function() {
                var div,
                        left = 1.5 * this.elements[0].offsetLeft + 0.5 * (this.elements[0].getLast().offsetLeft + this.elements[0].getLast().offsetWidth),
                        right = 1.5 * this.elements[2].offsetLeft + 0.5 * (this.elements[2].getLast().offsetLeft + this.elements[2].getLast().offsetWidth);
                
                if(left > this.container.offsetLeft) {
                        div = this.elements.pop();
                        div.setStyle('left', this.elements[0].offsetLeft - div.getLast().offsetLeft + div.getLast().offsetWidth);
                        this.elements = [div].concat(this.elements);
                        
                } else if(right < this.right) {
                        div = this.elements.shift();
                        div.setStyle('left', this.elements[1].offsetLeft + length);
                        this.elements.push(div);
                }        
        },
        
        grow: function() {
                var        growth,
                        changeX,
                        changeY,
                        divs,
                        curPos,
                        off = (this.elements[1].offsetLeft < 0) ? 1 : 0,
                        that = this;
                        
                (2).times(function(i) {
                        i += off;
                        divs = that.elements[i].childNodes;
                        
                        that.elements[i].getElements('img').each(function(img, j) {
                                curPos = that.elements[i].offsetLeft + divs[j].offsetLeft + img.offsetWidth / 2;
                                
                                if(curPos > 0 && curPos < that.right) {
                                        growth = that.growth(curPos);
                                        changeX = that.diff[j].width * growth;
                                        changeY = that.diff[j].height * growth;
                                        
                                        img.setStyles({
                                                'width': that.min[j].width + changeX, 
                                                'height': that.min[j].height + changeY
                                        });
                                        
                                        divs[j].setStyles({
                                                'left': that.min[j].left - changeX / 2,
                                                'top': that.min[j].top - changeY / 2
                                        });
                                        
                                        divs[j].getElement('h3').setStyles({
                                                'width': that.min[j].width + changeX
                                        });
                                        
                                }
                        });
                });        
        },
        
        spacing: function() {
                var divs,
                that = this;
                var B, A, D;
                (3).times(function (i) {
                        divs = that.elements[i].childNodes;
                        that.elements[i].getElements('img').each(function(img, j) {
                                A = divs[j];
                                
                                if(j > 0) {        
                                        B = divs[j - 1];
                                        B.setStyles({
                                                'left': A.offsetLeft - (that.options.spacing + B.offsetWidth)
                                        });
                                }        
                                
                                if(j < that.count - 1) {
                                        D = divs[j + 1];
                                        D.setStyles({
                                                'left': that.options.spacing + A.offsetLeft + A.offsetWidth
                                        });
                                }
                        });
                });
                
                B = this.elements[0];
                A = this.elements[1];
                D = this.elements[2];
                
                B.setStyles({
                        'left': A.offsetLeft - (2 * that.options.spacing + B.getLast().offsetLeft + B.getLast().offsetWidth)
                });
                
                D.setStyles({
                        'left': A.offsetLeft + 2 * that.options.spacing + A.getLast().offsetLeft + A.getLast().offsetWidth
                });
                
        },
        
        growth: function(pos) {
                return ((pos < this.middle) ?  
                        this.options.transition(pos / this.middle) : 
                        1 - this.options.transition((pos - this.middle) / this.middle)).limit(0, Infinity);
        }
                
});
