/**
 * MooFlow - Image gallery
 *
 * Dependencies: MooTools 1.2
 *
 * @version			0.2.1
 *
 * @license			MIT-style license
 * @author			Tobias Wetzel <info [at] outcut.de>
 * @copyright		Author
 * @docmentation	http://outcut.de/MooFlow/Docmentation.html
 */ 

var MooFlow = new Class({

    Implements: [Events, Options],
	
    options: {
        onStart: $empty,
        onClickView: $empty,
        onAutoPlay: $empty,
        onAutoStop: $empty,
        onRequest: $empty,
        onResized: $empty,
        onEmptyinit: $empty,
        reflection: 0.4,
        heightRatio: 0.6,
        offsetY: 0,
        startIndex: 1,
        interval: 3000,
        factor: 145,
        bgColor: '#000',
        useCaption: false,
        useResize: false,
        useSlider: false,
        useWindowResize: false,
        useMouseWheel: true,
        useKeyInput: false,
        useViewer: false
    },
	
    initialize: function(element, options){
        this.MooFlow = element;
        this.setOptions(options);
        this.foc = 150;
        this.factor = this.options.factor;
        this.offY = this.options.offsetY;
        this.isFull = false;
        this.isAutoPlay = false;
        this.isLoading = false;
        this.inMotion = false;
		
        this.MooFlow.addClass('mf').setStyles({
            'overflow':'hidden',
            'background-color':this.options.bgColor,
            'position':'relative',
            'height':this.MooFlow.getSize().x*this.options.heightRatio,
            'opacity':0
        });
		
        if(this.options.useWindowResize) window.addEvent('resize', this.update.bind(this, 'init'));
        if(this.options.useMouseWheel || this.options.useSlider) this.MooFlow.addEvent('mousewheel', this.wheelTo.bind(this));
        if(this.options.useKeyInput) document.addEvent('keydown', this.keyTo.bind(this));
		
        this.getElements(this.MooFlow);
    },
	
    clearInit: function(){
        this.fireEvent('emptyinit');
    },
	
    getElements: function(el){
        this.master = {
            'images':[]
        };
        var els = el.getChildren();
        if(!els.length) {
            this.clearInit();
            return;
        }
        $$(els).each(function(el){
            var hash = $H(el.getElement('img').getProperties('src','title','alt','longdesc'));
            if(el.get('tag') == 'a') hash.combine(el.getProperties('href','rel','target'));
            this.master['images'].push(hash.getClean());
            el.dispose();
        }, this);
        this.clearMain();
    },
	
    clearMain: function(){
        if(this.cap){
            this.cap.fade(0);
        }
        if(this.nav){
            new Fx.Tween(this.nav, {
                'onComplete': function(){
                    this.MooFlow.empty();
                    this.createAniObj();
                }.bind(this)
            }).start('bottom', -50);
        }
        if(!this.nav && !this.cap){
            this.MooFlow.empty();
            this.createAniObj();
        }
    },
	
    getMooFlowElements: function(key){
        var els = [];
        this.master.images.each(function(el){
            els.push(el[key]);
        });
        return els;
    },
	
    createAniObj: function(){
        this.aniFx = new Fx.Value({
            'transition': Fx.Transitions.Expo.easeOut,
            'link': 'cancel',
            'duration': 750,
            onMotion: this.process.bind(this),
            'onStart': this.flowStart.bind(this),
            'onComplete': this.flowComplete.bind(this)
        });
        this.addLoader();
    },
	
    addLoader: function(){
        this.MooFlow.store('height', this.MooFlow.getSize().y);
        this.loader = new Element('div',{
            'class':'loader'
        }).inject(this.MooFlow);
        new Fx.Tween(this.MooFlow, {
            'duration': 800,
            'onComplete': this.preloadImg.bind(this)
        }).start('opacity', 1);
    },
	
    preloadImg: function(){
        this.loadedImages = new Asset.images(this.getMooFlowElements('src'), {
            'onComplete': this.loaded.bind(this),
            'onProgress': this.createMooFlowElement.bind(this)
        });
    },
	
    createMooFlowElement: function(counter, i){
        var obj = this.getCurrent(i);
        var img = this.loadedImages[i];
        obj['width'] = img.width;
        obj['height'] = img.height;
        img.removeProperties('width','height');

        obj['div'] = new Element('div').setStyles({
            'position':'absolute',
            'display':'none',
            'height': this.MooFlow.getSize().y
        }).inject(this.MooFlow);
        obj['con'] = new Element('div').inject(obj['div']);
        img.setStyles({
            'vertical-align':'bottom',
            'width':'100%',
            'height':'50%'
        });
        img.addEvents({
            'click': this.clickTo.bind(this, i),
            'dblclick': this.viewCallBack.bind(this, i)
            });
        img.inject(obj['con']);
		
        new Element('div').reflect({
            'img': img,
            'ref': this.options.reflection,
            'height': obj.height,
            'width': obj.width,
            'color': this.options.bgColor
        }).setStyles({
            'width':'100%',
            'height':'50%',
            'background-color': this.options.bgColor
            }).inject(obj['con']);
		
        this.loader.set('text', (counter+1) + ' / ' + this.loadedImages.length);
    },
	
    loaded: function(){
        this.index = this.options.startIndex;
        this.iL = this.master.images.length-1;
        new Fx.Tween(this.loader, {
            'duration': 800,
            'onComplete': this.createUI.bind(this)
        }).start('opacity', 0);
    },
	
    createUI: function(){
        this.loader.dispose();
        if(this.options.useCaption){
            this.cap = new Element('div').addClass('caption').set('opacity',0).inject(this.MooFlow);
        }
        this.nav = new Element('div').addClass('mfNav').setStyle('bottom','-50px');
        this.autoPlayCon = new Element('div').addClass('autoPlayCon');
        this.sliderCon = new Element('div').addClass('sliderCon');
        this.resizeCon = new Element('div').addClass('resizeCon');
        if(this.options.useAutoPlay){
            this.autoPlayCon.adopt(
                new Element('a',{
                    'class':'stop',
                    'events': {
                        'click':this.stop.bind(this)
                        }
                    }),
            new Element('a',{
                'class':'play',
                'events': {
                    'click':this.play.bind(this)
                    }
                })
        );
}
if(this.options.useSlider){
    this.sliPrev = new Element('a',{
        'class':'sliderNext',
        'events': {
            'click':this.prev.bind(this)
            }
        });
this.sliNext = new Element('a',{
    'class':'sliderPrev',
    'events': {
        'click':this.next.bind(this)
        }
    });
this.knob = new Element('div',{
    'class':'knob'
});
this.knob.adopt(new Element('div',{
    'class':'knobleft'
}));
this.slider = new Element('div',{
    'class':'slider'
}).adopt(this.knob);
this.sliderCon.adopt(this.sliPrev,this.slider,this.sliNext);
this.slider.store('parentWidth', this.sliderCon.getSize().x-this.sliPrev.getSize().x-this.sliNext.getSize().x);
}
if(this.options.useResize){
    this.resizeCon.adopt(new Element('a',{
        'class':'resize',
        'events': {
            'click':this.setScreen.bind(this)
            }
        }));
}		
this.MooFlow.adopt(this.nav.adopt(this.autoPlayCon, this.sliderCon, this.resizeCon));	
this.showUI();
},
	
showUI: function(){
    if(this.cap) this.cap.fade(1);
    this.nav.tween('bottom', 20);
    this.fireEvent('start');
    this.update();
},
	
update: function(e){
    if(e == 'init') return;
    this.oW = this.MooFlow.getSize().x;
    this.sz = this.oW * 0.5;
    if(this.options.useSlider){
        this.slider.setStyle('width',this.slider.getParent().getSize().x-this.sliPrev.getSize().x-this.sliNext.getSize().x-1);
        this.knob.setStyle('width',(this.slider.getSize().x/this.iL));
        this.sli = new SliderEx(this.slider, this.knob, {
            steps: this.iL
            }).set(this.index);
        this.sli.addEvent('onChange', this.glideTo.bind(this));
    }
    this.glideTo(this.index);
    this.isLoading = false;
},
	
setScreen: function(){
    if(this.isFull = !this.isFull){
        this.holder = new Element('div').inject(this.MooFlow,'after');
        this.MooFlow.wraps(new Element('div').inject(document.body));
        this.MooFlow.setStyles({
            'position':'absolute',
            'z-index':'100',
            'top':'0',
            'left':'0',
            'width':window.getSize().x,
            'height':window.getSize().y
            });
        if(this.options.useWindowResize){
            this._initResize = this.initResize.bind(this);
            window.addEvent('resize', this._initResize);
        }
    } else {
        this.MooFlow.wraps(this.holder);
        window.removeEvent('resize', this._initResize);
        delete this.holder, this._initResize;
        this.MooFlow.setStyles({
            'position':'relative',
            'z-index':'',
            'top':'',
            'left':'',
            'width':'',
            'height':this.MooFlow.retrieve('height')
            });
        this.slider.setStyle('width',this.slider.retrieve('parentWidth'));
    }
    this.fireEvent('resized', this.isFull);
    this.update();
},
	
initResize: function(){
    this.MooFlow.setStyles({
        'width':window.getSize().x,
        'height':window.getSize().y
        });
    this.update();
},
	
getCurrent: function(index){
    return this.master.images[$chk(index) ? index : this.index];
},
	
loadJSON: function(url){
    if(!url || this.isLoading) return;
    this.isLoading = true;
    new Request.JSON({
        'onComplete': function(data){
            if($chk(data)){
                this.master = data;
                this.clearMain();
                this.fireEvent('request', data);
            }
        }.bind(this)
    }, this).get(url);
},
	
loadHTML: function(url, filter){
    if(!url || !filter || this.isLoading) return;
    this.isLoading = true;
    new Request.HTML({
        'onSuccess': function(tree, els, htm){
            var result = new Element('div', {
                'html': htm
            }).getChildren(filter);
            this.getElements(result);
            this.fireEvent('request', result);
        }.bind(this)
    }, this).get(url);
},
	
flowStart: function(){
    this.inMotion = true;
},
	
flowComplete: function(){
    this.inMotion = false;
},
	
viewCallBack: function(index){
    if(this.index != index || this.inMotion) return;
    var el = $H(this.getCurrent());
    var returnObj = {};
    returnObj['coords'] = el.div.getElement('img').getCoordinates();
    el.each(function(v, k){
        if($type(v) == 'number' || $type(v) == 'string') returnObj[k] = v;
    }, this);
    this.fireEvent('clickView', returnObj);
},
prev: function(){
    if(this.index > 0) this.clickTo(this.index-1);
},
next: function(){
    if(this.index < this.iL) this.clickTo(this.index+1);
},
stop: function(){
    $clear(this.autoPlay);
    this.isAutoPlay = false;
    this.fireEvent('autoStop');
},
play: function(){
    this.autoPlay = this.auto.periodical(this.options.interval, this);
    this.isAutoPlay = true;
    this.fireEvent('autoPlay');
},
auto: function(){
    if(this.index < this.iL) this.next();
    else if(this.index == this.iL) this.clickTo(0);
},
keyTo: function(e){
    switch (e.code){
        case 37:
            e.stop();
            this.prev();
            break;
        case 39:
            e.stop();
            this.next();
    }
},
wheelTo: function(e){
    if(e.wheel > 0) this.prev();
    if(e.wheel < 0) this.next();
    e.stop().preventDefault();
},
clickTo: function(index){
    if(this.index == index) return;
    //this.aniFx.cancel();
    if(this.sli) this.sli.set(index);
    this.glideTo(index);
},
glideTo: function(index){
    this.index = index;
    this.aniFx.start(this.aniFx.get(), index*-this.foc);
    if(this.cap) this.cap.set('html', this.getCurrent().title);
},
process: function(x){
    var z,W,H,zI=this.iL,foc=this.foc,f=this.factor,sz=this.sz,oW=this.oW,offY=this.offY,div,elh,elw;
    this.master.images.each(function(el){
        div = el.div.style;
        elw = el.width;
        elh = el.height;
        if(x>-foc*6 && x<foc*6){
            with (Math) {
                z = sqrt(10000 + x * x) + 100;
                H = round((elh / elw * f) / z * sz);
                W = round(elw * H / elh);
                if(H >= elw * 0.5) {
                    W = round(f / z * sz);
                }
                div.left = round(((x / z * sz) + sz) - (f * 0.5) / z * sz) + 'px';
                div.top = round(oW * 0.4 - H) + offY + 'px';
                }
            el.con.style.height = H*2 + 'px';
            div.width = W + 'px';
            div.zIndex = x < 0 ? zI++ : zI--;
            div.display = 'block';
        } else {
            div.display = 'none';
        }
        x += foc;
    });
}
});

var SliderEx = new Class({
    Extends: Slider,
    set: function(step){
        this.step = Math.round(step);
        this.fireEvent('tick', this.toPosition(this.step));
        return this;
    },
    clickedElement: function(event){
        var dir = this.range < 0 ? -1 : 1;
        var position = event.page[this.axis] - this.element.getPosition()[this.axis] - this.half;
        position = position.limit(-this.options.offset, this.full -this.options.offset);
        this.step = Math.round(this.min + dir * this.toStep(position));
        this.checkStep();
        this.fireEvent('tick', position);
    }
});

Fx.Value = new Class({
    Extends: Fx,
    compute: function(from, to, delta){
        this.value = Fx.compute(from, to, delta);
        this.fireEvent('motion', this.value);
        return this.value;
    },
    get: function(){
        return this.value || 0;
    }
});

Element.implement({
    reflect: function(arg){
        if(Browser.Engine.trident){
            var i = arg.img.cloneNode(true);
            i.style.filter = 'flipv progid:DXImageTransform.Microsoft.Alpha(opacity=20,style=1,finishOpacity=0,startx=0,starty=0,finishx=0,finishy='+100*arg.ref+')';
            i.setStyles({
                'width':'100%',
                'height':'100%'
            });
            return new Element('div').adopt(i);
        } else {
            var i = arg.img.clone();
            var can = new Element('canvas').setProperties({
                'width':arg.width,
                'height':arg.height
                });
            if(can.getContext){
                var ctx = can.getContext("2d");
                ctx.save();
                ctx.translate(0,arg.height-1);
                ctx.scale(1,-1);
                ctx.drawImage(i, 0, 0, arg.width, arg.height);
                ctx.restore();
                ctx.globalCompositeOperation = "destination-out";
                ctx.fillStyle = arg.color;
                ctx.fillRect(0, arg.height*0.5, arg.width, arg.height);
                var gra = ctx.createLinearGradient(0, 0, 0, arg.height*arg.ref);
                gra.addColorStop(1, "rgba(255, 255, 255, 1.0)");
                gra.addColorStop(0, "rgba(255, 255, 255, "+(1-arg.ref)+")");
                ctx.fillStyle = gra;
                ctx.rect(0, 0, arg.width, arg.height);
                ctx.fill();
                delete ctx, gra;
            }
            return can;
        }
    }
});

window.addEvent('domready', function(){
    $$('.MooFlowieze').each(function(mooflow){
        new MooFlow(mooflow);
    });
});
