/**
 * @author Peter Swan
 */

var Slideshow = Class.create({
	AUTOSLIDE_INTERVAL: 3,
	ANIMATION_DURATION: 0.5,
	image_src: [],
	image_options: [],
	container: null,
	currentSlide: 0,
	image_elms: [],
	load_observers: [],
	loading_elements: [],
	goto_elements: $H(),
	windowWidth: 0,
	windowHeight: 0,
	autoSlideTimer: null,
	resizeTimer: null,
	sliding: false,
	options: {
		auto: false,
		auto_resume: false,
		/* vertical_resolve: 'height',  // options 'stretch', 'height', 'tile_both', 'tile_x'
		resize_option: 'height',
		vertical_aspect_ratio: 4/3,*/
		resize_function: null,
		vertical_align: 1,
		transition: Effect.Transitions.EaseFrom,
		fps: 200
	},
	
	initialize: function(container, sources, start_index, options){
		this.options = Object.extend(this.options, options || {});
		this.container = $(container);
		if( !this.container ){
			throw 'Slideshow: container is not an element';
		}
		/* allow options to be passed in with each image */
		sources.each(function(s){
			var source = null;
			var options = null;
			if(Object.isString(s)){
				source = s;
			}else{
				source = s.source;
				options = s.options || null;
			}
			if( source ){
				this.image_src.push(source);
				this.image_options.push(options);
			}
		}, this);
		for( var i=0; i<this.image_src.length; i++){
			var temp = {};
			temp.div = new Element('div', {'class': 'slide'});
			temp.div.setStyle({position: 'absolute', top: '0px', left: '0px'});
			temp.img = new Element('img', {'id': this.identify() + '_slide_' + i});
			temp.height = 0;
			temp.width = 0;
			temp.loaded = false;
			temp.loading = false;
			temp.slide_on_load = false;
			temp.div.insert(temp.img);
			this.load_observers[i] = this.loadCallback.bind(this, i, 1);
			temp.img.observe('load', this.load_observers[i]);
			this.image_elms[i] = temp;
			this.container.insert(temp.div.hide());
		}
		
		var id = this.identify();
		$$('.' + id + '_previous').invoke('observe', 'click', function(){
			if( this.options.auto ){
				this.stop();
			}
			this.prev();
			if( this.options.auto ){
				this.start('prev');
			}
		}.bind(this));
		$$('.' + id + '_next').invoke('observe', 'click', function(){
			if( this.options.auto ){
				this.stop();
			}
			this.next();
			if( this.options.auto ){
				this.start('next');
			}
		}.bind(this));
		this.loading_elements = $$('.' + id + '_loading');
		var selector = '[class*=' + id + '_goto_]';
		var gotos = $$(selector);
		var reg = new RegExp(id + '_goto_([^ ]+)');
		if( gotos.length ){
			for(i=0; i<gotos.length; i++){
				var match = reg.exec(gotos[i].className);
				if( match.length == 2 ) match = match[1];
				var num = parseInt(match);
				if(Object.isNumber(num) && num < this.image_src.length){
					this.goto_elements.set(num, gotos[i]);
					gotos[i].observe('click', function(e, num){
						this.go(num);
						e.stop();
					}.bindAsEventListener(this, num));
				}
			}
		}
		this.currentSlide = start_index || 0;
		this.loadImage(this.currentSlide);
		var preload = this.nextIndex(this.currentSlide);
		if( this.currentSlide != preload ) this.loadImage(preload);
		
		Event.observe(window, 'resize', function(){
			if( this.resizeTimer ){
				window.clearTimeout(this.resizeTimer);
			}
			this.resizeTimer = this.resize.bind(this).delay(0.25);
		}.bind(this));
		if( this.options.auto ){
			this.start('next');
		}else{
			var c = this.currentSlide;
			new PeriodicalExecuter(function(pe){
				if(this.image_elms[c].loaded){
					pe.stop();
					this.resize();
					this.loading_elements.invoke('hide');
					this.image_elms[c].div.show();
					this.setGotoClass(c);
				}
			}.bind(this), 0.15);
		}
	},
	
	start: function(){
		
	},
	
	stop: function(){
		
	},
	
	loadImage: function(i){
		var s = this.image_src[i];
		var e = this.image_elms[i];
		if( !e.loaded && !e.loading){
			e.loading = true;
			e.img.writeAttribute({'src': s});
		}
	},
	
	imageLoadCallback: function(i, img){
		this.image_elms[i].height = img.height;
		this.image_elms[i].width = img.width;
		this.image_elms[i].loaded = true;
		this.image_elms[i].loading = false;
		if( this.image_elms[i].slide_on_load ){
			this.slide(i, this.image_elms[i].direction, true);
		}
	},
	
	loadCallback: function(i){
		var temp = new Image();
		temp.onload = this.imageLoadCallback.bind(this, i, temp);
		temp.src = this.image_src[i];
	},
	
	/* return true if image is successfully queued to slide in to the frame, false otherwise */
	slide: function(i, t, force){
		if( this.sliding && force!==true){
			return false;
		}
		this.sliding = true;
		/* 
		if the image isn't loaded...
		 */
		var e = this.image_elms[i];
		if( !e.loaded ){
			if( !e.loading ){			// if it's not loading, load it
				this.loadImage(i);
			}
			if( !e.slide_on_load ){		// set it to slide in when it does load
				e.slide_on_load = true;
				this.loading_elements.invoke('show');	// show the loading message
			}
			return true;
		}
		if( Object.isUndefined(t) || t===null){
			t = i<this.currentSlide?0:1;
		}
		this.image_elms[i].div.setStyle({'left': (this.windowWidth * (t?2:0)) + 'px', 'zIndex': 2}).show();
		this.resizeImage(i);
		
		this.loading_elements.invoke('hide');
		new Effect.Move(this.image_elms[i].div, {
				x: this.windowWidth,
				mode: 'absolute',
				duration: this.ANIMATION_DURATION,
				transition: this.options.transition,
				fps: this.options.fps,
				afterFinish: function(){
					this.image_elms[this.currentSlide].div.hide();
					this.image_elms[i].div.setStyle({'zIndex': 1});
					this.currentSlide = i;
					this.sliding = false;
				}.bind(this)
			}
		);
		return true;
	},
	
	go: function( num ){
		if( num < this.currentSlide ){
			if( this.slide(num, false) ){
				this.loadImage(this.prevIndex(num));
				this.setGotoClass(num);
			}
		}else if( num > this.currentSlide ){
			if( this.slide(num, true) ){
				this.loadImage(this.nextIndex(num));
				this.setGotoClass(num);
			}
		}
	},
	
	prev: function(){
		var i = this.prevIndex();
		if( this.slide(i, false) ){
			this.setGotoClass(i);
			this.loadImage(this.prevIndex(i));
		}
	},
	
	next: function(){
		var i = this.nextIndex();
		if( this.slide(i, true) ){
			this.setGotoClass(i);
			this.loadImage(this.nextIndex(i));
		}
	},
	
	setGotoClass: function(num){
		if( num<0 || num>this.image_elms.length) return;
		this.goto_elements.values().invoke('removeClassName', 'current_image');
		var temp = null;
		if( (temp=this.goto_elements.get(num)) ) temp.addClassName('current_image');
	},
	
	prevIndex: function(){
		var i = arguments.length?arguments[0]:this.currentSlide;
		return i==0?this.image_src.length-1:i-1;
	},
	
	nextIndex: function(){
		var i = arguments.length?arguments[0]:this.currentSlide;
		return (i+1)%this.image_src.length;
	},
	
	resizeImage: function(i){
		if( Object.isFunction(this.options.resize_function) ){
			if( this.options.resize_function(this.windowWidth, this.windowHeight, this.image_elms[i], this.image_options[i], this.options) ) 
				return;
		}
		this._resizeImage(i);
	},
	
	_resizeImage: function(i){
		var e = this.image_elms[i];
		e.div.setStyle({
			width: this.windowWidth + 'px'
		});
		var w = Math.ceil(e.width / e.height * this.windowHeight);
		var d = Math.max(e.width, this.windowWidth);
		w = isNaN(w) ? 0 : w;
		d = isNaN(d) ? 0 : d;
		w = Math.max(w, d);
		e.img.setStyle({
			width: w + 'px'
		});
		var vertical_align = this.image_options[i]&&!Object.isUndefined(this.image_options[i].vertical_align)?this.image_options[i].vertical_align:this.options.vertical_align;
		if( vertical_align ){
			var height = w * e.height/e.width;
			var offset = parseInt((height - this.windowHeight)/vertical_align) * -1;
			e.img.makePositioned();
			e.img.setStyle({top: offset + 'px'});
		}
	},
	
	resize: function(){
		this.getWindowSize();
		this.container.setStyle({width: (this.windowWidth*3) + 'px', height: this.windowHeight + 'px', left: '-' + this.windowWidth + 'px'});
		this.resizeImage(this.currentSlide);
		this.image_elms[this.currentSlide].div.setStyle({left: this.windowWidth + 'px'});
	},
	
	getWindowSize: function(){
		var myWidth = 0, myHeight = 0;
		if( typeof( window.innerWidth ) == 'number' ) {
			//Non-IE
			myWidth = window.innerWidth;
			myHeight = window.innerHeight;
		} else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
			//IE 6+ in 'standards compliant mode'
			myWidth = document.documentElement.clientWidth;
			myHeight = document.documentElement.clientHeight;
		} else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
			//IE 4 compatible
			myWidth = document.body.clientWidth;
			myHeight = document.body.clientHeight;
		}
		this.windowWidth = myWidth;
		this.windowHeight = myHeight;
	},
	
	identify: function(){
		return this.container.identify();
	}
});