/* -----------------------------------------------------------------

	Script: 
		MooFlow.js v.0.2a
	
	Copyright:
		Copyright (c) 2007 Tobias Wetzel (ToBSn), <http://outcut.de/>
	
	License:
		MIT-style license
		
	ChangeLog:
		Added {
			Reflection via JS
			Load Images via JSON
			Skinable UI ['better support in progress ;)']
			onClickView Callback - returns the image width all Properties
		}
		Changed {
			Class Initialization
			....
		}
		
	Probs:
		Safari 1/2 canvas must be added to body before can paint the reflection :(
		
		....and lot of dirty code ... i know .....
	
	Tested:
		Safari 3
		Firefox
		Opera 9
		IE 6

----------------------------------------------------------------- */
var SliderEx = new Class({
    Extends: Slider,
    setEx: function(step){
        this.step = step.limit(0, this.options.steps);
		this.fireEvent('onTick', this.toPosition(this.step));
		return this;
    }
});

Fx.TweenEx = new Class({
	Extends: Fx.Tween,
	render: function(element, property, value){
		this.fireEvent('onMotionChange', value[0].value);
		element.setStyle(property, this.serve(value, this.options.unit));
	}
});

Element.implement({
	reflect: function(arg){
		var i = new Element('img').setProperty('src',arg.src);
		if (Browser.Engine.trident) {
			i.setProperties({'width':arg.width,'height':arg.height})
			i.style.filter = 'flipv progid:DXImageTransform.Microsoft.Alpha(opacity=30, style=1, finishOpacity=0, startx=0, starty=0, finishx=0, finishy='+arg.height*0.3+')';
			return i;
		} else {
			var can = new Element('canvas').setProperties({'width':arg.width, 'height':arg.height});
			if (can.getContext && !Browser.Engine.webkit419 ) {
				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 = '#110F22';
				ctx.fillRect(0, arg.height*0.5, arg.width, arg.height);
				
				var gra = ctx.createLinearGradient(0, 0, 0, arg.height*0.5);					
				gra.addColorStop(1, "rgba(255, 255, 255, 1.0)");
				gra.addColorStop(0, "rgba(255, 255, 255, "+(1-0.3)+")");
				
				ctx.fillStyle = gra;
				ctx.fillRect(0, 0, arg.width, arg.height);
			}
			return can;
		}
	}
});

var MooFlow = new Class({

	Implements: [Events, Options],
	
	options: {
		onStart: Class.empty,
		onComplete: Class.empty,
		onCancel: Class.empty,
		onClickView: Class.empty,
		main: 'MooFlow',
		reflection: 0.5,
		startIndex: 0,
		interval: 3000,
		factor: 115,
		bgColor: '#110F22',
		stylePath: 'MooFlow.css',
		useCaption: false,
		useResize: false,
		useSlider: false,
		useWindowResize: false,
		useMouseWheel: false,
		useKeyInput: false
	},
	
	initialize: function(options){
		this.setOptions(options);
		this.foc = 150;
		this.curI = this.options.startIndex;
		this.sli = null;
		this.checker = null;
		this.interval = this.options.interval;
		this.factor = this.options.factor;
		this.isFull = false;
		this.loadIdle = false;

		this.images = $(this.options.main).getChildren();

		this.master = {'images':[]};

		new Asset.css(this.options.stylePath);

		if(this.options.useWindowResize){
			window.addEvent('resize', this.update.bind(this));
		}
		if(this.options.useMouseWheel && this.options.useSlider){
			$(this.options.main).addEvent('mousewheel', this.wheelTo.bind(this));		
		}
		if(this.options.useKeyInput){
			  document.onkeydown = function(e) {
			    var dir = (e ? e : event).keyCode;
			    if(dir == 39)
			     this.next();
			    if(dir == 37)
			     this.prev();
			  }.bind(this);
		}

		var aniObj = new Element('div').inject($(this.options.main, 'bottom'));

		this.aniFx = new Fx.TweenEx(aniObj, 'left', {
			transition: Fx.Transitions.Expo.easeOut,
			duration: 750,
			onMotionChange: function(value){
				this.process(value);
			}.bind(this),
			onComplete: function(){
				
			}.bind(this)
		});
		
		this.preInit();
	},
	
	onAbort: function(error){
		$(this.options.main).getChildren().dispose();
		new Element('div').set('html', error).inject($(this.options.main));
	},
	
	loadJSON: function(src){
		if(!src || this.loadIdle) return;		
		this.loadIdle = true;
		new Request.JSON({url: src,
			onComplete: function(data){
				this.curI = 0;
				this.clearMain(data);
			}.bind(this),
			onFailure: function(data){
				this.fireEvent('onChancel', 'Can not load JSON-Data!');
			}.bind(this)
		}, this).GET();
	},
	
	preInit: function(){
		$$(this.images).each(function(obj){
			this.master['images'].push(obj.getElement('img').getProperties(
				'id', 'class', 'src', 'title', 'alt', 'longdesc', 'width', 'height'
			));
			obj.dispose();
		}, this);

		this.addLoader();
		return true;
	},
	
	clearMain: function(data){
		new Fx.Tween($('MooFlowNav'), 'bottom', {
					'onComplete' : function (){
						$('MooFlowNav').dispose();
					}
				}).start('-50');
		new Fx.Tween($('caption'), 'opacity', {
					'onComplete' : function (){
						$('caption').dispose();
					}
				}).start('0');
		$$('.imgDiv').each(function(obj){
			obj.dispose();
		});
		this.master = data;
		this.addLoader();
		return true;
	},
	
	addLoader: function(){
		$(this.options.main).store('height', '250');
		new Element('div').addClass('loader').set('id', 'loader').inject($(this.options.main));
		$(this.options.main).setStyle('visibility', 'visible').addClass('load');
		new Fx.Tween($(this.options.main), 'height', {
					duration : 1000,
					onComplete : function (){
						this.preloadImg();
					}.bind(this)
				}).start($(this.options.main).retrieve('height'));	
	},
	
	preloadImg: function(){
		var imgs = [];
		this.master['images'].each(function(src){
			imgs.push(src['src']);
		});
		var loadedImages = new Asset.images(imgs, {
		    onComplete: function(){
				new Fx.Tween($('loader'), 'opacity', {
					duration : 1000,
					onComplete : function (){
						$(this.options.main).removeClass('load');
						$('loader').dispose();
						this.init();	
					}.bind(this)
				}).start(0);		
		    }.bind(this),
			onProgress: function(counter, i){
				this.master['images'][i]['width'] = loadedImages[i].width;
				this.master['images'][i]['height'] = loadedImages[i].height;
				$('loader').set('html', (counter+1) + ' / ' + imgs.length);
			}.bind(this)
		}, this);
	},
	
	init: function(){
		this.iL = this.master['images'].length-1;
		this.master['images'].each(function(image, i){
			var div = new Element('div').addClass('imgDiv').setStyles({
				'display':'none',
				'height':'100%',
				'background-color': this.options.bgColor
			});
			var img = new Element('img').setProperties({
				'src': image.src,
				'width': image.width,
				'height': image.height
			}).setStyles({'display':'block'}).inject(div);
			
			var ref = new Element('img').setStyles({'display':'block'}).reflect({
				'src': image.src,
				'ref': this.options.reflection,
				'height': image.height,
				'width': image.width
			}).inject(div);
			
			img.addEvent('click', this.clickTo.bind(this,[i]));
			img.addEvent('dblclick', this.showImage.bind(this, [img, i]));
			
			div.inject($(this.options.main));
			
			this.master['images'][i]['div'] = div;
			this.master['images'][i]['img'] = img;
			this.master['images'][i]['ref'] = ref;
			
		}, this);
		this.createElements();
		return true;
	},
	
	createElements: function(){
	/*
		if(this.options.useCaption){
			var cap = new Element('div').addClass('caption').setProperty('id','caption').set('opacity','0');
			$(this.options.main).adopt(cap);
			new Fx.Tween(cap, 'opacity').start('0', '1');
		}
		var nav = new Element('div').addClass('MooFlowNav').setProperty('id','MooFlowNav').setStyle('bottom', '-75');
		var autoPlayCon = new Element('div').addClass('autoPlayCon');
		if(this.options.useAutoPlay){
			var play = new Element('a').addClass('play').addEvent('click', this.play.bind(this));
			var stop = new Element('a').addClass('stop').addEvent('click', this.stop.bind(this));
			autoPlayCon.adopt(stop, play);
		}
		var sliderCon = new Element('div').addClass('sliderCon');
		var prev = new Element('a').addClass('sliderNext').setProperty('id','prev');
		var next = new Element('a').addClass('sliderPrev').setProperty('id','next');
		var slider = new Element('div').addClass('slider').setProperty('id','slider');
		var knob = new Element('div').addClass('knob').setProperty('id','knob');
		knob.adopt(new Element('div').addClass('knobleft'));
		slider.adopt(knob);
		sliderCon.adopt(prev,slider,next);
		var resizeCon = new Element('div').addClass('resizeCon');
		if(this.options.useResize){
			var resize = new Element('a').addClass('resize').setProperty('id','resize');
			resize.addEvent('click', this.setScreen.bind(this));
			resizeCon.adopt(resize);
		}
		nav.adopt(autoPlayCon,sliderCon,resizeCon);
		$(this.options.main).adopt(nav);

		

		slider.store('parentWidth', sliderCon.getSize().x-prev.getSize().x-next.getSize().x);
		*/
		this.fireEvent('onStart');
		this.loadIdle = false;
		this.update();
		this.autoPlay = this.auto.periodical(this.interval, this);
	},
	update: function(){
		this.oW = $(this.options.main).getSize().x;
		this.sz = this.oW * 0.5;
		if(this.options.useSlider){	
			$('slider').setStyle('width',$('slider').getParent().getSize().x-$('prev').getSize().x-$('next').getSize().x);
			$('knob').setStyles({'width':($('slider').getSize().x/this.iL)});
			this.sli = new SliderEx($('slider'), $('knob'),{
				steps: this.iL
			}).set(this.curI);
			this.sli.addEvent('onChange', this.glideTo.bind(this));
			$('next').addEvent('click', this.next.bind(this));
			$('prev').addEvent('click', this.prev.bind(this));
		}
		this.process(this.curI*-this.foc);
		this.glideTo(this.curI);
	},
	setScreen: function(){
		// need real coordinates
		this.isFull = !this.isFull;
		if(this.isFull){
			$(this.options.main).setStyles({'position':'absolute','top':'0','left':'0','width':window.getSize().x,'height':window.getSize().y});
			if(this.options.useWindowResize){
				window.addEvent('resize', this.initResize.bind(this));
			}
		} else {
			window.removeEvent('resize', this.initResize);
			$(this.options.main).setStyles({'position':'relative','top':'','left':'','width':'','height':$(this.options.main).retrieve('height')});
			$('slider').setStyle('width',$('slider').retrieve('parentWidth'));
		}
		this.update();
	},
	initResize: function(){
		//$(this.options.main).setStyles({'position':'absolute','top':'0','left':'0','width':window.getSize().x,'height':window.getSize().y});
		//this.update();
	},
	showImage: function(el, index){
		if(this.curI != index) return;
		var copy = el.clone().erase('style').removeEvents().setProperties({
			'alt': this.master['images'][index].alt,
			'title': this.master['images'][index].title,
			'longdesc': this.master['images'][index].longdesc
		});
		this.fireEvent('onClickView', copy);
	},
	prev: function(){
		if(this.curI > 0)
			this.curI--;this.clickTo(this.curI);
	},
	stop: function(){
		$clear(this.autoPlay);
		return true;
	},
	play: function(){
		this.autoPlay = this.auto.periodical(this.interval, this);
	},
	auto: function(){
		if(this.curI < this.iL){
			this.next();
		} else if(this.curI == this.iL){
			this.curI=0;this.clickTo(this.curI);
		}
	},
	next: function(){
		if(this.curI < this.iL)
			this.curI++;this.clickTo(this.curI);
	},
	keyTo: function(e){
		e = new Event(e)
		switch (e.code){
			case 37:
				this.prev();
				break;
			case 39:
				this.next();
				break;
		}
		e.stop();
	},
	wheelTo: function(e){
		var e = new Event(e)		
		var d = e.wheel;
		if(e.preventDefault) e.preventDefault();		
		if(d > 0) this.prev();
		if(d < 0) this.next();
		
		e.stop();
	},
	clickTo: function(i){
		if(this.options.useSlider){
			this.sli.setEx(i);
		}
		this.glideTo(i);
	},
	glideTo: function(i){
		this.aniFx.cancel();
		this.curI = i;
		if(this.options.useCaption){
			$('caption').set('html', this.master['images'][this.curI]['title']);
		}
		this.aniFx.start(i*-this.foc);
	},
	process: function(x){
		var zI = this.iL, z, newW, newH, newL, newT;
		this.master['images'].each(function(el){
			if(x<-this.foc*5||x>this.foc*5)
			el.div.setStyle('display','none');	
			else el.div.setStyle('display','block');
			
			z = Math.sqrt(10000 + x * x) + 100;
			newL = Math.round(((x / z * this.sz) + this.sz) - (this.factor * 0.5) / z * this.sz);
			newH = Math.round((el.height / el.width * this.factor) / z * this.sz);
			newT = Math.round(this.oW * 0.4 - newH);
			if(newH > el.width * 0.51)
			newW = Math.round(this.factor / z * this.sz);
			else  Math.round(newW = el.width * newH / el.height);
			
			el.img.setStyle('width', newW);
			el.img.setStyle('height', newH);
			el.ref.setStyle('width', newW);
			el.ref.setStyle('height', newH);
			el.div.setStyle('left', newL);
			el.div.setStyle('top', newT);				
			el.div.setStyle('zIndex', x < 0 ? zI++ : zI--);		
			x += this.foc;
		}, this);
	}
});