/********************************************************************************
*	Grid Animation v 1.0.1 by Phillip Parr										*
*	http://wizpip.com															*
*																				*
*																				*
*	usage:																		*
*																				*
*	$('#mydiv').grid();															*
*																				*
*																				*
*	options:																	*
*																				*
*	bigSize		(default: 3) - the size of the focus div						*
*	selector	(default: div.post) - the element(s) to gridify					*
*	focus		(default: 'focus') - the class given to focus element			*
*																				*
*	callback - name of the function to call when changing selection. 			*
*	Passes div to update and 0 for closing or 1 for opening						*
*																				*
*	eg: $('#mydiv').grid({bigSize: 3, callback: loadContent});					*
********************************************************************************/

(function($) {
	
	$.fn.grid = function(options) {
		var opts = $.extend({}, $.fn.grid.defaults, options);
		
		return this.each(function() {
			var $this = $(this);
		    var o = $.meta ? $.extend({}, opts, $this.data()) : opts;	
			o.sizeX, o.sizeY, o.fullSizeX, o.fullSizeY, o.boxes, o.across, o.grid, o.main = 0, o.mainX = 0, o.mainY = 0;
			$this.find(o.selector).css({position: 'absolute'});
		
			// assuming the first div is always the focus one
			o.sizeX = parseInt($this.find('div:first-child').next().width());
			o.sizeY = parseInt($this.find('div:first-child').next().height());
			o.fullSizeX = $this.find('div:first-child').next().outerWidth(true);
			o.fullSizeY = $this.find('div:first-child').next().outerHeight(true);
			o.boxes = $this.find(o.selector).length;
			
			calculatePositions(o, $this);
			
			if(o.callback) {
				(o.callback)($this.find(o.selector+':first'));
			}
	
			// change visible box
			$this.find(o.selector).click(function() {
			
				if($(this).hasClass(o.focus) || $this.find(o.selector).is(':animated')) return;
				var obj = $(this);
				if(o.callback) {
					(o.callback)($(this));
				}
				$this.find('div.'+o.focus).animate({width:o.sizeX + 'px', height:o.sizeY + 'px'}, function() {
					$this.find('div.'+o.focus).removeClass(o.focus); 
					o.main = parseInt(obj.attr('id').replace(/[a-z\-]*/, ''));						
					o = populateGrid(o);
					$this.find('#post-'+o.main).addClass(o.focus).css({width:o.sizeX + 'px', height:o.sizeY + 'px'});
					animateBoxes(o, $this, true);
				});
			});
			
			$(window).resizeComplete(function() {
				calculatePositions(o, $this);
			});			
		});
	};


	$.fn.grid.defaults = {
		bigSize: 3,
		selector: 'div.post',
		focus: 'focus'
	};
	
	
	function calculatePositions(o, $this) {
		o.across = Math.floor($(window).width() / o.fullSizeX);
		o = populateGrid(o);
		animateBoxes(o, $this, false);
	}
	
	
	// setup our grid
	function populateGrid(o) {
		var box = 0;
		o.grid = new Array();
	
		// knowing the box number means we can determine the starting position of the box in the grid too
		o.mainY = Math.floor(o.main / o.across);
		o.mainX = (o.main % o.across);	
		if(o.mainX + o.bigSize > o.across) o.mainX = o.across - o.bigSize;
		
		// this bit checks to see if we are on the bottom row(s) and moves up instead of down (unless there aren't enough rows)
		if(o.mainY + o.bigSize > Math.ceil((o.boxes + o.bigSize * o.bigSize - 1) / o.across)) o.mainY = Math.ceil(o.boxes / o.across) - (o.bigSize - 1);
		
		if (o.mainY < 0) o.mainY = 0;
		
		// place large box
		for(var i2 = o.mainY; i2 < o.mainY + o.bigSize; i2++) {
			for(var i = o.mainX; i < o.mainX + o.bigSize; i++) {
				if(typeof(o.grid[i]) == 'undefined') {
					o.grid[i] = new Array();
				}			
				o.grid[i][i2] = o.main;
			}
		}
	
		// flow other boxes around the main one
		for(var i2 = 0; i2 < Math.ceil((o.boxes + o.bigSize * o.bigSize - 1) / o.across); i2++) {
			for(var i = 0; i < o.across; i++) {
				if(box == o.main) box++;
				if(box >= o.boxes) break;
				if(typeof(o.grid[i]) == 'undefined') {
					o.grid[i] = new Array();
				}
				if(o.grid[i][i2] != o.main) {
					o.grid[i][i2] = box++;
				}
			}
		}
		return o;
	}
	
	
	// make them move
	function animateBoxes(o, $this, scroll) {

		// discover a left pad value to 'center' grid later
		o.pad = (Math.floor(($(window).width() - $(window).getScrollbarWidth()) - (o.fullSizeX * o.across)) / 2);
		
		fullHeight = 1;
	
		for(var i in o.grid) {
			for(var i2 in o.grid[i]) {
				if (fullHeight < i2) fullHeight = i2;
				if(o.grid[i][i2] == o.main && (o.mainX != i || o.mainY != i2)) continue;
				$this.find('#post-'+o.grid[i][i2]).animate({left: ((i * o.fullSizeX) + o.pad) + 'px',top: i2 * o.fullSizeY + 'px'});
			}
		}
		fullHeight++;
		$this.height(fullHeight*o.fullSizeY);
		$this.find('div.'+o.focus).animate({width:o.fullSizeX * (o.bigSize - 1) + o.sizeX + 'px', height:o.fullSizeY * (o.bigSize - 1) + o.sizeY + 'px'}, function() { 
			if (scroll && !$(this).isVisible()) {
				$('html,body').animate({scrollTop: $this.find('div.'+o.focus).offset().top - parseInt($this.find(o.selector).css('margin-top')) }, 750);
			}
		});
	}
	
	
	jQuery.fn.resizeComplete = function(callback) {

		var element = this;
		var height = element.height();
		var width = element.width();
		var monitoring = false;
		var timer;
		
		function monitorResizing() {
		
			monitoring = true;
			var newHeight = element.height();
			var newWidth = element.width();
			
			if(newHeight != height || newWidth != width) {
				height = newHeight;
				width = newWidth;
				timer = setTimeout(function() { monitorResizing() },200);
			} else {
				monitoring = false;
				clearTimeout(timer);
				callback();
			}
		}
		
		function onResize() {
		
			if(monitoring) return;
				monitorResizing();
		}
			
		if($.browser.mozilla) {
			element.resize(callback);
		} else {
			element.resize(onResize);
		}
	}
	
	jQuery.fn.getScrollbarWidth = function() {
	
		var scrollbarWidth;
	
		if ( !scrollbarWidth ) {
			if ( $.browser.msie ) {
				var $textarea1 = $('<textarea cols="10" rows="2"></textarea>').css({ position: 'absolute', top: -1000, left: -1000 }).appendTo('body'), $textarea2 = $('<textarea cols="10" rows="2" style="overflow: hidden;"></textarea>').css({ position: 'absolute', top: -1000, left: -1000 }).appendTo('body');
				scrollbarWidth = $textarea1.width() - $textarea2.width();
				$textarea1.add($textarea2).remove();
			} else {
				var $div = $('<div />').css({ width: 100, height: 100, overflow: 'auto', position: 'absolute', top: -1000, left: -1000 }).prependTo('body').append('<div />').find('div').css({ width: '100%', height: 200 });
				scrollbarWidth = 100 - $div.width();
				$div.parent().remove();
			}
		}
		return scrollbarWidth;
	}
	
	jQuery.fn.isVisible = function() {
		var elem = $(this);
    	var docViewTop = $(window).scrollTop();
		var docViewBottom = docViewTop + $(window).height();
	
		var elemTop = $(elem).offset().top;
		var elemBottom = elemTop + $(elem).height();
	
		return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom) && (elemBottom <= docViewBottom) &&  (elemTop >= docViewTop));
	}


})(jQuery);