/*
Script: Floom.js
	Floom - MooTools-based blinds slideshow

Version: 
	1.0

License:
	MIT-style license.

Copyright:
	Copyright (c) 2009 [Oskar Krawczyk](http://nouincolor.com/).

Dependencies:
	- MooTools-core 1.2.1 or higher [mootools-core.js](http://www.mootools.net/core/)
	- MooTools-more 1.2.2.1 or higher [mootools-more.js](http://www.mootools.net/more/)
*/

//MooTools More, <http://mootools.net/more>. Copyright (c) 2006-2009 Aaron Newton <http://clientcide.com/>, Valerio Proietti <http://mad4milk.net> & the MooTools team <http://mootools.net/developers>, MIT Style License.

MooTools.More={version:"1.2.3.1"};(function(){var a={language:"en-US",languages:{"en-US":{}},cascades:["en-US"]};var b;MooTools.lang=new Events();$extend(MooTools.lang,{setLanguage:function(c){if(!a.languages[c]){return this;
}a.language=c;this.load();this.fireEvent("langChange",c);return this;},load:function(){var c=this.cascade(this.getCurrentLanguage());b={};$each(c,function(e,d){b[d]=this.lambda(e);
},this);},getCurrentLanguage:function(){return a.language;},addLanguage:function(c){a.languages[c]=a.languages[c]||{};return this;},cascade:function(e){var c=(a.languages[e]||{}).cascades||[];
c.combine(a.cascades);c.erase(e).push(e);var d=c.map(function(f){return a.languages[f];},this);return $merge.apply(this,d);},lambda:function(c){(c||{}).get=function(e,d){return $lambda(c[e]).apply(this,$splat(d));
};return c;},get:function(e,d,c){if(b&&b[e]){return(d?b[e].get(d,c):b[e]);}},set:function(d,e,c){this.addLanguage(d);langData=a.languages[d];if(!langData[e]){langData[e]={};
}$extend(langData[e],c);if(d==this.getCurrentLanguage()){this.load();this.fireEvent("langChange",d);}return this;},list:function(){return Hash.getKeys(a.languages);
}});})();Fx.Elements=new Class({Extends:Fx.CSS,initialize:function(b,a){this.elements=this.subject=$$(b);this.parent(a);},compute:function(g,h,j){var c={};
for(var d in g){var a=g[d],e=h[d],f=c[d]={};for(var b in a){f[b]=this.parent(a[b],e[b],j);}}return c;},set:function(b){for(var c in b){var a=b[c];for(var d in a){this.render(this.elements[c],d,a[d],this.options.unit);
}}return this;},start:function(c){if(!this.check(c)){return this;}var h={},j={};for(var d in c){var f=c[d],a=h[d]={},g=j[d]={};for(var b in f){var e=this.prepare(this.elements[d],b,f[b]);
a[b]=e.from;g[b]=e.to;}}return this.parent(h,j);}});var Accordion=Fx.Accordion=new Class({Extends:Fx.Elements,options:{display:0,show:false,height:true,width:false,opacity:true,fixedHeight:false,fixedWidth:false,wait:false,alwaysHide:false,trigger:"click",initialDisplayFx:true},initialize:function(){var c=Array.link(arguments,{container:Element.type,options:Object.type,togglers:$defined,elements:$defined});
this.parent(c.elements,c.options);this.togglers=$$(c.togglers);this.container=document.id(c.container);this.previous=-1;if(this.options.alwaysHide){this.options.wait=true;
}if($chk(this.options.show)){this.options.display=false;this.previous=this.options.show;}if(this.options.start){this.options.display=false;this.options.show=false;
}this.effects={};if(this.options.opacity){this.effects.opacity="fullOpacity";}if(this.options.width){this.effects.width=this.options.fixedWidth?"fullWidth":"offsetWidth";
}if(this.options.height){this.effects.height=this.options.fixedHeight?"fullHeight":"scrollHeight";}for(var b=0,a=this.togglers.length;b<a;b++){this.addSection(this.togglers[b],this.elements[b]);
}this.elements.each(function(e,d){if(this.options.show===d){this.fireEvent("active",[this.togglers[d],e]);}else{for(var f in this.effects){e.setStyle(f,0);
}}},this);if($chk(this.options.display)){this.display(this.options.display,this.options.initialDisplayFx);}},addSection:function(d,b){d=document.id(d);
b=document.id(b);var e=this.togglers.contains(d);this.togglers.include(d);this.elements.include(b);var a=this.togglers.indexOf(d);d.addEvent(this.options.trigger,this.display.bind(this,a));
if(this.options.height){b.setStyles({"padding-top":0,"border-top":"none","padding-bottom":0,"border-bottom":"none"});}if(this.options.width){b.setStyles({"padding-left":0,"border-left":"none","padding-right":0,"border-right":"none"});
}b.fullOpacity=1;if(this.options.fixedWidth){b.fullWidth=this.options.fixedWidth;}if(this.options.fixedHeight){b.fullHeight=this.options.fixedHeight;}b.setStyle("overflow","hidden");
if(!e){for(var c in this.effects){b.setStyle(c,0);}}return this;},display:function(a,b){b=$pick(b,true);a=($type(a)=="element")?this.elements.indexOf(a):a;
if((this.timer&&this.options.wait)||(a===this.previous&&!this.options.alwaysHide)){return this;}this.previous=a;var c={};this.elements.each(function(f,e){c[e]={};
var d=(e!=a)||(this.options.alwaysHide&&(f.offsetHeight>0));this.fireEvent(d?"background":"active",[this.togglers[e],f]);for(var g in this.effects){c[e][g]=d?0:f[this.effects[g]];
}},this);return b?this.start(c):this.set(c);}});var Asset={javascript:function(f,d){d=$extend({onload:$empty,document:document,check:$lambda(true)},d);
var b=new Element("script",{src:f,type:"text/javascript"});var e=d.onload.bind(b),a=d.check,g=d.document;delete d.onload;delete d.check;delete d.document;
b.addEvents({load:e,readystatechange:function(){if(["loaded","complete"].contains(this.readyState)){e();}}}).set(d);if(Browser.Engine.webkit419){var c=(function(){if(!$try(a)){return;
}$clear(c);e();}).periodical(50);}return b.inject(g.head);},css:function(b,a){return new Element("link",$merge({rel:"stylesheet",media:"screen",type:"text/css",href:b},a)).inject(document.head);
},image:function(c,b){b=$merge({onload:$empty,onabort:$empty,onerror:$empty},b);var d=new Image();var a=document.id(d)||new Element("img");["load","abort","error"].each(function(e){var f="on"+e;
var g=b[f];delete b[f];d[f]=function(){if(!d){return;}if(!a.parentNode){a.width=d.width;a.height=d.height;}d=d.onload=d.onabort=d.onerror=null;g.delay(1,a,a);
a.fireEvent(e,a,1);};});d.src=a.src=c;if(d&&d.complete){d.onload.delay(1);}return a.set(b);},images:function(d,c){c=$merge({onComplete:$empty,onProgress:$empty,onError:$empty,properties:{}},c);
d=$splat(d);var a=[];var b=0;return new Elements(d.map(function(e){return Asset.image(e,$extend(c.properties,{onload:function(){c.onProgress.call(this,b,d.indexOf(e));
b++;if(b==d.length){c.onComplete();}},onerror:function(){c.onError.call(this,b,d.indexOf(e));b++;if(b==d.length){c.onComplete();}}}));}));}};

var Floom = new Class({
	
	Implements: [Events, Options],
		
	options: {
		prefix: 		'floom_',
		amount: 		24,
		animation: 		70,
		interval: 		8000,
		axis: 			'vertical',
		progressbar: 	true,
		captions: 		true,
		captionsFxOut: 	$empty,
		captionsFxIn: 	$empty,
		slidesBase: 	$empty,
		sliceFxIn: 		$empty,
		onSlideChange: 	$empty,
		onPreload: 		$empty
	},
	
	initialize: function(wrapper, slides, options){
			
		this.setOptions(options);
			
		wrapper = $(wrapper);
		this.slides = this.driver(slides);
		
		this.wrapper = {
			el: 	wrapper,
			width: 	wrapper.getSize().x,
			height: wrapper.getSize().y
		};
						
		this.slices = {
			els: [],
			width: (this.options.axis == 'vertical' ? this.wrapper.width / this.options.amount : this.wrapper.width).toInt(),
			height: (this.options.axis == 'vertical' ? this.wrapper.height : this.wrapper.height / this.options.amount).toInt()
		};
		
		this.current = {
			slide: 0,
			overlay: 0,
			counter: 0
		};
		
		this.preloadImgs = [];
		
		this.createStructure();		
	},
	
	driver: function(slides){		
		// build the options object from a set of elements
		if ($type(slides[0]).contains('element')) {			
			this.slidesEl = [];
			
			// assign caption and the filename/url
			slides.each(function(slide){
				this.slidesEl.push({
					image: slide.get('src'),
					caption: slide.get('title')
				});
			}, this);
			
			// remove redundant elements
			slides.destroy().empty();
			
			// assign the new object
			slides = this.slidesEl;			
		}
				
		return slides;
	},
		
	horizontal: function(){
		return {
			'background-position': '0 -' + (this.slices.height * this.current.counter) + 'px'
		};	
	},

	vertical: function(){
		return {
			'background-position': '-' + (this.slices.width * this.current.counter) + 'px 0'
		};
	},

	createProgressbar: function(){
		this.progressbar = new Element('div', {
			'class': this.options.prefix + 'progressbar',
			'morph': {
				'duration': this.options.interval - (this.options.animation * this.options.amount),
				'transition': 'linear'
			}
		});
		
		this.progressbar.inject(this.wrapper.el);
	},
	
	createCaptions: function(){
		this.captions = new Element('div', {
			'class': this.options.prefix + 'caption',
			'html': 'caption',
			'styles': {
				'opacity': 0
			}
		});
		
		this.captions.inject(this.wrapper.el);
	},
	
	createStructure: function(){
		this.container = new Element('div', {
			'class': this.options.prefix + 'container',
			'styles': {
				'height': this.wrapper.height,
				'width': this.wrapper.width
			}
		});
				
		this.container.inject(this.wrapper.el);
		
		// create the progress bar
		if (this.options.progressbar) this.createProgressbar();
		
		// create the caption container
		if (this.options.captions) this.createCaptions();
				
		// preload images and start up the slider
		this.preload();
	},
	
	createBlinds: function(idx){
		
		// update the global counter
		this.current.counter = idx;
		
		// create the slices
		this.slices.els[idx] = new Element('div', {
			'class': this.options.prefix + 'slice ' + this.options.prefix + this.options.axis,
			'tween': {
				'duration': this.options.animation * 4
			},
			'styles': $merge({
				'opacity': 0,
				'width': this.slices.width,
				'height': this.slices.height,
				'background-image': 'url(' + this.options.slidesBase + this.slides[this.current.slide].image + ')'
			}, this[this.options.axis]())
		}).inject(this.container);
		
		// animate the slide
		this.slices.els[idx].morph($merge({
			'opacity': 1
		}, this.options.sliceFxIn));

		// move to the next slide
		if (idx == this.options.amount-1) this.step.delay(this.options.animation, this);
	},
	
	preload: function(){		
		// build the images array
		this.slides.each(function(o){
			this.preloadImgs.push(this.options.slidesBase + o.image);
		}, this);
		
		// preload all and activate when done
		new Asset.images(this.preloadImgs, {
			onComplete: this.onPreload.bind(this)
		});
	},
	
	onPreload: function(){
		this.animateBlinds().periodical(this.options.interval, this);
		
		this.fireEvent('onPreload', this.slides[this.current.slide]);
	},

	animateBlinds: function(){
		this.current.slide++;
		
		// go back to the first one when at the end
		if (this.current.slide == this.slides.length-1) this.current.slide = 0;
		
		// create blinds
		for (var idx = 0; idx < this.options.amount; idx++) {
			this.createBlinds.delay(this.options.animation * idx, this, idx);
		}
		
		// hide the progressbar when it reaches the end
		if (this.options.progressbar) this.progressbar.fade('out');
		
		if (this.options.captions) {
			
			// apply the animation
			this.captions.morph($merge({
				'opacity': 0
			}, this.options.captionsFxOut));
		}
		
		return this.animateBlinds;
	},
	
	step: function(){		
		
		// apply the image to the background
		this.container.set('styles', {
			'background-image': 'url(' + this.options.slidesBase + this.slides[this.current.slide].image + ')'
		});
		
		// destory slices when animations finishes
		this.slices.els.each(function(slice){
			slice.destroy();
		});

		// prepeare and animate the progressbar
		if (this.options.progressbar) {
			
			// calculate the width of the progressbar including margins
			var calculatedWidth = this.container.getSize().x - (this.progressbar.getStyles('margin-left')['margin-left'].toInt() * 2);
			
			// animate the size
			this.progressbar.morph({
				'width': [0, calculatedWidth]
			});
			
			// show the progressbar
			this.progressbar.fade('in');			
		}
		
		// update and animate the caption
		if (this.options.captions) {
			
			// update the copy
			this.captions.set('html', this.slides[this.current.slide].caption);
			
			// animate the caption
			this.captions.morph($merge({
				'opacity': 1
			}, this.options.captionsFxIn));
		}
		
		this.fireEvent('onSlideChange', this.slides[this.current.slide]);
	}
});

Element.implement({
	floom: function(slides, options){
		return new Floom(this, slides, options);
	}
});