/*
---

script: SlideShow.js

description: Easily extendable, class-based, slideshow widget. Use any element, not just images. Comes with packaged transitions but is easy to extend and create your own transitions.  The class is built to handle the basics of a slideshow, extend it to implement your own navigation piece and custom transitions.

license: MIT-style license.

authors: Ryan Florence <http://ryanflorence.com>

requires:
- /Loop
- more:1.2.4.4:Fx.Elements

provides: [SlideShow, Element.playSlideShow, Element.pauseSlideShow]

...
*/


var SlideShow = new Class({
	
	Implements: [Options, Events, Loop],
		
		options: {
			/*
			onShow: $empty,
			onShowComplete: $empty,
			onReverse: $empty,
			onPlay: $empty,
			onPause: $empty,
			*/
			delay: 7000,
			transition: 'crossFade',
			duration: '500', 
			easing: 'linear',
			autoplay: false
		},
	
	initialize: function(element, options){  
		this.setOptions(options);
		this.setLoop(this.showNext, this.options.delay);
		this.element = document.id(element);
		this.slides = this.element.getChildren();
		this.current = this.slides[0];  
		this.curItem = 0;
		this.transitioning = false;
		this.setup(); 
		this.interval = 0;
		if (this.options.autoplay) this.play();
	},
	
	setup: function(){  
	  this.setupElement().setupSlides(true);
		return this;
	},
	
	setupElement: function(){
		var el = this.element;
		if (el.getStyle('position') != 'absolute' && el != document.body) el.setStyle('position','relative');
		return this;
	},
	
	setupSlides: function(hideFirst){  
		var distance = this.element.getSize().x; 
		this.slides.each(function(slide, index){ 
			if (this.options.transition == "scrollLeft") slide.setStyle('left', index*distance);  
			else if(this.options.transition == "scrollRight") slide.setStyle('left', index*distance*(-1));  
			else slide.setStyle('left', 0);
			slide.leftPos = slide.getStyle('left').toInt();
			this.storeTransition(slide).reset(slide);
			if (hideFirst && index != 0) slide.setStyle('display','none');
		}, this);
		return this;
	},
	
	storeTransition: function(slide){ 
		var classes = slide.get('class');
		var transitionRegex = /transition:[a-zA-Z]+/;
		var durationRegex = /duration:[0-9]+/;
		var transition = (classes.match(transitionRegex)) ? classes.match(transitionRegex)[0].split(':')[1] : this.options.transition;
		var duration = (classes.match(durationRegex)) ? classes.match(durationRegex)[0].split(':')[1] : this.options.duration; 
		/* adding easing support */   
		var easingRegex = /ease:[a-zA-Z]+/;
		var easing = (classes.match(easingRegex)) ? classes.match(easingRegex)[0].split(':')[1] : this.options.easing;
		easing.replace(',',':'); 
		slide.store('ssTransition', transition).store('ssDuration', duration).store('ssEasing', easing); 
		/* end easing support */
		return this;
	},
	
	resetOptions: function(options){ 
		this.options = $merge(this.options, options);
		this.setupSlides(false);
		return this;
	},
	
	getTransition: function(slide){    
		return slide.retrieve('ssTransition');
	},
	
	getDuration: function(slide){    
		return slide.retrieve('ssDuration');
	}, 
	
	getEasing: function(slide){     
		return slide.retrieve('ssEasing');
	},
	
	show: function(slide, options){    
		slide = (typeof slide == 'number') ? this.slides[slide] : slide;
		if (slide != this.current && !this.transitioning){
			this.transitioning = true;
			var transition = (options && options.transition) ? options.transition: this.getTransition(slide),
				duration = (options && options.duration) ? options.duration: this.getDuration(slide),
				easing = (options && options.easing) ? options.easing: this.getEasing(slide);       
			if (this.options.transition == "scrollLeft" || this.options.transition == "scrollRight")
			{
			   	var	previous = this.current,
					next = slide; 
			} 
			else
			{
			 
				var	previous = this.current.setStyle('z-index', 1),
					next = this.reset(slide);   
			}
			var slideData = {
				previous: {
					element: previous,
					index: this.slides.indexOf(previous)
				}, 
				next: {
					element: next,
					index: this.slides.indexOf(next)
				}
			};
			this.fireEvent('show', slideData);
			this.transitions[transition](previous, next, duration, easing, this);
			(function() { 
				previous.setStyle('display','none');
				this.fireEvent('showComplete', slideData);
				this.transitioning = false;
			}).bind(this).delay(duration);
			this.current = next;
		}
		return this;
	},
	
	reset: function(slide){     
		return slide.setStyles({
			'position': 'absolute',
			'z-index': 0,
			'display': 'block',
			'left': slide.leftPos,
			'top': 0
		}).fade('show');
	},
	
	nextSlide: function(){
		var next = this.current.getNext();
		return (next) ? next : this.slides[0];
	},

	previousSlide: function(){  
		var previous = this.current.getPrevious();
		return (previous) ? previous : this.slides.getLast();
	},
	
	showNext: function(options){
		this.show(this.nextSlide(), options);
		return this;
	},
	
	showPrevious: function(options){  
		this.show(this.previousSlide(), options);
		return this;
	},
	
	play: function(){   
		this.startLoop();
		this.fireEvent('play');
		return this;
	},
	
	pause: function(){
		this.stopLoop();
		this.fireEvent('pause');  
		this.slides.each(function(slide, index){
			clearInterval(slide.interval);
			slide.leftPos = slide.getStyle('left').toInt();
		});
		return this;
	},
	
	reverse: function(){
		var fn = (this.loopMethod == this.showNext) ? this.showPrevious : this.showNext;
		this.setLoop(fn, this.options.delay);
		this.fireEvent('reverse');
		return this;
	},
	
	toElement: function(){
		return this.element;
	}
	
});

Element.Properties.slideshow = {

	set: function(options){
		var slideshow = this.retrieve('slideshow');
		if (slideshow) slideshow.pause();
		return this.eliminate('slideshow').store('slideshow:options', options);
	},

	get: function(options){
		if (options || !this.retrieve('slideshow')){
			if (options || !this.retrieve('slideshow:options')) this.set('slideshow', options);
			this.store('slideshow', new SlideShow(this, this.retrieve('slideshow:options')));
		}
		return this.retrieve('slideshow');
	}

};


Element.implement({
	
	playSlideShow: function(options){
		this.get('slideshow', options).play();
		return this;
	},
	
	pauseSlideShow: function(options){
		this.get('slideshow', options).pause();
		return this;
	}
	
});

SlideShow.adders = {
	
	transitions:{},
	
	add: function(className, fn){
		this.transitions[className] = fn;
		this.implement({
			transitions: this.transitions
		});
	},
	
	addAllThese : function(transitions){
		$A(transitions).each(function(transition){
			this.add(transition[0], transition[1]);
		}, this);
	}
	
}

$extend(SlideShow, SlideShow.adders);
SlideShow.implement(SlideShow.adders);

SlideShow.add('fade', function(previous, next, duration, easing, instance){
	previous.set('tween',{duration: duration, transition: easing}).fade('out');
	return this;
});

SlideShow.addAllThese([

	['none', function(previous, next, duration, easing, instance){
		previous.setStyle('display','none');
		return this;
	}],

	['crossFade', function(previous, next, duration, easing, instance){
		previous.set('tween',{duration: duration, transition: easing}).fade('out');
		next.set('tween',{duration: duration, transition: easing}).fade('in');
		return this;
	}],

	['fadeThroughBackground', function(previous, next, duration, easing, instance){
		var half = duration/2;
		next.set('tween',{ duration: half, transition: easing}).fade('hide');
		previous.set('tween',{
			duration: half, 
			transition: easing,
			onComplete: function(){
				next.fade('in');
			}
		}).fade('out');
	}],
	
	['pushLeft', function(previous, next, duration, easing, instance){
		var distance = instance.element.getSize().x;                                             
		next.setStyle('left', distance);
		new Fx.Elements([previous,next],{duration: duration, transition: easing}).start({
			0: { left: [-distance] },
			1: { left: [0] }
		});
		return this;
	}],

	['pushRight', function(p,n,d,e,i){
		var distance = i.element.getSize().x;
		n.setStyle('left', -distance);
		new Fx.Elements([p,n],{duration: d, transition: e}).start({
			0: { left: [distance] },
			1: { left: [0] }
		});
		return this;
	}],

	['pushUp', function(p,n,d,e,i){
		var distance = i.element.getSize().y;
		n.setStyle('top', distance);
		new Fx.Elements([p,n],{duration: d, transition: e}).start({
			0: { top: [-distance] },
			1: { top: [0] }
		});
		return this;
	}],

	['pushDown', function(p,n,d,e,i){
		var distance = i.element.getSize().y;
		n.setStyle('top', -distance);
		new Fx.Elements([p,n],{duration: d, transition: e}).start({
			0: { top: [distance] },
			1: { top: [0] }
		});
		return this;
	}],

	['blindRight', function(p,n,d,e,i){
		var distance = i.element.getSize().x;
		n.setStyles({
			left: -distance,
			'z-index': 2
		}).set('tween',{duration: d, transition: e}).tween('left',0);
		return this;
	}],

	['blindLeft', function(p,n,d,e,i){
		var distance = i.element.getSize().x;
		n.setStyles({
			left: distance,
			'z-index': 2
		}).set('tween',{duration: d, transition: e}).tween('left',0);
		return this;
	}],

	['blindUp', function(p,n,d,e,i){
		var distance = i.element.getSize().y;
		n.setStyles({
			top: distance,
			'z-index': 2
		}).set('tween',{duration: d, transition: e}).tween('top',0);
		return this;
	}],

	['blindDown', function(p,n,d,e,i){
		var distance = i.element.getSize().y;
		n.setStyles({
			top: -distance,
			'z-index': 2
		}).set('tween',{duration: d, transition: e}).tween('top',0);
		return this;
	}],

	['blindDownFade', function(p,n,d,e,i){
		this.blindDown(p,n,d,e,i).fade(p,n,d,e,i);
	}],

	['blindUpFade', function(p,n,d,e,i){
		this.blindUp(p,n,d,e,i).fade(p,n,d,e,i);
	}],

	['blindLeftFade', function(p,n,d,e,i){
		this.blindLeft(p,n,d,e,i).fade(p,n,d,e,i);
	}],

	['blindRightFade', function(p,n,d,e,i){
		this.blindRight(p,n,d,e,i).fade(p,n,d,e,i);
	}],

	['scrollLeft', function(previous, next, duration, easing, instance){
	   
		instance.pause(); 
		var distance = instance.element.getSize().x;  
		var lowPoint = distance*(-1);    
		var numItems = instance.slides.length-1; 
		var initPos, newIndex, endSlide;  
		instance.slides.each(function(slide, index){ 
			slide.isScrolling = true;
 			slide.interval = setInterval(function(){
			    var newPos = slide.getStyle('left').toInt() - 1;
			    slide.setStyle('left', newPos); 
				slide.setStyle('display','block');
			    if (slide.getStyle('left').toInt() < lowPoint) 
				{                                                                                                                       
					newIndex =  numItems-instance.curItem;   
					endSlide =  instance.slides[newIndex];
					initPos = distance + endSlide.getStyle('left').toInt();                                                        
					slide.setStyle('left',initPos);     
					instance.curItem = (instance.curItem == 0) ? numItems : instance.curItem - 1;
				}
			},duration);
	    });                       
		
		return this;
	}]	,

	['scrollRight', function(previous, next, duration, easing, instance){

		instance.stopLoop(); 
		var distance = instance.element.getSize().x;  
		var highPoint = distance;    
		var numItems = instance.slides.length-1;  
		var initPos, newIndex, endSlide;  
		instance.slides.each(function(slide, index){ 
			slide.isScrolling = true;
 			slide.interval = setInterval(function(){
			    var newPos = slide.getStyle('left').toInt() + 1;
			    slide.setStyle('left', newPos); 
				slide.setStyle('display','block');
			    if (slide.getStyle('left').toInt() > highPoint) 
				{                                                                                                                       
					newIndex =  numItems-instance.curItem;   
					endSlide =  instance.slides[newIndex];
					initPos = endSlide.getStyle('left').toInt() - distance;                                                        
					slide.setStyle('left',initPos);     
					instance.curItem = (instance.curItem == 0) ? numItems : instance.curItem - 1;
				}
			},duration);
	    });      

		return this;
	}] 

]);

