Slideshow=new Class({
	Implements:[Options,Events],
	options:{
		engine:'Slider',
		engineOptions:{},
		
		slideOptions:{},
		slideClass:null,
		
		width:null,
		height:null,
		
		wrapClass:'slideshow',
		wrapId:null,
		
		slideDuration:4000,
		build:{togglePlay:true},
		debug:false
	},
	slides:[],
	elements:{
		wrap:null
	},
	Engine:null,
	built:null,
	
	width:0,
	height:0,
	
	currentSlide:0,
	animate:true,
	
	timer:null,
	running:false,
	
	plugins:[],
	
	initialize:function(options){
		this.setOptions(options);
		this._parseOptions();
		this._initEngine();
	},
	_parseOptions:function(){
		if(this.options.slideClass===null)
			this.options.slideClass=Slideshow.Slide;
	},
	_initEngine:function(){
		if(typeof(this.options.engine)=='string')
			this.Engine=new Slideshow.Engines[this.options.engine](this,this.options.engineOptions);
		else
			this.Engine=new this.options.engine(this,this.options.engineOptions);
	},
	addSlide:function(slide,options){
		var slideObj=new this.options.slideClass(slide,options);
		slideObj.id=Slideshow.idCounter++;
		this.slides.push(slideObj);
		
		return this;
	},
	build:function(force){
		if(this.built && !force)
			return this.built;
		var that=this;
		var wrapElm=new Element('div',{
			'class':this.options.wrapClass,
			id:this.options.wrapId
		});
		this.elements.wrap=wrapElm;
		
		var engineContent=this.Engine.build(force);
		engineContent.inject(wrapElm);
		
		this.built=wrapElm;
		
		this.fireEvent('build',[this.built]);
		
		this.gotoSlide(this.currentSlide,true);
		return this.built;
	},
	toElement:function(){
		this.build();
		return this.built;
	},
	inject:function(target,position){
		document.id(this.toElement()).inject(target,position);
	},
	changeSlide:function(offset,instant){
		if(offset===undefined)
			offset=1;
			
		var index=(this.currentSlide + offset) % this.slides.length;
		this.gotoSlide(index,instant);
		return this;
	},
	gotoSlide:function(slideIndex,instant){
		if(!this.slides[slideIndex])
			return this;
		this.Engine.gotoSlide(slideIndex,instant);
		var oldSlide=this.currentSlide;
		this.currentSlide=slideIndex;
		
		this.fireEvent('changeSlide',[slideIndex,oldSlide]);
		
		return this;
	},
	resize:function(size){
		if(size===undefined)
			size={
				width:this.options.width,
				height:this.options.height
			}
		if(size.width===null || size.height===null){
			var wrapSize=this.elements.wrap.getSize();
			if(size.width===null)
				size.width=wrapSize.x;
			if(size.height===null)
				size.height=wrapSize.y;
		}
		this.width=size.width;
		this.height=size.height;
		this.elements.wrap.setStyles(size);
		this.Engine.resize();
	},
	play:function(){
		if(this.running)
			return this;
		this.running=true;
		this._playLoop();
		this.fireEvent('play');
		return this;
	},
	_playLoop:function(){
		if(this.running==false)
			return false;
			
		var duration=this.Engine.getSlideDuration(this.currentSlide);
		if(duration===null)
			duration=this.options.slideDuration;
		var that=this;
		
		
		this.timer=(function(){
			that._playLoop();
			that.changeSlide();
		}).delay(duration);
	},
	stop:function(){
		clearTimeout(this.timer);
		this.running=false;
		this.fireEvent('stop');
		return this;
	},
	toggle:function(){
		if(this.running)
			this.stop();
		else
			this.play();
		return this;
	},
	addPlugin:function(pluginClass,a,b,c){
		var Plugin=new pluginClass(this,a,b,c);
		for(var key in Plugin){
			var value=Plugin[key];
			if(this.options.debug){
				(function(key,value){
					
					if(typeOf(value)=='function'){
						Plugin[key]=function(){
							return value.apply(Plugin,arguments);
						};	
					}
				})(key,value);
			}
		}
		this.plugins.push(Plugin);
		return Plugin;
	},
	resetTimer:function(){
		if(this.running==false)
			return false;
		clearTimeout(this.timer);
		this._playLoop();
	},
	fireEvent:function(type, args, delay){
		Events.prototype.fireEvent.bind(this,[type, args, delay]);
		this.plugins.each(function(plugin){
			plugin.fireEvent(type,args,delay);
		});
	}
});
Slideshow.idCounter=0;
Slideshow.Slide=new Class({
	Implements:[Options],
	options:{
		duration:null,
		href:null,
		openInNewWindow:false,
		'class':'slide',
		id:null,
		imageMode:'background',
		backgroundStyle:{
			backgroundRepeat:'no-repeat',
			backgroundPosition:'center',
			backgroundColor:'#ffffff'
		}
	},
	id:null,
	type:null,
	content:null,
	built:null,
	size:{
		width:null,
		height:null
	},
	initialize:function(slide,options){
		var slideType=typeof(slide);
		switch(slideType){
			case 'element':
			break;
			case 'string':
				slideType='image';
			break;
			default:
				return this;
			break;
		}
		this.setOptions(options);
		
		this.type=slideType;
		this.content=slide;
	},
	build:function(force){

		if(force && this.built)
		{
			switch(this.type){
				case 'element':
					this.content.dispose();
				break;
			}
			this.built.destroy();
		}
		else if(this.built)
			return this.built;
			
			
		var slideElm,
			attributes={
				'class':this.options['class'],
				id:this.options.id
			},
			tag='div';
		
		if(this.options.href){
			tag='a';
			attributes.href=this.options.href;
			if(this.options.openInNewWindow)
				attributes.target='__blank';
		}
		
		slideElm=new Element(tag,attributes);
		
		switch(this.type){
			case 'image':
				switch(this.options.imageMode){
					case 'background':
						var styles=this.options.backgroundStyle;
						styles.backgroundImage='url('+this.content+')';
						
						slideElm.setStyles(styles);
					break;
					case 'img':
						
						//PUUTTUU
						
					break;
				}
			break;
			
			case 'element':
				this.content.inject(slideElm);
			break;
		}
		this.built=slideElm;
		return slideElm;
	},
	destroy:function(){
		if(this.built)
			this.built.destroy();
	},
	resize:function(size){
		if(size.width!==undefined)
			this.size.width=size.width;
		if(size.height!==undefined)
			this.size.height=size.height;
		
		if(this.built)
			this.built.setStyles(this.size);
	},
	getDuration:function(){
		return this.options.duration;
	}
});
Slideshow.Engines={};
Slideshow.Engines.Slider=new Class({
	Implements:[Options],
	options:{
		sliderClass:'slider',
		cssTransitions:false,
		cssTransitionsClass:'use-transitions',
		mode:'horizontal',
		fx:{
			duration:600,
			transition:'quad:in:out'
		}
	},
	Slideshow:null,
	built:null,
	
	sliderLength:0,
	slideLength:0,
	fx:null,
	
	initialize:function(Slideshow,options){
		this.setOptions(options);
		this.Slideshow=Slideshow;
	},
	build:function(force){
		this.Slideshow.elements.wrap.setStyle('overflow','hidden');
	
	
		var that=this;
		var sliderElm=new Element('div',{
			'class':this.options.sliderClass
		});
		if(this.options.cssTransitions)
			sliderElm.addClass(this.options.cssTransitionsClass);
			
		this.Slideshow.elements.slides=[];
		this.Slideshow.slides.each(function(slide,id){
			var slideElm=slide.build(force).inject(sliderElm).setStyle('float','left');
			that.Slideshow.elements.slides[id]=slideElm;
		});
		
		this.built=sliderElm;
		
		
		if(!this.options.cssTransitions)
			this.fx=new Fx.Morph(sliderElm,this.options.fx);
		else
			this.fx=null;
		
		this.Slideshow.elements.slider=sliderElm;
		
		return sliderElm;
	},
	destroy:function(){
		this.stop();
		this.Slideshow.slides.each(function(slide){
			slide.destroy();
		});
	},
	toElement:function(){
		return this.build();
	},
	resize:function(){
		if(!this.built)
			this.build();
			
		var size={},
		width=this.Slideshow.width,
		height=this.Slideshow.height;
		
		
		
		
		switch(this.options.mode){
			case 'vertical':
				//PUUTTUU
			break;
			case 'horizontal':
			default:
				if(height=='auto')
					
			break;
		}
		this.slideLength=width;
		this.sliderLength=width * this.Slideshow.slides.length;
		
		this.Slideshow.elements.slider.setStyle('width',this.sliderLength);
		
		this.Slideshow.slides.each(function(slide){
			slide.resize({
				width:width,
				height:height
			});
		});
	},
	gotoSlide:function(slideIndex,instant){
		var sliderElm=this.Slideshow.elements.slider;
		var left=-slideIndex * this.slideLength;
		if(this.options.cssTransitions){
			if(instant)
				sliderElm.removeClass(this.options.cssTransitionClass);
			sliderElm.setStyle('margin-left',left);
			if(instant)
				sliderElm.addClass(this.options.cssTransitionClass);
		}
		else
		{
			this.fx.start({
				marginLeft:left
			});
		}
	},
	getSlideDuration:function(slideId){
		return this.Slideshow.slides[slideId].getDuration();
	}
});

Slideshow.Plugin=new Class({
	Slideshow:null,
	Implements:[Options,Events],
	linkedEvents:[],
	elements:{},
	name:'UNNAMED PLUGIN',
	initialize:function(Slideshow,options){
		this.Slideshow=Slideshow;
		this.setOptions(options);
		for(var key in this){
			if((/^on[A-Z]/).test(key)){
				this.addEvent(key,this[key]);	
			}
		}
	},
	clearElements:function(){
		var flatten=function(obj){
			var result=[],
				values=Object.values(obj);
				
			values.each(function(value,key){
				if(typeOf(value)=='object'){
					var flattened=flatten(value);
					delete values[key];
					flattened.each(function(flatValue){
						result.push(flatValue);
					});
				} else {
					result.push(value);	
				}
			});	
			
			return result;
		}
		
		var flatElements=flatten(this.elements);
		flatElements.each(function(elm){
			elm.destroy();
		});
		this.elements={};
	}
});
Slideshow.SlideList=new Class({
	Extends:Slideshow.Plugin,
	options:{
		'class':'slide-list',
		'buttonClass':'slide-button',
		'currentSlideClass':'current'
	},
	name:'SlideList',
	initialize:function(Slideshow,options){
		this.parent(Slideshow,options);
		//this.addEvent('build',this.onBuild);
		//this.addEvent('changeSlide',this.onChangeSlide);
	},
	onBuild:function(){
		this.clearElements();
		var that=this;
		this.elements.wrap=new Element('ul',{
			'class':this.options['class']
		});
		this.elements.slides=[];
		this.Slideshow.slides.each(function(slide,id){
			var elm=new Element('li',{
				text:id+1,
				'class':that.options.buttonClass,
				events:{
					click:function(e){
						e.preventDefault();
						that.Slideshow.resetTimer();
						that.Slideshow.gotoSlide(id);
					}	
				}
			});
			
			that.elements.slides.push(elm);
			that.elements.wrap.adopt(elm);
			
			
		});
		this.elements.wrap.inject(this.Slideshow.elements.wrap);
	},
	onChangeSlide:function(slideIndex,oldSlideIndex){
		
		this.elements.slides[oldSlideIndex].removeClass(this.options.currentSlideClass);
		this.elements.slides[slideIndex].addClass(this.options.currentSlideClass);
	}
});
Slideshow.FloatingElement=new Class({
	Extends:Slideshow.Plugin,
	element:null,
	name:'floatingElement',
	initialize:function(Slideshow,element,options){
		this.element=element;
		this.parent(Slideshow,options);
		//this.addEvent('build',this.onBuild);
		//this.fireEvent('build');
	},
	onBuild:function(slideshowContainer){
		this.element.inject(slideshowContainer);
	}
});

Slideshow.ToggleButton=new Class({
	Extends:Slideshow.Plugin,
	name:'toggleButton',
	onBuild:function(wrapElm){
		var that=this;
		var button=new Element('a',{
			href:'#',
			'class':'toggle-button',
			events:{
				click:function(e){
					e.preventDefault();
					that.Slideshow.toggle();
					
				}
			}
		});
		
		this.addEvent('play',function(){
			that.checkState();
		});
		this.addEvent('stop',function(){
			that.checkState();
		});
		this.elements.toggleButton=button;
		button.inject(wrapElm);
		this.checkState();
	},
	checkState:function(){
		if(this.Slideshow.running)
			this.elements.toggleButton.removeClass('play');
		else
			this.elements.toggleButton.addClass('play');
	}
});
