/*
 * Slideshow with html that is asynchronously loaded for every slide
 */
var HtmlSlides = new Class({
	
	/*
	 * element - the parent element of the slides. should be overflow: hidden and have exactly one child with the initial content in it.
	 * url - Template of the url where pages are loaded from. The substring '{{ slideNo }}' is replaced by the current slide index. Example '/content/?page={{ slideNo }}' 
	 * options:
	 * 		duration - Transition duration in ms.
	 * 		firstSlideNo - Number of the first slide. Defaults to 0.
	 * 		slidesNo - Total number of slides. Defaults to 1.
	 * events:
	 * 		loadingStarted - Fired when a slide has started loading
	 * 		loadingFinished - Fired when a slide is done loading
	 * 		slideChanged - Fired when the shown slide has changed. Passes the index as argument.
	 */
	initialize: function(element, url, options) {
		this.setOptions({
			duration: 500,
			firstSlideNo: 0,
			slidesNo: 1
		}, options);
		
		this.element = $(element);
        
		this.url = url;
		
		this.loaded = false;
		
		this.slideIndex = 0;
		
		this.createWrapper();
	},
	
	/*
	 * Creates the slides wrapper and the transition effect
	 */
	createWrapper: function() {
		var el = this.element.getChildren()[0];
		this.slidesWrapper = new Element('div');
		this.slidesWrapper.replaces(el);
		this.slidesWrapper.adopt(el);
		el.setStyle('float', 'left');
		
		this.slidesFx = new Fx.Tween(this.slidesWrapper, {
			duration: this.options.duration,
			property: 'margin-left'
		});

		this.resize();
},
	
	/*
	 * Shows the next/prev slide
	 */
	changeSlide: function(dir) {
		this.slideIndex += dir;
		
		var nextSlide = this.slidesWrapper.getChildren()[this.slideIndex];
		
		if (!nextSlide) {
			this.load(this.changeSlideNow.bind(this));
			return;
		}
		
		this.changeSlideNow();
	},
	
	/*
	 * Shows the previous image
	 */
	showPrevSlide: function() {
		if (this.slideIndex > 0) {
			this.changeSlide(-1);
		}
	},
	
	/*
	 * Shows the next image
	 */
	showNextSlide: function() {
		if (this.slideIndex < this.options.slidesNo-1) {
			this.changeSlide(1);
		}
	},
	
	/*
	 * Does the actual animation
	 */
	changeSlideNow: function() {
		var left = this.slideIndex * this.element.getSize().x;
		this.slidesFx.start(-left).chain(function() {
			this.fireEvent('slideChanged', this.slideIndex);
		}.bind(this));
	},
	
	/*
	 * Starts loading the newx slide
	 * callback - function that is called then the next slide has finished loading
	 */
	load: function(callback) {
		this.fireEvent('loadingStarted');

		var newSlide = new Element('div', {
			'styles': {
				'float': 'left',
		        'width': this.element.getSize().x + 'px'
			}
		});
		this.slidesWrapper.adopt(newSlide);
		
		var req = new Request.HTML({
			update: newSlide,
			url: this.url.replace('{{ slideNo }}', this.options.firstSlideNo + this.slideIndex)
		});
		req.addEvent('success', function() {
			this.fireEvent('loadingFinished');
			callback();
		}.bind(this));

		req.get();
	},
	
	/*
	 * Called when window is resized
	 */
	resize: function() {
        var doResize = function() {
            var elW = this.element.getSize().x;
            this.slidesWrapper.setStyles({
                width: (elW * this.options.slidesNo) + 'px',
                'margin-left': (-this.slideIndex * elW) + 'px'
            });
            this.slidesWrapper.getChildren().setStyle('width', elW + 'px');
        }.bind(this);
        
        doResize();
        if (window.ie) {
            window.setTimeout(doResize, 100);
        }
	},
	
	/*
	 * Returns current index of image.
	 * During animation the index of the image shown at the end 
	 * of the animation is returned.
	 */
	getIndex: function() {
		return this.slideIndex;
	}
});

HtmlSlides.implement(new Events());
HtmlSlides.implement(new Options());
