/*
 Slideshow v0.5
 
 CHANGES
 ==============
v0.5
 - Everything is encapsulated within 'adjohu namespace'
 - Refactored to make logic more... logical.

v0.4
 - Images can now hold data.
 - Images height and width are held in the image object
 ==============
 Lightweight slideshow made by Adam Hutchinson.
 www.adamhutchinson.co.uk
 Requires Prototype(1.6.1) + Scriptaculous(1.8.3)
*/
var adjohu = adjohu || {};

adjohu.slideshows = [];
adjohu.Slideshow = function(parentId,opt){
	// We need an opt object...
	if(typeof(opt) != 'object') opt = {};
	
	this.parent          = typeof parentId == "string" ? $(parentId) : parentId ;
	this.images          = [];
	this.slideTime       = (opt.interval < 100) ? opt.interval * 1000 : opt.interval|| 2000; // Change this for a longer timeout
	this.fadeDuration    = (this.slideTime < 2000) ? this.slideTime /4000 : 1;
 	this.timeout         = null;
	this.currPos         = -1;
	this.lastPos         = 0;
	this.started         = false;
	this.imageFolder     = opt.folder || '/images/'; //Change these to match site config
	this.imageExtension  = typeof opt.extension == "string" ? opt.extension : '.jpg';
	this.toBackground    = (opt.background == 1) ? 1 : 0 || 0;
  	this.repeat          = opt.repeat || 'no-repeat';
	this.onChange        = typeof opt.onChange == 'function' ? opt.onChange : function(){} || function(){}; // Empty function for onChange if it's needed.
	this.maxDimensions   = [opt.x || 0,opt.y || 0]; // These don't do anything yet... :P
	this.imgLoadFunc     = typeof opt.imgLoadFunc == 'function' ? opt.imgLoadFunc : function(){} || function(){}; // Function used each time an image loads (incase we need to dynamically resize something that's not involved in the main slideshow logic.)
	
	adjohu.slideshows.push(this);
};

// Add Image to Slideshow
adjohu.Slideshow.prototype.addImg = function(src,opt){
	if(typeof(src) == 'string' || typeof(src) =='number'){
		src=src.toString();
		// If src isn't a direct url then make the src based on the folder and extension specified in the slideshow object.
		if(src.indexOf('http://') == -1){
			src = this.imageFolder+src+this.imageExtension;	
		}
		
		// Get the options (if there are any)
		opt = (typeof(opt) == "object") ? opt : {};
		var onClick = opt.onClick || null;
		var data	= opt.data	  || null;
		
		var new_img = new adjohu.Img(src,onClick,data,this, this.images.length);
		
		// Add the image to images array
		this.images.push(new_img);
	}
};

// Remove image from slideshow
adjohu.Slideshow.prototype.removeImg = function(index){
	// remove from memory
	delete this.images[index];
	// remove array element
	this.images.splice(index,1);
}

// Swap Image with another image by 'images' array position (old Position, new Position)
adjohu.Slideshow.prototype.showImg = function(nPos){
	// Hide image
	if(typeof(this.images[this.lastPos]) !== "undefined" && this.toBackground === 0){
		this.images[this.lastPos].hide(this.parent,this.fadeDuration);
	}
	
	// Show image
	// If we're doing the slideshow as background images then run different function
	if(this.toBackground == 1){
		this.images[nPos].showBg(this.parent,this.fadeDuration,this.repeat);	
	}else{
		this.images[nPos].show(this.parent,this.fadeDuration);
	}
	
	// Call onChange function, pass the current image and this slideshow to it.
	this.onChange(this.images[nPos],this);
};

// Main slideshow logic
adjohu.Slideshow.prototype.run = function(){
	if(this.started === true){
		// Stop slideshow if there is only 1 slide
		if(this.images.length <= 1){
			this.stop();
		}
		
		// Change slide and restart timeout
		clearTimeout(this.timeout);
		this.changeSlide();
		this.timeout = setTimeout(this.run.bind(this),this.slideTime);	
	}
};

// Change the slide 
adjohu.Slideshow.prototype.changeSlide = function(toSlide){
		this.lastPos = this.currPos;
		
		// If there is no slide number passed, change to the next slide
		this.currPos = this.goodPos(toSlide || this.currPos + 1);
		
		this.showImg(this.currPos);
		
		// pre load next image
		var index_to_preload = this.goodPos(this.currPos + 1);
		this.images[index_to_preload].loadMe();	
};

// Returns either the passed position or the first image depending on whether the image exists
adjohu.Slideshow.prototype.goodPos = function(pos){
	if(pos == this.images.length || pos === null){
		return 0;	
	}else return pos;
};

// Slideshow start logic
adjohu.Slideshow.prototype.start = function(){
	// If there are images
	if(this.images.length !==0 && this.started === false){	
		this.started = true;
		this.run();		
	}
	
	return true;
};

adjohu.Slideshow.prototype.stop = function(){
	clearTimeout(this.timeout);
	this.started=false;
	
	return true;
};

// An image used in the slideshow
adjohu.Img = function(src, onClick, data, parent_slideshow, index){
	this.src = src;
	this.data = data;
	this.onClick = typeof(onClick == "function") ? onClick : function(){};
	this.img = null;
	this.h   = null;
	this.w   = null;
	this.index = index; // Index in images array of slideshow
	this.slideshow = parent_slideshow;
};

// Load the actual Image element if you haven't already.
adjohu.Img.prototype.loadMe = function(){
	if(this.img === null){
		var img = new Image();
		img.src = this.src;
		img.style.position='absolute';
		this.img = img;	
		
		// Check for image load and when loaded, adjust image height and width vars
		var self = this;
		img.onload = function(){
			self.h = img.height;
			self.w = img.width;
			// Call the slideshows 'image load function' and pass this image to it
			self.slideshow.imgLoadFunc(self,self.slideshow);
		};
		
		// If the image errors then remove it from slideshow
		img.onerror = function(){
			this.slideshow.removeImg(this.index);
		}
	
		return true;
	}
	
	return false;
};

// Fade in an image and add it to the element specified by parent
adjohu.Img.prototype.show = function(parent,duration){
	//If the image is not loaded then load it
	this.loadMe();	
	this.img.style.display = 'none';
	this.img.onclick = this.onClick;
	if(this.onClick) this.img.style.cursor = 'pointer';
	parent.appendChild(this.img);
	new Effect.Appear(this.img,{
		duration:duration
	});
};

// Fade out an image and remove from parent
adjohu.Img.prototype.hide = function(parent,duration){
	if(this.img){
		// this.img is needed by afterFinish callback
		var img = this.img;
		new Effect.Fade(img,{
			duration:duration,
			afterFinish: function(){
				parent.removeChild(img);
			}
		});	
	}
};

adjohu.Img.prototype.showBg = function(parent,duration,repeat){
	// Load image
	this.loadMe();
	
	// we need to reference the image in afterFinish function
	var self = this;

	// fade out parent as we're using background images.
	parent.fade({afterFinish:function(){
			parent.style.backgroundImage = 'url('+self.src+')';
      parent.style.backgroundRepeat= repeat;

			// If it has an onclick function
			parent.onclick = self.onClick || null;
			parent.style.cursor = (self.onClick) ? 'pointer' : 'auto';
			
			parent.appear({duration:duration});	
	}});
};

