//= require <mootools-core-1.3-full-nocompat>
//= require <uiframework/UIComponent>
var Gallery = function()
{
	this.Extends = UIComponent;

	//////////////////////////////////////////////////
	// Children

	/**
	 * Wrapper for the thumbnails
	 *
	 * @type UIComponent
	 */
	this.thumbContainer = null;
	/**
	 * Currently displayed image
	 *
	 * @type UIComponent
	 */
	this.image = null;

	////////////////////////////////////////////////////
	// Properties
	
	/**
	 * Storage for the ClassFactory used to generate instances
	 * of the thumbnails used in this control.
	 *
	 * @type ClassFactory
	 */
	this._thumbnailRenderer = null;

	/**
	 * Storage for the dataProvider used in this control.
	 *
	 * @type Array
	 */
	this._dataProvider = null;

	/**
	 * Storage for the active thumbnails.
	 *
	 * @type Array
	 */
	this._thumbnails = null;

	/**
	 * Repository for inactive thumbnails
	 * waiting to be reused.
	 *
	 * @type Array
	 */
	this.freedThumbnails = null;

	/**
	 * Flag indicating the dataProvider has changed.
	 *
	 * @type Boolean
	 */
	this.dataProviderChanged = false;

	/**
	 * Index of the currently selected image
	 *
	 * @type int
	 */
	this._selectedIndex = 0;

	/**
	 * The previous selected index.
	 * 
	 * @type int
	 */
	this._oldSelectedIndex = -1;

	/**
	 * Flag indicating whether the selectedIndex has changed.
	 * 
	 * @type int
	 */
	this.selectedIndexChanged = false;

	/**
	 * @ignore
	 */
	this.initialize = function()
	{
		this.parent('div',
		{
			'class' : 'gallery',
			styles:{
				"position":"relative"
			}
		});
		// Initialize property defaults
		this._thumbnails = [];
		this.freedThumbnails = [];
	};

	/**
	 * @ignore
	 */
	this.commitProperties = function()
	{
		this.parent();
		if (this.dataProviderChanged)
		{
			this.buildGallery();

			this.dataProviderChanged = false;
		}

		if (this.selectedIndexChanged)
		{
			this.commitSelectedIndex();

			this.selectedIndexChanged = false;
		}
	};

	/**
	 * Creates the children used in this control.
	 */
	this.createChildren = function()
	{
		this.parent();

		this.image = new UIComponent('div', {
			"class":"galleryImageContainer"
		});
		this.addChild(this.image);
	};

	/**
	 * @ignore
	 */
	this.updateDisplayList = function(width, height)
	{
		this.parent(width, height);
		var maxW = 0;
		var maxH = 0;
		var col = 0;
		var row = 0;
		if (this._thumbnails && this._thumbnails.length)
		{
			var posX = 0;
			var posY = 0;
			var len = this._thumbnails.length;
			for (var i = 0; i < len; i++)
			{
				var thumb = this._thumbnails[i];
				maxW = Math.max(thumb.innerImg.measuredWidth(),  maxW);
				maxH = Math.max(thumb.innerImg.measuredHeight(), maxH);
			}
			// Second pass to uniform sizes
			var maxXBounds = 0;
			len =  this._thumbnails.length;
			for (i = 0; i < len; i++)
			{
				thumb = this._thumbnails[i];
				var img = thumb.innerImg;
				thumb.setActualSize(maxW, maxH);
				if (col == 2)
				{
					col = 0;
					row++;
					posX = 0;
					posY += thumb.height() + 5;
				}
				thumb.move(posX, posY);
				col++;
				posX +=  thumb.width() + 5;
				// Center the image
				img.move((maxW - img.width()) / 2, (maxH - img.height()) / 2);
				maxXBounds = Math.max(maxXBounds, thumb._x + thumb.getSize().x);
			}
			var bm = thumb.getBorderMetrics();
			this.thumbContainer.setActualSize(maxXBounds, posY + maxH + bm.top + bm.bottom);
			this.thumbContainer.move(0, (height - this.thumbContainer.height()) / 2);
			
			this.image.setActualSize(this.image.innerImg.width(), this.image.innerImg.height());
			var offsetX = this.thumbContainer._x + this.thumbContainer.width();
			posX = width - offsetX;
			this.image.move(offsetX + (posX - this.image.width()) / 2, (height - this.image.height()) / 2);
		}
	};

	////////////////////////////////////////////////////
	// Helper functions
	
	this.commitSelectedIndex = function()
	{
		if (this.image && this.image.innerImg)
		{
			this.image.removeChild(this.image.innerImg);
			this.image.innerImg = null;
		}
		if (this._selectedIndex != -1)
		{
			var innerImg;
			var data = this._dataProvider[this._selectedIndex].image;
			if (instanceOf(data, Element))
				innerImg = new UIComponent(data);
			else
			{
				innerImg = new UIComponent("img");
				innerImg.set(data);
			}
			this.image.innerImg = innerImg;
			this.image.addChild(innerImg);

			var thumb = this._thumbnails[this._selectedIndex];
			thumb.set("opacity", 1.0);
		}
		if (this._oldSelectedIndex != -1)
		{
			var oldThumb = this._thumbnails[this._oldSelectedIndex];
			oldThumb.set("opacity", .25);
		}
	}
	/**
	 * Creates the thumbnail container if it does 
	 * not already exist.
	 */
	this.createThumbnailContainer = function()
	{
		if (!this.thumbContainer)
		{
			this.thumbContainer = new UIComponent('div', {
				"class":"galleryThumbnailContainer"
			});
			this.addChild(this.thumbContainer);
		}
	};

	/**
	 * Builds the gallery component.
	 */
	this.buildGallery = function()
	{
		this.createThumbnailContainer();
		this.removeActiveThumbnails();
		if (this._dataProvider && this._dataProvider.length)
		{
			var len = this._dataProvider.length;
			for (var i = 0; i < len; i++)
			{
				var data = this._dataProvider[i];
				var thumbnail = data.thumbnail;
				var renderer = this.getFreedThumbnail(thumbnail);
				renderer.set("opacity", .25);
				renderer.set("tween", {
					duration:200
				});
				this.thumbContainer.addChild(renderer);
				this._thumbnails.push(renderer);
			}
			// Remove the existing image (if any)
			if (this.image.innerImg)
			{
				this.image.removeChild(this.image.innerImg);
				this.image.innerImg = null;
			}
			// Display the first image in the gallery
			this.commitSelectedIndex();
		}
	};

	/**
	 * Removes all active thumbnails from the
	 * DOM and stores the freed instances for
	 * later use.
	 */
	this.removeActiveThumbnails = function()
	{
		var i = this._thumbnails.length;
		while(i--)
		{
			this.thumbContainer.removeChild(this._thumbnails[i]);
			this.freedThumbnails.push(this._thumbnails[i]);
		}
		this._thumbnails = [];
	};

	/**
	 * Gets a thumbnail instance.  If a previously
	 * freed thumbnail is not available, one is
	 * created with a class name of "galleryThumbnail"
	 *
	 * @return {UIComponent} The UIComponent wrapper for the img element.
	 */
	this.getFreedThumbnail = function(data /* Elements or Object*/)
	{
		var thumbnail = this.freedThumbnails.pop();
		var element = null;
		if (instanceOf(data, Element))
			element = data;
		if (!thumbnail)
		{
			thumbnail = new UIComponent("div", {
				"class":"galleryThumbnailWrapper"
			});
			var innerImg = new UIComponent(element || "img", {
				"class":"galleryThumb"
			});
			thumbnail.innerImg = innerImg;
			thumbnail.addChild(innerImg);
			thumbnail.addEventListener("mouseenter", this.thumbnail_mouseEnterHandler, false, 0, this);
			thumbnail.addEventListener("mouseleave", this.thumbnail_mouseLeaveHandler, false, 0, this);
			thumbnail.addEventListener("click", this.thumbnail_clickHandler, false, 0, this);
		}
		if (!element)
			thumbnail.innerImg.set(data);

		return thumbnail;
	};

	////////////////////////////////////////////////////
	// Event Handlers

	/**
	 * Triggers animations or other processes once
	 * the image has completed loading
	 *
	 * @param {UICevent} event The UICEvent dispatched
	 * when the image finishes loading.
	 */
	this.image_loadHandler = function(event /* UICEvent */)
	{
		
	};

	this.thumbnail_mouseEnterHandler = function(event /* UICEvent */)
	{
		var thumb = event.target;
		thumb.fade(1.0);
	};

	this.thumbnail_mouseLeaveHandler = function(event /* UICEvent */)
	{
		if (this._thumbnails.indexOf(event.target) == this._selectedIndex)
			return;
		var thumb = event.target;
		thumb.fade(.25);
	};

	this.thumbnail_clickHandler = function(event /* UICEvent */)
	{
		this.selectedIndex(this._thumbnails.indexOf(event.target));
	};

	////////////////////////////////////////////////////
	// getters / setters

	/**
	 * The currently selected index of the gallery
	 *
	 * @param {int} value The new selected index.
	 * @return {int} The currently selected index.
	 */
	this.selectedIndex = function(value /* int */)
	{
		if (arguments.length && Math.floor(value) != this._selectedIndex)
		{
			this._oldSelectedIndex = this._selectedIndex;
			this._selectedIndex = Math.floor(value);
			this.selectedIndexChanged = true;

			this.invalidateProperties();
			this.invalidateDisplayList();
		}
		return this._selectedIndex;
	}

	/**
	 * This control accepts an array of objects
	 * as the dataProvider.  Each object in the array
	 * is used to populate the thumbnailRenderers.
	 * 
	 * @param {Array} value An array of objects used to
	 * populate the thumbnailRenderers.
	 *
	 * @return {Array} The current value for the dataProvider.
	 */
	this.dataProvider = function(value /* Array */)
	{
		if (arguments.length)
		{
			this._dataProvider = value;
			this.dataProviderChanged = true;

			this.invalidateProperties();
			this.invalidateDisplayList();
		}
		return this._dataProvider;
	};
};
Gallery = new Class(new Gallery());
