/**
 * This plugin automatically vertically aligns the children of the selected
 * container. This will only work correctly if there is no height set through
 * CSS for the children.
 */
(function($)
{
	$.fn.alignVertical = function(children)
	{
		// This plugin is dependent on the boundaries plugin, and since we can only change this file,
		// just place it here.
		if (!$.fn.boundaries)
		{
			(function($)
			{
				function test(boundaries)
				{
					$('<div />')
					.appendTo('body')
					.css('border', '2px solid black')
					.width(boundaries.width - 4)
					.height(boundaries.height - 4)
					.css(
					{
						position: 'absolute',
						top: boundaries.top,
						left: boundaries.left
					});
				}
				
				function getBoundaries(node, includeMargin)
				{
					var	$node = $(node);
					
					// In WebKit browsers the width and height of the .module <div> causes corrupt width and height values.
					if ($node.is('.module'))
					{
						$node.css('display', 'block !important');
					}
					
					var	boundaries = {},
						offset = $node.offset(),
						width = $node.outerWidth(includeMargin),
						height = $node.outerHeight(includeMargin);
					
					// We need to ceil, otherwise Firefox might be one pixel off.
					offset.left = Math.ceil(offset.left);
					offset.top = Math.ceil(offset.top);
					
					if (includeMargin)
					{
						offset.left = offset.left - parseInt($node.css('margin-left'), 10);
						offset.top = offset.top - parseInt($node.css('margin-top'), 10);
					}
					
					boundaries.left = offset.left;
					boundaries.right = offset.left + width;
					boundaries.top = offset.top;
					boundaries.bottom = offset.top + height;
					boundaries.width = width;
					boundaries.height = height;
					
					return boundaries;
				}
				
				$.fn.boundaries = function(includeMargin)
				{
					return getBoundaries(this[0], includeMargin);
				};
				
				$.fn.realBoundaries = function(includeMargin)
				{
					var real = {};
					
					this.find('*:visible').andSelf().each(function()
					{
						var b = getBoundaries(this, includeMargin);
						
						if (b.width === 0 || b.height === 0)
						{
							return;
						}
						
						if (b.left < real.left || real.left === undefined) real.left = b.left;
						if (b.right > real.right || real.right === undefined) real.right = b.right;
						if (b.top < real.top || real.top === undefined) real.top = b.top;
						if (b.bottom > real.bottom || real.bottom === undefined) real.bottom = b.bottom;
					});
					
					if (real.left !== undefined)
					{
						real.width = real.right - real.left;
						real.height = real.bottom - real.top;
					}
					
					//test(real);
					
					return real;
				};
			})
			(jQuery);
		}
		
		return this.each(function()
		{
			var	that = $(this),
				
				items = typeof children === 'string' ? that.find(children) : children,
				
				row = [],
				
				containerWidth = that.width(),
				
				restWidth = 0,
				
				maxHeight = 0,
				
				images = that.find('img'),
				
				completedImages = 0;
			
			function handleRow()
			{
				if (row.length)
				{
					$(row).each(function()
					{
						var $cell = $(this);
						$cell.height(maxHeight - ($cell.outerHeight(false) - $cell.height()));
					})
					
					row = [];
				}
			}

			function handleImage(invoker)
			{
				if (++completedImages === images.length)
				{
					align();
				}
			}
			
			function align()
			{
				items.each(function()
				{
					var b = $(this).realBoundaries(false);
					
					if (restWidth - b.width >= 0)
					{
						restWidth -= b.width;
						
						if (maxHeight < b.height)
						{
							maxHeight = b.height;
						}
					}
					else
					{
						// Handle previous row.
						handleRow();
						
						restWidth = containerWidth - b.width;
						
						maxHeight = b.height;
					}
					
					row.push(this);
				});
				
				handleRow();
			}
			
			if (images.length)
			{
				images.each(function()
				{
					if (this.complete)
					{
						handleImage.call(this);
					}
					else
					{
						this.onload = this.onerror = this.onabort = handleImage;
					}
				});
			}
			else
			{
				align();
			}
		});
	};
})
(jQuery);

