var WebElements;

if(!WebElements) WebElements = {};

WebElements.ImageShifter = function(element, options) {
	
	this.element = element;			// container that holds the images
	this.images = null;				// array of images to be displayed - only for internal use
									// use image_names for specifying the images or leave it empty to use the images that are already in the html code
	
	this.image_names = null;		// array of image names
	this.image_path = "";			// path to the images
	this.shiftprevious = null;		// element that forces previous image to show up on click
	this.shiftnext = null;			// element that forces next image to show up on click
	this.shiftwindow = null;		// container that frames the visible window in which the moving images should be visible
	this.shifttoggle = null;		// element that toggles images' shifting on click
	
	this.name = "imageshifter";		// name of the imageshifter instance for cookies etc.
	this.activeimage = 0;			// the currently active image
	this.nextimage = 0;				// the next image
	this.previousimage = 0;			// the previous image
	this.mode = "fade";				// movement mode of the images ("switch" | "fade" | "slideup" | "slidedown" | "slideleft" | "slideright" | "blindup")
	this.direction = "forward";		// direction of array traversion ("forward" | "backward" | "random")
	this.running = false;			// determines if imageshifter main loop is running
	
	this.use_cookies = true;
	this.cookie_path = "";
	
	this.timeout_id = 0;			// timeout id for the main loop of the imageshifter (life-cycle)
	this.height = null;				// height of the shiftwindow
	this.width = null;				// height of the shiftwindow
	this.unit = "px";				// unit of the image's position to be animated 
	this.fps = 60;					// frames per second of the animation
	this.duration = 1000;			// duration of an image's fading or movement
	this.lifecycle = 5000;			// duration of an image's life-cycle (including display and fade)
	this.form = "linear";
	this.callback = null;
	this.animator = null;
	
	this.setOptions(options);
	
	this.init();
	
	this.attachBehaviors();
}

WebElements.ImageShifter.prototype.setOptions = function(options) {
	
	if(options) 
	{
		for(var optionname in options)
		{
			this[optionname] = options[optionname];
		}
		
		return true;
	}
	
	return false;
}

WebElements.ImageShifter.prototype.init = function() {
	
	if(this.shiftwindow == null)
	{
		this.shiftwindow = this.element;
	}
	if(this.height == null)
	{
		this.height = this.shiftwindow.offsetHeight;
	}
	if(this.width == null)
	{
		this.width = this.shiftwindow.offsetWidth;
	}
	
	this.shiftwindow.style.height = this.height + this.unit;
	this.shiftwindow.style.width = this.width + this.unit;
	this.shiftwindow.style.overflow = "hidden";
	this.shiftwindow.style.position = "relative";
	
	// if no image names are specified
	if(this.image_names == null)
	{
		// use images already in the html code
		this.images = this.shiftwindow.getElementsByTagName("img");
		
		for(var i = 0; i < this.images.length; i++)
		{
			this.images[i].style.position = "absolute";
			this.images[i].style.display = "none";
		}
	}
	else
	{
		// if image names are specified use these images and drop images that my be left in the html code
		var imagetags = this.shiftwindow.getElementsByTagName("img");
		
		if(imagetags != null)
		{
			for(var i = 0; i < imagetags.length; i++)
			{
				this.shiftwindow.removeChild(imagetags[i]);
			}
		}
		
		this.images = new Array();
		
		// create image tags from the image names
		for(var i = 0; i < this.image_names.length; i++)
		{
			var imagetag = document.createElement("img");
			
			imagetag.src = this.image_path + this.image_names[i];
			
			imagetag.style.position = "absolute";
			imagetag.style.display = "none";
			
			this.shiftwindow.appendChild(imagetag);
			
			this.images.push(imagetag);
		}
	}
	
	// update the image indexes
	this.updateImages("init");
	
	// show the active image
	this.images[this.activeimage].style.display = "";	
}

WebElements.ImageShifter.prototype.attachBehaviors = function() {
	
	var self = this;
	
	if(this.shiftprevious) WebElements.Utils.addEventListener(this.shiftprevious, "click", function(e) { self.previousImage(); });
	if(this.shiftnext) WebElements.Utils.addEventListener(this.shiftnext, "click", function(e) { self.nextImage(); });
	if(this.shifttoggle) WebElements.Utils.addEventListener(this.shifttoggle, "click", function(e) { self.toggleMainLoop(); });
}

WebElements.ImageShifter.prototype.updateImages = function(direction) {
	
	switch(direction)
	{
		case "init":
					// if object's direction is random, randomize the indizes to start with
					if(this.direction == "random" && this.images.length > 1)
					{
						this.activeimage = parseInt(Math.random() * this.images.length);
						
						do {
							this.nextimage = parseInt(Math.random() * this.images.length);
						}
						while(this.nextimage == this.activeimage)
						
						return;
					}
					// if not, do nothing - only let nextimage and previousimage be calculated
					break;
					
		case "forward":
					this.activeimage++;
					
					if(this.activeimage == this.images.length)
					{
						this.activeimage = 0;
					}
					break;
					
		case "backward":
					this.activeimage--;
					
					if(this.activeimage < 0)
					{
						this.activeimage = this.images.length - 1;
					}
					break;
		
		case "random":
					this.activeimage = this.nextimage;
					
					if(this.images.length == 1) break;
					
					var temp = 0;
					
					do {
						// Math.random() generates random number > 0 and < 1
						// parseInt generates the nearest smaller integer
						// so temp will always be a valid image array index
						// but try to find a different index than before
						temp = parseInt(Math.random() * this.images.length);
					}
					while(temp == this.nextimage)
						
					this.nextimage = temp;
					
					return;
	}
	
	this.nextimage = this.activeimage + 1;
	this.previousimage = this.activeimage - 1;
	
	if(this.nextimage == this.images.length) this.nextimage = 0;
	if(this.previousimage < 0) this.previousimage = this.images.length - 1;
}

WebElements.ImageShifter.prototype.shiftImage = function(direction) {
	
	if((!this.animator || !this.animator.running) && this.images.length > 1)
	{
		var self = this;
		
		// create animator object with initial animation chain (empty),
		// defined frames per second and a callback function
		this.animator = new WebElements.Animator(new WebElements.AnimationChain(), this.fps, function() { self.updateImages(direction); });
		
		// switch the animation mode and create appropriate animations
		switch(this.mode)
		{
			case "switch":
						this.createSwitchAnimation(direction);
						break;
						
			case "fade":
						this.createFadeAnimation(direction);
						break;
						
			case "slideup":
						this.createSlideupAnimation(direction);
						break;
						
			case "blindup":
						this.createBlindupAnimation(direction);
						break;
						
			default:
						this.createFadeAnimation(direction);
						break;
		}
		
		this.animator.start();
		
		return true;
	}
	
	return false;
}

WebElements.ImageShifter.prototype.nextImage = function() {
	
	if(!this.animator || !this.animator.running)
	{
		switch(this.direction)
		{
			case "forward":
					this.shiftImage("forward");
					break;
					
			case "backward":
					this.shiftImage("backward");
					break;
				
			case "random":
					this.shiftImage("random");
					break;
		}
	}
	
	return false;
}

WebElements.ImageShifter.prototype.previousImage = function() {
	
	if(!this.animator || !this.animator.running)
	{
		switch(this.direction)
		{
			case "forward":
					this.shiftImage("backward");
					break;
					
			case "backward":
					this.shiftImage("forward");
					break;
				
			case "random":
					this.shiftImage("random");
					break;
		}
	}
	
	return false;
}

WebElements.ImageShifter.prototype.createSwitchAnimation = function(direction) {
	
	var currentimage = this.images[this.activeimage];
	var nextimage = this.images[(direction == "forward" || direction == "random") ? this.nextimage : this.previousimage];
	
	// create animations to be executed
	var animation_1 = new WebElements.AnimationObject(currentimage, "display", "", "none", "", 0, null, null);
	var animation_2 = new WebElements.AnimationObject(nextimage, "display", "none", "", "", 0, null, null);
	
	// create groups for animation objects and put them into
	// the animation chain
	this.animator.animation_chain.addAnimationGroup(new WebElements.AnimationGroup(new Array(animation_1, animation_2)));
}

WebElements.ImageShifter.prototype.createFadeAnimation = function(direction) {
	
	var currentimage = this.images[this.activeimage];
	var nextimage = this.images[(direction == "forward" || direction == "random") ? this.nextimage : this.previousimage];
	
	// create animations to be executed
	var animation_1 = new WebElements.AnimationObject(nextimage, "opacity", 1, 0, "", 0, null, null);
	var animation_2 = new WebElements.AnimationObject(nextimage, "display", "none", "", "", 0, null, null);
	
	var animation_3 = new WebElements.AnimationObject(currentimage, "opacity", 1, 0, "", this.duration, null, this.form);
	var animation_4 = new WebElements.AnimationObject(nextimage, "opacity", 0, 1, "", this.duration, null, this.form);
	
	var animation_5 = new WebElements.AnimationObject(currentimage, "display", "", "none", "", 0, null, null);
	
	// create groups for animation objects and put them into
	// the animation chain
	this.animator.animation_chain.addAnimationGroup(new WebElements.AnimationGroup(new Array(animation_1, animation_2)));
	this.animator.animation_chain.addAnimationGroup(new WebElements.AnimationGroup(new Array(animation_3, animation_4)));
	this.animator.animation_chain.addAnimationGroup(new WebElements.AnimationGroup(animation_5));
}

WebElements.ImageShifter.prototype.createSlideupAnimation = function(direction) {
	
	var currentimage = this.images[this.activeimage];
	var nextimage = this.images[(direction == "forward" || direction == "random") ? this.nextimage : this.previousimage];
	
	// create animations to be executed
	var animation_1 = new WebElements.AnimationObject(nextimage, "top", 0, this.height, this.unit, 0, null, null);
	var animation_2 = new WebElements.AnimationObject(nextimage, "display", "none", "", "", 0, null, null);
	
	var animation_3 = new WebElements.AnimationObject(currentimage, "top", 0, -this.height, this.unit, this.duration, null, this.form);
	var animation_4 = new WebElements.AnimationObject(nextimage, "top", this.height, 0, this.unit, this.duration, null, this.form);
	
	var animation_5 = new WebElements.AnimationObject(currentimage, "display", "", "none", "", 0, null, null);
	
	// create groups for animation objects and put them into
	// the animation chain
	this.animator.animation_chain.addAnimationGroup(new WebElements.AnimationGroup(new Array(animation_1, animation_2)));
	this.animator.animation_chain.addAnimationGroup(new WebElements.AnimationGroup(new Array(animation_3, animation_4)));
	this.animator.animation_chain.addAnimationGroup(new WebElements.AnimationGroup(animation_5));
}

WebElements.ImageShifter.prototype.createBlindupAnimation = function(direction) {
	
	var currentimage = this.images[this.activeimage];
	var nextimage = this.images[(direction == "forward" || direction == "random") ? this.nextimage : this.previousimage];
	
	// create animations to be executed
	var animation_1 = new WebElements.AnimationObject(nextimage, "top", 0, this.height, this.unit, 0, null, null);
	var animation_2 = new WebElements.AnimationObject(nextimage, "display", "none", "", "", 0, null, null);
	var animation_3 = new WebElements.AnimationObject(nextimage, "zIndex", "auto", 100, "", 0, null, null);
	
	var animation_4 = new WebElements.AnimationObject(nextimage, "top", this.height, 0, this.unit, this.duration, null, this.form);
	
	var animation_5 = new WebElements.AnimationObject(currentimage, "display", "", "none", "", 0, null, null);
	var animation_6 = new WebElements.AnimationObject(nextimage, "zIndex", 100, "auto", "", 0, null, null);
	
	// create groups for animation objects and put them into
	// the animation chain
	this.animator.animation_chain.addAnimationGroup(new WebElements.AnimationGroup(new Array(animation_1, animation_2, animation_3)));
	this.animator.animation_chain.addAnimationGroup(new WebElements.AnimationGroup(animation_4));
	this.animator.animation_chain.addAnimationGroup(new WebElements.AnimationGroup(new Array(animation_5, animation_6)));
}

WebElements.ImageShifter.prototype.startMainLoop = function() {
	
	// only start shifting images, if there are more than one image
	if(this.images.length > 1)
	{
		this.running = true;
		
		var self = this;
		
		this.timeout_id = setTimeout(function() { self.mainLoop(); }, this.lifecycle);
	}
}

WebElements.ImageShifter.prototype.stopMainLoop = function() {
	
	clearTimeout(this.timeout_id);
	
	this.running = false;
}

WebElements.ImageShifter.prototype.toggleMainLoop = function() {
	
	if(this.running) 	this.stopMainLoop();
	else 				this.startMainLoop();
}

WebElements.ImageShifter.prototype.mainLoop = function() {
	
	var self = this;
	
	this.shiftImage(this.direction);
	
	this.timeout_id = setTimeout(function() { self.mainLoop(); }, this.lifecycle);
}
