var Loop = new Class({

    isLooping: false,
    loopFunction: undefined,
	loopDelay: 10000,
	
    setLoop: function(loopFunction,delay) {
		this.loopDelay = (delay) ? delay : this.loopDelay;
        if(this.isLooping) this.stopLoop();
        this.loopFunction = loopFunction;
        return this;
    },
    startLoop: function(delay) {
		this.stopLoop();
		this.isLooping = true;
        this.loopDelay = (delay) ? delay : this.loopDelay;
        this.periodical = this.loopFunction.periodical(this.loopDelay,this);
        return this;
    },
	stopLoop: function() {
        this.isLooping = false;
        clearInterval(this.periodical);
        return this;
    }
});


var SlideShowStructure = new Class({
	
	Implements: [Options, Events],
	options: {
		width: '900px',
		height: '500px',
		opacity: 0.5,
		showAlt: true,
		showNavigation: true,
		showNavigationPoints: true,
		id: '1',
		slideShowOptions: {
			startIndex: 0,
	    	slideInterval: 10000,
			duration: 500,
			effectName: 'fade',
			transition: 'sine:in',
			width: '900px',
			height: '500px',
			autoPlay: true,
			randomSwitch: false
		}
	},
	initialize: function(element,imageArray,options) {
		this.setOptions(options);
		this.element = element;
		this.imageArray = imageArray;
		this.element.setStyles({width: this.options.width, height: this.options.height});
		this.addProgressBar();
		this.imagePreload();
		
	},
	addProgressBar: function() {
		this.progressBar = new Element('div').addClass('jk_slideshow_progressbar');
		this.progressBar.setStyles({width: this.options.width, height: this.options.height});
		this.element.adopt(this.progressBar);
	},
	removeProgressBar: function() {
		this.progressBar.dispose();
	},
	imagePreload: function() {
		var images = Array();
		this.imageArray.each(function(imageObject, index) {	
			images.push(imageObject.imagePath);
		}, this);
		
		var slideShowStructure = this;		
  		var loader = new Asset.images(images, { 
    		onComplete: function() {
				slideShowStructure.setupStructure();
			}
 		});
	},
	setupStructure: function() {
		this.element.setStyles({width: this.options.width, height: this.options.height});
		this.slidesContainer = new Element('div').setProperties({id: 'jk_slideshow_slidecontainer'+'_'+this.options.id});
		this.slidesContainer.addClass('jk_slideshow_slidecontainer');
		this.slidesContainer.setStyles({width: this.options.width, height: this.options.height});
		this.element.adopt(this.slidesContainer);
		
		this.altDivFx = Array();
		this.altDiv = Array();
		
		this.imageArray.each(function(imageObject, index) {	
			var div = new Element('div').addClass('jk_slideshow_slide');
			div.setStyles({width: this.options.width, height: this.options.height});
			this.slidesContainer.adopt(div);
			
			var imgDiv = new Element('div').addClass('jk_slideshow_image').setStyles({background: 'url('+imageObject.imagePath+') center center no-repeat'});
			imgDiv.setStyles({width: this.options.width, height: this.options.height});
			if(imageObject.linkURL != undefined) {
				a = new Element('a').setProperties({href: imageObject.linkURL, title: imageObject.imageTitle});
				a.adopt(imgDiv);
				div.adopt(a);
			} else {
				div.adopt(imgDiv);
			}
			
			if(this.options.showAlt) {
				if(typeof imageObject.imageAlt != "undefined") {
					var altDiv = new Element('div').addClass('jk_slideshow_alt').setStyle('opacity', this.options.opacity);
					var altText = new Element('div').addClass('jk_slideshow_alt_text').set('html',imageObject.imageAlt);
					altDiv.adopt(altText);
					div.adopt(altDiv);
					this.altDivFx[index] = new Fx.Morph(altDiv,{duration: 250}).set('height', 0);
					this.altDiv[index] = altDiv;
				}
			}

		},this);
		
		
		this.createSlideShow();
		
		if(this.options.showNavigation) this.addNavigation();
		if(this.options.showNavigationPoints) this.addNavigationPoints();
		
		this.slideShow.start();
		
		this.removeProgressBar();	
	},
	createSlideShow: function() {
		this.slideShow = new SlideShow(this.slidesContainer, this.options.slideShowOptions);
		this.fireEvent('slideShowCreated');
		
		this.slideShow.addEffect("none", function(current, next, duration, transition, instance){ 
			current.setStyle("display","none");
			return this;
		});
		
		this.slideShow.addEffect("fade", function(current, next, duration, transition, instance){ 
			current.set("tween",{
				duration: duration, 
				transition: transition
			}).fade("out");
			return this;
		});
		
		this.slideShow.addEffect("fadeBackground", function(current, next, duration, transition, instance){
			var half = duration / 2;
			next.set("tween",{ 
				duration: half,
				transition: transition
			}).fade("hide");
			current.set("tween",{ 
				duration: half, 
				transition: transition, 
				onComplete: function(){ next.fade("in"); }
			}).fade("out");
		});
		
		this.slideShow.addEffect("slideLeft", function(current, next, duration, transition, instance){
			var distance = instance.element.getStyle("width").toInt();
			next.setStyle("left", distance);
			[next, current].each(function(slide){
				var to = slide.getStyle("left").toInt() - distance;
				slide.set("tween",{
					duration: duration, 
					transition: transition
				}).tween("left", to);
			});
			return this;
		});
		
		this.slideShow.addEffect("slideRight", function(current, next, duration, transition, instance){
			var distance = instance.element.getStyle("width").toInt();
			next.setStyle("left", -distance);
			[next, current].each(function(slide){
				var to = slide.getStyle("left").toInt() + distance;
				slide.set("tween",{
					duration: duration, 
					transition: transition
				}).tween("left", to);
			}); 
			return this;
		});
		
		this.slideShow.addEffect("slideDown", function(current, next, duration, transition, instance){
			var distance = instance.element.getStyle("height").toInt();
			next.setStyle("top", -distance);
			[next, current].each(function(slide){
				var to = slide.getStyle("top").toInt() + distance;
				slide.set("tween",{
					duration: duration, 
					transition: transition
				}).tween("top", to);
			});
			return this;
		});
		
		this.slideShow.addEffect("slideUp", function(current, next, duration, transition, instance){
			var distance = instance.element.getStyle("height").toInt();
			next.setStyle("top", distance); 
			[next, current].each(function(slide){ 
				var to = slide.getStyle("top").toInt() - distance;
				slide.set("tween",{
					duration: duration, 
					transition: transition
				}).tween("top", to);
			});
			return this;
		});
	},
	addNavigation: function() {
		this.naviLeft = new Element('a').setProperties({href: '#'});
		this.naviLeft.addClass('jk_slideshow_navigation_left');
		this.naviLeft.setStyle('opacity', this.options.opacity);
		this.naviLeft.addEvent('click', function(e){
			e.stop();
			this.slideShow.pause();
			this.slideShow.cycleBackward();
		}.bind(this));
		this.naviLeft.addEvent('mouseenter', function(){
			this.naviLeft.setStyle('opacity', 1);
		}.bind(this));
		this.naviLeft.addEvent('mouseleave', function(){
			this.naviLeft.setStyle('opacity', this.options.opacity);
		}.bind(this));
		
		this.naviRight = new Element('a').setProperties({href: '#'});
		this.naviRight.addClass('jk_slideshow_navigation_right');
		this.naviRight.setStyle('opacity', this.options.opacity);
		this.naviRight.addEvent('click', function(e){
			e.stop();
			this.slideShow.pause();
			this.slideShow.cycleForward();
		}.bind(this));
		this.naviRight.addEvent('mouseenter', function(){
			this.naviRight.setStyle('opacity', 1);
		}.bind(this));
		this.naviRight.addEvent('mouseleave', function(){
			this.naviRight.setStyle('opacity', this.options.opacity);
		}.bind(this));
			
		this.element.adopt(this.naviLeft, this.naviRight);							
	},
	addNavigationPoints: function() {
		this.naviPointsContainer = new Element("div").addClass("jk_slideshow_navigation_pointscontainer");	
		this.naviPoints = Array();	
		this.slideShow.getSlides().each(function(slide, index) {	
			naviPoint = new Element('a').setProperties({href: '#'});
			naviPoint.addClass('jk_slideshow_navigation_point');
			naviPoint.setStyle('opacity', this.options.opacity);
			naviPoint.addEvent('click', function(e){
					e.stop();
					this.slideShow.pause();
					this.slideShow.show(this.slideShow.getSlide(index));
			}.bind(this));
												
			this.naviPoints.push(naviPoint);
		}.bind(this));
		
		this.naviPointsContainer.adopt(this.naviPoints);
		this.element.adopt(this.naviPointsContainer);
		
		this.slideShow.addEvent('onShowComplete', function(){ 
			this.slideShow.getSlides().each(function(slide, index) {
				if(slide == this.slideShow.current) {
					this.naviPoints.each(function(naviPoint,i) {
						if(index == i) naviPoint.setStyle('opacity', 1);
						else naviPoint.setStyle('opacity', this.options.opacity);
					}, this);

					if(typeof this.altDiv[index] != "undefined") this.altDivFx[index].start({'height': 35});
				}
				if(typeof this.altDiv[index] != "undefined") this.altDivFx[index].set({'height': 0});
			}, this);
		}.bind(this));	
	}
});



var SlideShow = new Class({
	effect:  Array,
	Implements: [Loop, Options, Events],
	options: {
		startIndex: 0,
	    slideInterval: 10000,
		duration: 500,
		effectName: 'fade',
		transition: 'sine:in',
		autoPlay: true,
		randomSwitch: false
	},
	initialize: function(element,options){	
		this.setOptions(options);
        this.element = element;
        this.slides = this.element.getChildren();
        this.current = this.slides[this.options.startIndex];
		this.slides.each(function(slide, index) {
			slide.setStyles({'position': 'absolute', 'z-index': 0, 'display': 'block', 'left': 0, 'right': 0, 'visibility': 'visible', 'opacity': 1});
            if(index != this.options.startIndex) slide.setStyles({'display': 'none'});
        }, this);
    },
	start: function() {
		this.show(this.current);
		this.setLoop(this.cycleForward, this.options.slideInterval);
        if(this.options.autoPlay) this.startLoop();
	},
	show: function(slide) {
        this.fireEvent('showBegin');
        if(slide != this.current) {
            var current = this.current.setStyles({'position': 'absolute', 'z-index': 1, 'display': 'block', 'left': 0, 'right': 0, 'visibility': 'visible', 'opacity': 1});
            var next = slide.setStyles({'position': 'absolute', 'z-index': 0, 'display': 'block', 'left': 0, 'right': 0, 'visibility': 'visible', 'opacity': 1});
            this.effect[this.options.effectName](current, next, this.options.duration, this.options.transition, this);
            (function() { 
                current.setStyles({'display': 'none'});
                this.fireEvent('showComplete');
            }).bind(this).delay(this.options.duration);
            this.current = next;
        } else {
			this.fireEvent('showComplete');
		}
        return this;
    },
	getSlide: function(index) {
		return this.slides[index];
	},
	getSlides: function() {
		return this.slides;
	},
	getCurrentSlide: function() {
        return this.current;
    },
    getNextSlide: function() {
        return (this.current.getNext()) ? this.current.getNext() : this.slides[0];
    },
    getPreviousSlide: function() {
        return (this.current.getPrevious()) ? this.current.getPrevious() : this.slides.getLast();
    },
	getTransition: function() {
		return this.options.transition;
	},
    cycleForward: function() {
		this.fireEvent('cycleForward');
		if(this.options.randomSwitch) this.show(this.slides[parseInt(Math.random() * (this.slides.length))]);
		else this.show(this.getNextSlide());
        return this;
    },
    cycleBackward: function(){
		this.fireEvent('cycleBackward');
        if(this.options.randomSwitch) this.show(this.slides[parseInt(Math.random() * (this.slides.length))]);
		else this.show(this.getPreviousSlide());
        return this;
    },
    play: function() {
		this.fireEvent('play');
        this.startLoop();
        return this;
    },
    pause: function(){
		this.fireEvent('pause');
        this.stopLoop();
        return this;
    },
    reverse: function() {
        var loopFunction = (this.loopMethod == this.cycleForward) ? this.cycleBackward : this.cycleForward;
        this.setLoop(loopFunction, this.options.slideInterval);
        this.fireEvent('reverse');
        return this;
    },
	addEffect: function(name, fn) {
        this.effect[name] = fn;
    }	
}); //end Class

