text: /*!
   * PerfectMasonry extension for Isotope
   *
   * Does similar things as the Isotopes "masonry" layoutmode, except that this one will actually go back and plug the holes
   * left by bigger elements, thus making a perfect brick wall. Profit!
   * 
   * Usage:
   * 	$('#grid').isotope({
   * 		layoutMode: 'perfectMasonry',
   *		perfectMasonry: {
   *			layout: 'horizontal',		// Set layout as vertical/horizontal (default: vertical)
   *			columnWidth: 200,			// Set/Prefer columns to x wide (default: width of first tile)
   *			rowHeight: 200,				// Set/Prefer rows to y high (default: height of first tile)
   * 
   *			liquid: true,				// Set layout as liquid (default: false)
   *			cols: 3,					// Force to have x columns (default: null)
   *			rows: 3,					// Force to have y rows (default: null)
   *			minCols: 3,					// Set min col count (default: 1)
   *			minRows: 3,					// Set min row count (default: 1)
   *			maxCols: 5,					// Set max col count (default: 9999)
   *			maxRows: 4					// Set max row count (default: 9999)
   * 		}
   * 	});
   *
   * 
   * @author Mikko Tikkanen, Zonear Ltd. <contact@zonear.com>
   */
  ;(function($, undefined) {
  	var version = '1.2.1';
  	var isotope = null,
  		$context = null,
  		$container = null,
  		isFirstRun = true;
  	
  	$.extend($.Isotope.prototype, {
  
  		/**
  		 * Reset layout properties
  		 *
  		 * Runs before any layout change
  		 * -------------------------------------------------------------------------------------------------------- */
  		_perfectMasonryReset: function() {
  			var isVertical = this.options.perfectMasonry.layout != 'horizontal',
  				isLiquid = this.options.perfectMasonry.liquid == true;
  			
  			// Do things on a first run
  			if(isFirstRun) {
  				isFirstRun = false;
  				isotope = this;
  				$context = $(this.element.context);
  				$container = $context.parent();
  				
  				// Make sure we have min/maxCols & rows
  				this.options.perfectMasonry.minCols = this.options.perfectMasonry.minCols || 1; 
  				this.options.perfectMasonry.minRows = this.options.perfectMasonry.minRows || 1;
  				this.options.perfectMasonry.maxCols = this.options.perfectMasonry.maxCols || 9999; 
  				this.options.perfectMasonry.maxRows = this.options.perfectMasonry.maxRows || 9999;
  			}
  			
  			// For liquid layout, replace default resize handler with forced relayout (outside firstRun as Isotope grid can be destroyed and created on the fly)
  			if(isLiquid && $._data(window, 'events').smartresize) {
  				$(window).off('smartresize.isotope');
  				$(window).on('resize.isotope.perfectmasonry', function() {
  					if(!$context.hasClass('isotope')) { return; }
  					$context.isotope('reLayout');
  				});
  			}
  			
  			// Setup layout properties ---------------------------------------------------
  			var properties = this.perfectMasonry = {};
  			
  			// Fill properties with columnWidth and rowHeight (true argument)
  			this._getSegments();
        		this._getSegments(true);
        		
        		// ...and with cols & rows
  			this._perfectMasonryGetSegments();
        		
  			// Handle liquid layout (cols, rows & sizes must be calculated on the fly)
  			if(isLiquid) {
  				var width = $container.width(),
  					height = $container.height();
  					
  				// Make sure we have colwidth & rowheight (get it from the calculated )
  				this.options.perfectMasonry.columnWidth = this.options.perfectMasonry.columnWidth || properties.columnWidth;
  				this.options.perfectMasonry.rowHeight = this.options.perfectMasonry.rowHeight || properties.rowHeight;
  				
  				// Figure out how many cols & rows either have been set or can be fit into the container (also make sure we're still between min/max)
  				properties.cols = this.options.perfectMasonry.cols || Math.floor(width / this.options.perfectMasonry.columnWidth);
  				properties.rows = this.options.perfectMasonry.rows || Math.floor(height / this.options.perfectMasonry.rowHeight);
  				properties.cols = Math.min(Math.max(properties.cols, this.options.perfectMasonry.minCols), this.options.perfectMasonry.maxCols);
  				properties.rows = Math.min(Math.max(properties.rows, this.options.perfectMasonry.minRows), this.options.perfectMasonry.maxRows);
  								
  				// Recalculate accurate width/height so that the whole available space is used
  				var diff = (isVertical ? properties.columnWidth / (width / properties.cols) : properties.rowHeight / (height / properties.rows));
  				properties.columnWidth = Math.floor(properties.columnWidth / diff);
  				properties.rowHeight = Math.floor(properties.rowHeight / diff);
  			}
  			
  			// Create top row of the grid
  			properties.grid = new Array(this.perfectMasonry.cols);
  
  			// Set container dimensions to 0
  			properties.containerHeight = 0;
  			properties.containerWidth = 0;
  	    },
  
  
  
  	    /**
  		 * Create layout
  		 * -------------------------------------------------------------------------------------------------------- */
  		_perfectMasonryLayout: function($elems) {
  			var instance = this,
  				properties = this.perfectMasonry,
  				isVertical = instance.options.perfectMasonry.layout != 'horizontal',
  				isLiquid = instance.options.perfectMasonry.liquid == true;
  			
  			// Create first set of the grid
  			properties.grid = new Array(properties[(isVertical ? 'cols' : 'rows')]);
  			
  			// Loop each element
  			$elems.each(function() {
  				var $this  = $(this);
  				
  				// Calculate col & row spans (with liquid layouts, store desired width as element data)
  				var colSpan = (isLiquid ? $this.data('colSpan') : Math.ceil($this.outerWidth() / (properties.columnWidth + 1))),
  					rowSpan = (isLiquid ? $this.data('rowSpan') : Math.ceil($this.outerHeight() / (properties.rowHeight + 1)));
  				
  				// For the first run with liquid layout, calculate sizes
  				if(!colSpan) {
  					colSpan = Math.ceil($this.outerWidth(true) / (properties.columnWidth + 1));
  					rowSpan = Math.ceil($this.outerHeight(true) / (properties.rowHeight + 1));
  					$this.data('colSpan', colSpan);
  					$this.data('rowSpan', rowSpan);
  				}
  				
  				
  				/* Do the layout
  				 * -------------------------------------------------------------------------------- */
  				
  				// Set spans
  				var aSpan = (isVertical ? colSpan : rowSpan);
  				var bSpan = (isVertical ? rowSpan : colSpan);
  				
  				// Bigger tiles can't fit into the last primary (though keep it still at least as 1)
  				var max = Math.max((isVertical ? properties.cols - colSpan : properties.rows - rowSpan) + 1, 1);
  								
  				// Loop through/create primaries (set hard limit of 10.000 to prevent endless loop)
  				var a = -1, x = 0, y = 0;
  				while(++a < 10000) {
  					properties.grid[a] = properties.grid[a] || [];
  					
  					// Go through the secondaries in the primary, set secondary and tile
  					for (var b = 0; b < max; b++) {
  						var tile = properties.grid[a][b];
  							
  						// If the tile is not free, move to the next one immediately
  						if(tile) { continue; }
  
  						// Tiles spanning to multiple rows/columns - Check if it'll fit
  						var doesFit = true;
  						if(colSpan > 1 || rowSpan > 1) {
  							for (var i = 0; i < aSpan; i++) {
  								for (var j = 0; j < bSpan; j++) {
  									properties.grid[a+j] = properties.grid[a+j] || [];
  									if(properties.grid[a+j][b+i]) { doesFit = false; break; }
  								}
  
  								// If it doesn't fit, don't waste our time looping
  								if(!doesFit) { break; }
  							}
  						}
  						if(!doesFit) { continue }
  						
  
  						// Set all the cells as occupied
  						for (var i = 0; i < aSpan; i++) {
  							for (var j = 0; j < bSpan; j++) {
  								properties.grid[a+j][b+i] = true;
  							}
  						}
  						
  						// Set x & y values
  						var x = a, y = b;
  						if(isVertical) { var x = b, y = a; }
  						
  						// Update container dimensions
  						properties.containerWidth = Math.max(properties.containerWidth, (x + aSpan) * properties.columnWidth);
  						properties.containerHeight = Math.max(properties.containerHeight, (y + bSpan) * properties.rowHeight);
  						
  						// In case of liquid layout, set element size full width/height
  						if(instance.options.perfectMasonry.liquid == true) {
  							$this.css({
  								width: properties.columnWidth * colSpan,
  								height: properties.rowHeight * rowSpan
  							});
  						}
  
  						// Set the element location and GTFO
  						instance._pushPosition($this, x*properties.columnWidth, y*properties.rowHeight);
  						return;
  					}
  				}
  				
  
  				// If we got all the way down to here, the element doesn't fit - Hide it
  				instance._pushPosition($this, -9999, -9999);
  			});
  		},
  		
  		
  		
  	    /**
  		 * Get container size
  		 *
  		 * For resizing the container
  		 * -------------------------------------------------------------------------------------------------------- */
  	    _perfectMasonryGetContainerSize: function() {
  			return {
  				width: this.perfectMasonry.containerWidth,
  				height: this.perfectMasonry.containerHeight
  			};
  	    },
  		
  		
  		
  	    /**
  		 * Resize changed
  		 *
  		 * Figure out if layout changed
  		 * -------------------------------------------------------------------------------------------------------- */
  	    _perfectMasonryResizeChanged: function() {
  	    	var properties = this.perfectMasonry;
  
  	    	// Store old values and calculate new numbers
  	    	var oldCols = properties.cols,
  	    		oldRows = properties.rows;
  	    	this._perfectMasonryGetSegments();
  			
  			// If new count was different, force layout change
  			if(this.options.perfectMasonry.layout == 'horizontal' && oldRows !== properties.rows) { return true; }
  			if(oldCols !== properties.cols) { return true; }
  			
  	    	return false;
  	    },
  		
  		
  		
  		
  	    /**
  		 * Private
  		 * Do segment calculations by hand
  		 * -------------------------------------------------------------------------------------------------------- */
  		_perfectMasonryGetSegments: function() {
  			var properties = this.perfectMasonry;
  			var parent = this.options.perfectMasonry.parent || this.element.parent();
  			
  			// Calculate columns
  			var parentWidth = parent.width();
  			properties.cols = Math.floor(parentWidth / properties.columnWidth) || 1;
  
  			// Calculate rows
  			var parentHeight = parent.height();
  			properties.rows = Math.floor(parentHeight / properties.rowHeight) || 1;
  		}
  	});
  	
  	
  })(jQuery);
  
  