/**
 * @author Jesse Hemminger
 */

 /**
 * Randomly replaces the images in the <ul> element specified by the elementId parameter
 * with images from the imageData array parameter. The randomly selected image is faded out
 * and the new image is faded in. The options object allows you to optionally specify a number of
 * blank spaces to leave in the list, the speed of the transitions, and
 * the lenght of the pause between transitions. As well you can specify an optional
 * second imageData array and how many imgaes from this array should be present in the list.
 * This is useful to create a random mixture of two types of images in a fixed proportion to
 * one another. For example if you want to have mostly thumbnail images of photos, but with
 * a few text images always mixed in. The photos might be samples of work and the text images
 * might be words describing your firm, your competences, or testemonials. If you use this optional
 * second imageData array you must specify a class name for the elements from this second array.
 * This is required in order to check if the randomly selected image to be replaced is from
 * this second array so that the program knows that it needs to place a new image from the
 * second array in the list.
 *
 * @param	elementId	string	The DOM id of the list of images, normally a <ul> element
 * @param	imageData	array	An array of objects with the image data. The objects in the
 * 								array need to have an imageURL attribute defined and can
 * 								optionally have the linkURL, caption and altText attributes defined.
 * 								{
 * 									imageURL: string, 
 * 									linkURL: string, 
 * 									altText: string, 
 * 									titleText: string, 
 * 									caption: string
 * 								}
 * @param	options		object	This paramiter is option. Its Structure is as follows:
 * 								{
 * 									random:					boolean,//determines if the slideshow plays in random order or in the order that they appear in the imageData array
 * 									captionClass:			string,	//if specified and if the imageData also specifies a caption, 
 * 																	//then a sibling element to the img element with the captionClass class 
 * 																	//will be search and its inner HTML replaced with the imageData caption value
 * 									imageListLength: 		int,	//not implemented. Would be used to build the list from scratch.
 * 									numBlankSpaces: 		int,	//number of blank <li> elements to leave in the list
 * 									blankSpaceClass: 		string,	//not implemented. class name for the <li> elements containing no image
 * 									transitionSpeed: 		int,	//the milliseconds
 * 									transitionPause: 		int,	//the length of time between transtions
 * 									additionalImageData: 	array,	//an array of objects with the image data. See imageData param above.
 * 									additionalImageClass: 	str,	//class name for the <li> elements containing images from this additional image data array
 * 									numAddlImgDisplayed: 	int		//not yet implemented. Could be implemented if this function were to build the list from 
 * 																	//scratch instead of just updating an existing list in the DOM
 * 								}
 */

var AnimatedImageList = new Class({
	options: {
		random: true,
		captionClass: "",
		imageListLength: 9,			//int		not implemented. Would be used to build the list from scratch.
		numBlankSpaces: 3,			//int		number of blank <li> elements to leave in the list
		blankSpaceClass: "",		//string	not implemented. class name for the <li> elements containing no image
		transitionSpeed: 500,		//int		the milliseconds
		transitionPause: 1000,		//int		the length of time between transtions
		additionalImageData: null,	//array		an array of objects with the image data. See imageData param above.
		additionalImageClass: "",	//str		class name for the <li> elements containing images from this additional image data array
		numAddlImgDisplayed: 2		//int		not yet implemented. Could be implemented if this function were to build the list from 
									//			scratch instead of just updating an existing list in the DOM
	},
	initialize: function(elementId, imageData, options) {
		this.elementId = elementId;
		this.imageData = imageData;
		this.setOptions(options);

		//list of currently displayed images
		this.currentlyDisplayedImageData = [];
		//list of not displayed images
		this.notDisplayedImageData = this.imageData.copy();
		//images that have already been displayed in this round
		this.alreadyDisplayedImageData = [];
		
		//list of currently displayed additional images
		//list of not displayed additional images
		//complete list of all additional images
		
		//window.addEvent('domready', this.domReadyHandler.bind(this));
		window.addEvent('load', this.onLoadHandler.bind(this));
	},
	onLoadHandler: function(e) {
		//first set things up
			//search for and store a reference to the DOM element with id = elementID
		this.listElement = $(this.elementId);
		//we need to find out which images are currently on display so that we don't end up with the same image on screen twice.
			//compare the imageData.imageURL's with the src param of the <img> tags currently in the DOM
			//we also need to set up a structure for keeping track of what is currently on display. or do we
			//isn't there a helper function to check if an element exists in the DOM?
			//yes there is a domready event in mootools on the window object
		//list of the imagesURLs that are currently on display on the screen
		var currentlyDisplayedURLs = [];
		this.listElement.getChildren().each(function(listItemElement) {
			var imageElement = $E('img', listItemElement);
			//currentlyDisplayedURLs.push(imageElement.getProperty('src'));
			this.imageData.each(function(item,index){
				if (item.imageURL == imageElement.getProperty('src')) {
					this.currentlyDisplayedImageData.push(item);
					this.notDisplayedImageData.remove(item);
					//make a reference to the corresponding imageData item for checking later
					imageElement.imageDataItem = item;
				}
			}, this);
		}, this);
		//I think I can assume that if the image is not passed in the imageData parameter it should not be included
		//in the slideshow. This would allow for an intro set of images that only is there at the beginning and
		//slowly gets replaced be the imageData set of images.
		
		//we need to preload the images that are not already being displayed.
			//we want to start this after the images that are currently displayed are finished loading?
			//that is why this whole whole function is attached with the onload event
		var images = [];
		this.imageData.each(function(item,index){
			images.push(item.imageURL);
		});
	    var options = {onComplete: this.startSlideShow.bind(this)};
		this.loadedImages = new Asset.images(images, options);
	},
	startSlideShow: function() {
		this.imageData.each(function(item,index){
			var img = this.loadedImages[index];
			if (item.altText) {
				img.setProperty('alt', item.altText);
			}
			if (item.titleText) {
				img.setProperty('title', item.titleText);
			}
			img.imageDataItem = item;
			if (item.linkURL) {
				var anchor = new Element('a', {href: insertImageData.linkURL});
				anchor.adopt(img);
				item.el = anchor;
			} else {
				item.el = img;
			}
		}, this);
		
		this.nextImage.delay(this.options.transitionPause, this);
	},
	nextImage: function() {
		//pick a random element from the list to replace
		var replaceListElement = this.listElement.getChildren().getRandom();
		var imageElement = $E('img', replaceListElement);
		
        var currentOpacity = imageElement.getStyle('opacity').toFloat();
		var transitionSpeed = this.options.transitionSpeed;
		var that = this;
        var options = {};
        options.duration = transitionSpeed * currentOpacity;
        options.onComplete = this.fadeOutComplete.bind(this, imageElement);
        fadeOut = new Fx.Style(imageElement, 'opacity', options);
        fadeOut.start(0);
	},
	fadeOutComplete: function(imageElement){
		//if the element we picked is blank the next list element we replace needs to be replaced blank
			//set a marker for the next transition
		
		//if the element we picked is one of the additional images, the next list element we replace needs to also be an additional image
			//set a marker for the next transtion
			
		//if the last element replaced wasn't blank (check the marker) we need to pick a random image
			//if the last element we replaced wasn't an additional image (check the marker)
				//pick the random image from the normal images
			//otherwise if the last element we replaced was an additional image (check the marker)
				//pick the random image from additional images
			//replace the random element with the random image
				//update the altText, caption and create a link if necessary
		//otherwise if the last element replaced was blank (check the marker) we don't need to pick a random image
			//just remove the image from the random element
			
		// when all of the images have been displayed once, reset the lists
		if (this.notDisplayedImageData.length == 0){
			this.notDisplayedImageData = this.alreadyDisplayedImageData.copy();
			this.alreadyDisplayedImageData = [];
		}
		
		// pick the next image to be displayed and move it from not displayed list to currently displayed list
		var insertImageData = this.notDisplayedImageData.getRandom();
		this.currentlyDisplayedImageData.push(insertImageData);
		this.notDisplayedImageData.remove(insertImageData);
		
		// if the image that we are replacing on-screen belongs to our imageData set
		// then we need to it from the currently displayed list to the already displayed list
		if (imageElement.imageDataItem) {
			this.currentlyDisplayedImageData.remove(imageElement.imageDataItem);
			this.alreadyDisplayedImageData.push(imageElement.imageDataItem);
		}
		
		// the element that will actually be replaced
		var replaceElement = imageElement;
		// if the image is inside a link (anchor tag), replace the whole link
		if (imageElement.getParent().getTag() == 'a') {
			replaceElement = imageElement.getParent();
		}
		
		// insert our new element before our old one
		insertImageData.el.setOpacity(0);
		insertImageData.el.injectBefore(replaceElement);
		
		// remove the old element
		replaceElement.remove();
		
		// fade our new element in
        var options = {};
        options.duration = this.options.transitionSpeed;
        options.onComplete = this.fadeInComplete.bind(this);
		fadeIn = new Fx.Style(insertImageData.el, 'opacity', options);
		fadeIn.start(1);
		
	},
	fadeInComplete: function(){
		this.nextImage.delay(this.options.transitionPause, this);
	}
});
AnimatedImageList.implement(new Options);
