/* 
	jQuery horizontal distribute plugin:
	
	verson: 0.1 - really, really not tested!
	author: Ben Hull www.benhull.info
	requires: jQuery 1.3 or later (will run on 1.2.x with the exception of 'refreshOnResize').
*/

(function($) {
	$.fn.distribute = function(options) {
	  // mix any set options with the defaults
	  var opts = $.extend({}, $.fn.distribute.defaults, options);
	  // iterate and distribute each matched element

	  return this.each(function() {
	  
	    container = $(this);	    
	    distributor.numberOfChildren = container.children(':visible').length;
			distributor.totalChildrenWidth = 0 
			
			//Prep the children and work out their width
		  container.children(':visible').each(function(){
				//zero the properties that will be changed by the distributor:
					var rowItem = $(this);
					if (opts.leftChildSelector || opts.rightChildSelector) {
						if (opts.leftChildSelector) {
							rowItem.children(opts.leftChildSelector).css(opts.spaceMethodLeft, 0);
						} else {
							rowItem.css(opts.spaceMethodLeft, 0);
						}
						if (opts.rightChildSelector) {
							rowItem.children(opts.rightChildSelector).css(opts.spaceMethodRight, 0);
						} else {
							rowItem.css(opts.spaceMethodRight, 0);
						}
					} else if (opts.childSelector) { //Reset the spacing on child elements if selected
						rowItem.children(opts.childSelector)
							.css(opts.spaceMethodLeft, 0)
							.css(opts.spaceMethodRight, 0)
					} else {
						rowItem
							.css(opts.spaceMethodLeft, 0)
							.css(opts.spaceMethodRight, 0)
					}
					
					rowItem
							.removeClass(opts.startOfRowClass)
							.removeClass(opts.endOfRowClass);
				
				distributor.totalChildrenWidth += $(this).width();
		  });
		
		  //Determine the ideal number of rows:
		  distributor.requiredRows = Math.ceil(distributor.totalChildrenWidth/(container.width()+opts.bufferSize));
		  
		  //Split the items into rows:
			distributor.rows = arrayToGroups(container.children(':visible'), distributor.requiredRows);
			
			//Distribute each row:
			for (var r=0;r<distributor.rows.length;r++) {
				var adjustedWidth = ($.browser.msie && $.browser.version < 7.0) ? container.width() : container.width() - opts.bufferSize; //IE6 Freaks out at using bufferSize here - I don't yet know why
				var	thisRow = distributor.rows[r],		
						rowWidth = adjustedWidth,
						contentWidth = 0,
						surplus = 0,
						leftSpace, 
						rightSpace;
		
				for (var i=0;i<thisRow.length;i++) {
					contentWidth += $(thisRow[i]).width();
				}
		
				surplus = rowWidth - contentWidth;
					
				if (Math.floor(surplus/thisRow.length) % 2 == 0) {
					//surplus is even (split equally).
					leftSpace = Math.floor((surplus/thisRow.length)/2);
					rightSpace = Math.floor((surplus/thisRow.length)/2);
				} else {
					//surplus is odd (put the extra pixel on the right).
					leftSpace = Math.floor((surplus/thisRow.length)/2);
					rightSpace = Math.ceil((surplus/thisRow.length)/2);
				}
				
				for (var c=0;c<thisRow.length;c++) {
					if (opts.leftChildSelector || opts.rightChildSelector) {
					
					//add classes to the start and end of each row:

						if (opts.leftChildSelector) {
							$(thisRow[c]).children(opts.leftChildSelector).css(opts.spaceMethodLeft, leftSpace);
						} else {
							$(thisRow[c]).css(opts.spaceMethodLeft, leftSpace);
						}
						
						if (opts.rightChildSelector) {
							$(thisRow[c]).children(opts.rightChildSelector).css(opts.spaceMethodRight, rightSpace);
						} else {
							$(thisRow[c]).css(opts.spaceMethodRight, rightSpace);
						}
						
					} else if (opts.childSelector) { //Apply the spacing to a child element if selected
						$(thisRow[c]).children(opts.childSelector)
							.css(opts.spaceMethodLeft, leftSpace)
							.css(opts.spaceMethodRight, rightSpace);
					} else { //Apply the spacing to the element itself
							$(thisRow[c])
							.css(opts.spaceMethodLeft, leftSpace)
							.css(opts.spaceMethodRight, rightSpace);
					}
					if (c == 0) {
						//rightSpace = leftSpace + rightSpace;
						//leftSpace = 0;
						$(thisRow[c]).addClass(opts.startOfRowClass);
					} else if (c == thisRow.length-1) {
						//leftSpace = leftSpace + rightSpace;
						//rightSpace = 0;
						$(thisRow[c]).addClass(opts.endOfRowClass);
					}
				}							
			}
			
			//Allow the distributor to re-run when the window is resized (useful because it is triggered on text resize/zoom)
			//This is broken at the moment!
			if (opts.refreshOnResize && $(window).one) {
				$(window).one("resize", function(){
					container.distribute(options);
				});
			}
	  });
	};
	
	// private function for debugging
	function debug($obj) {
	  if (window.console && window.console.log) {
	    //window.console.log('distribute selection count: ' + $obj.size());
	  }
	};

	//Split an array into evenly sized groups
	var arrayToGroups = function(source, groups) {  
		var grouped = [],
				groupSize = Math.ceil(source.length/groups),
				queue = source;
		
		for (var r=0;r<groups;r++) {
			grouped.push(queue.splice(0, groupSize));			
		}
		return grouped;
	}
	
	// private settings
	var distributor = {
		container: false,
		rows: false,
		numberOfChildren: 0,
		totalChildrenWidth: 0
	}
	
	// plugin defaults
	$.fn.distribute.defaults = {
	  childSelector: false, 							// A filter to select children of each element and apply spacing to them (instead of to the element itself). Use '*:first' to apply to the first child, regardless of type
	  leftChildSelector: false,
	  rightChildSelector: false, 					// If you need to specify separate left/right selectors (useful for sliding doors)
	  spaceMethodLeft: 'padding-left', 		// The css rule to add space to (needs to be something that accepts a px value). margin-left, padding-left, and border-left-width all work.
	  spaceMethodRight: 'padding-right', 	// Same as spaceMethodLeft, but for the right side.
	  startOfRowClass: 'startOfRow', 			// Apply a class to the first item in each row (if the list breaks into multi-rows)
	  endOfRowClass: 'endOfRow', 					// Apply a class to the last item in each row (if the list breaks into multi-rows)
	  refreshOnResize: false, 						// Run the calculation again when the window resizes (helpful for text resize/zoom, broken in FF)
	  bufferSize: 0 											// A width buffer to add breathing room to the container - helpful for fine-tuning widths so new rows don't trun up on resize/zoom.
	};

})(jQuery);
