// Grid Solver (c) Dominic Szablewski - www.phoboslab.org

var gridSize = 32; // Size of a grid unit in pixels
var gridMinWidth = 6; // Minimum grid width in grid units

var gridWidth = 0;
var grid = null;

// CSS-Class, width and height of the boxes in grid units
var boxDef = {
	'box0': {'width': 6, 'height': 9},
	'box1': {'width': 4, 'height': 6},
	'box2': {'width': 4, 'height': 3},
	'box3': {'width': 2, 'height': 3}
};

// This function is called, when the grid is fully loaded. After that, it
// calls itself every 250ms, to check if the available grid width has changed
function gridSolve( cid ) {
	
	window.setTimeout("gridSolve('"+cid+"')", 250);
	
	// Get the pixel widht of the container element
	var container = document.getElementById(cid);
	var newWidth = parseInt( container.offsetWidth );
	var newGridWidth = parseInt( newWidth / gridSize ); 
	
	newGridWidth = newGridWidth < gridMinWidth ? gridMinWidth : newGridWidth;

	if( gridWidth == newGridWidth ) {
		// Width hasn't changed since our last run - nothing to do here
		return; 
	}
	else {
		// Adjust width and continue
		gridWidth = newGridWidth;
	}
	
	// Remove all boxes from the container and store them in an array
	boxes = new Array();
	while( container.hasChildNodes() ) {
		e = container.removeChild( container.firstChild );
		if( e.tagName == 'DIV' ) {
			boxes.push( e );
		}
	}

	// Initialise a new grid
	grid = new Array( gridWidth );
	for( var i = 0; i < grid.length; i++ ) {
		grid[i] = 0;
	}

	// And insert every box again
	for(var i = 0; i < boxes.length; i++) {
		insertThumb( boxes[i], cid ) 
	}
}

// Calculate the position of the thumb
// This function is similliar to the PHP function GridSolver::insert()
function insertThumb( box, cid ) {

	// Size for this box
	var boxWidth = boxDef[box.className]['width'];
	var boxHeight = boxDef[box.className]['height'];
		
	// Height of the grid
	var maxHeight = 0; 
	
	// Height of the grid at the last position
	var currentHeight = -1;
	
	// Find free spots within the grid and collect them in an arry
	// A spot is a area in the grid with equal height
	var spotWidth = 0; // Width of the spot in grid units
	var spotLeft = 0; // Position in the grid (relative to left border)
	var freeSpots = new Array();
	for( var i = 0; i < grid.length; i++) {
		
		// Height is the same as at the last position?
		// -> increase the size of this spot
		if( currentHeight == grid[i] ) {
			spotWidth++;
		}
		
		// The height is different from the last position, and our current spot 
		// is wider than 0
		if( (currentHeight != grid[i] || i+1 == grid.length) && spotWidth > 0) {
			var spot = {
				'width': spotWidth,
				'left': spotLeft,
				'height': currentHeight
			};
			freeSpots.push( spot );
			
			spotWidth = 1;
			spotLeft = i;
		}
		
		// Increase spot width if this is the first run
		else if( spotWidth == 0 ) {
			spotWidth = 1;
		}
		
		currentHeight = grid[i];
		if( grid[i] > maxHeight ) {
			maxHeight = grid[i];
		}
	}
		
	// Loop through all found spots and rate them, based on their size and height
	// This way the smallest possible spot in the lowest possible height is filled
	var targetHeight = 0;
	var targetLeft = 0;
	var bestScore = -1;	
	
	// Default spot (left border) if we don't find a better one
	for( var j = 0; j < boxWidth; j++ ) {
		if( grid[j] > targetHeight ) {
			targetHeight = grid[j];
		}
	}
	var newHeight = targetHeight + boxHeight;
		
	for( var i = 0; i < freeSpots.length; i++ ) {
		
		// Difference of the height of this spot to the total height of the grid
		var heightScore = ( maxHeight - freeSpots[i]['height'] );
		
		// Relation of the required and the available space
		var widthScore = boxWidth / freeSpots[i]['width'];
		
		// The score for this spot is calculated by these both criteria
		var score = heightScore * heightScore  + widthScore * 6;
		
		// Is the score for this spot higher than for the last one we found?
		if( freeSpots[i]['width'] >= boxWidth && score > bestScore ) {
			targetHeight = freeSpots[i]['height'];
			targetLeft = freeSpots[i]['left'];
			newHeight = freeSpots[i]['height'] + boxHeight;
			bestScore = score;
		}
	}	
	
	// Adjust grid height
	for( var j = 0; j < boxWidth; j++ ) {
		grid[targetLeft  + j] = newHeight;
	}
	
	// Insert the box into our document
	var container = document.getElementById( cid );
	container.appendChild( box );
	box.style.left = (targetLeft * gridSize) + 'px';
	box.style.top =  (targetHeight * gridSize) + 'px';
	container.style.height = (maxHeight * gridSize) + 'px';
	return true;
}