/**
 * @author Sjors
 */
var GridManager = new Class({
	Implements: [Options],
	options: {
		minRowWidth: 3,
		maxRowWidth: 6,
		openCardWidth: 3,
		margin: 20
	},
	cards: new Array(),

	openCard: '',

	initialize: function (container, options) {
		this.setOptions(options);
		this.container = document.id(container);

		if (this.options.minRowWidth < this.options.openCardWidth) {
			throw new Error('GridManager:initialize - minimal row width cannot be smaller than open card width');
		}
	},

	distribute: function () {
		if (this.cards.length == 0) {
			Denham.showNoCardsMessage();
			return;
		}

		Denham.hideNoCardsMessage();

		// Determine the amount of cards to place in a row
		var rowWidth;
		rowWidth = Math.floor((document.getSize().x + this.options.margin - 40) / (this.options.closedOuterWidth + this.options.margin));
		rowWidth = rowWidth < this.options.minRowWidth ? this.options.minRowWidth : rowWidth;
		rowWidth = rowWidth > this.options.maxRowWidth ? this.options.maxRowWidth : rowWidth;

		var amountCards = this.cards.length;

      if (this.openCard != '') {
	  		// Walk through the cards in the card collection, find the open card and determine its index in the current sorting

			var openCardIndex;
			for (var i=0; i<amountCards; i++) {
				if (this.cards[i].id == this.openCard) {
					openCardIndex = i;
					break;
				}
			}

			// Determine the row and the position in the row for the open card
			var openCardRow, openCardPosition;
			openCardRow      = Math.ceil((openCardIndex + 1) / rowWidth);
			openCardPosition = (openCardIndex + 1)%rowWidth;
			openCardPosition = openCardPosition == 0 ? rowWidth : openCardPosition;

			// Determine the space on either side of the card
			var spaceLeft, spaceRight;
			spaceLeft  = openCardPosition - 1;
			spaceRight = rowWidth - openCardPosition;

			// Determine which way to fold open
			var openPositionIndex;
			if (spaceLeft > spaceRight) {
				if (spaceLeft >= this.options.openCardWidth - 1) { //check if there is enough space to fit to the left
					openPositionIndex = (openCardPosition - 1) - (this.options.openCardWidth - 1);
				} else {
					openPositionIndex = 0;
				}
			} else if (spaceLeft < spaceRight) {
				if (spaceRight >= this.options.openCardWidth - 1) { //check if there is enough space to fit to the right
					openPositionIndex = openCardPosition - 1;
				} else {
					openPositionIndex = rowWidth - this.options.openCardWidth -1;
				}
			} else {
				openPositionIndex = openCardPosition - 2;
			}

			// Get the raw height of the open card and stretch to fit the grid
			var openCardHeight, openCardRowHeight, openCardWidth;
			openCardWidth      = (this.options.openCardWidth * (this.options.closedOuterWidth + this.options.margin)) - this.options.margin
			openCardHeight     = document.id(this.openCard).retrieve('instance').getOpenHeight(openCardWidth - (this.options.closedOuterWidth - this.options.closedInnerWidth));
			openCardHeightRows = Math.ceil((openCardHeight+this.options.margin) / (this.options.margin + this.options.closedOuterHeight));
			openCardHeight     = openCardHeightRows * (this.options.margin + this.options.closedOuterHeight) - this.options.margin;
			openCardHeight    -= this.options.closedOuterHeight - this.options.closedInnerHeight;

			// Collect zero based locations for top left and bottom right
			var openCardIndexes = {
				topLeftX: openPositionIndex,
				topLeftY: openCardRow - 1,
				bottomRightX: openPositionIndex + this.options.openCardWidth - 1,
				bottomRightY: openCardRow - 2 + openCardHeightRows
			}

			// To determine the number of needed rows, determine how many places the open card would occuppy
			var neededSpaces, neededRows;
			neededSpaces = this.options.openCardWidth * openCardHeightRows + amountCards - 1;
			neededRows   = Math.ceil(neededSpaces / rowWidth);

			if (neededRows <= openCardIndexes.bottomRightY) {
				neededRows = openCardIndexes.bottomRightY + 1;
			}

		} else {
			//Determine the number of needed rows
			var neededRows = Math.ceil(amountCards / rowWidth);
		}

		// Set various dimensions
		var containerWidth = (rowWidth * (this.options.closedOuterWidth + this.options.margin)) - this.options.margin + 10;
		this.container.setStyles({
			'width': containerWidth,
			'height': (neededRows * (this.options.closedOuterHeight + this.options.margin))
		});
		$$('#header', '#submenu').setStyle('width', containerWidth-10);

		// Distribute the cards
		var cardIndex, params, currentCard, done;
		cardIndex = -1;
		done = false;

		for (var row=0; row<neededRows; row++) {
			if (done) break;

			for (var col=0; col<rowWidth; col++) {
				if (openCardIndexes) {
					if (row >= openCardIndexes.topLeftY && row <= openCardIndexes.bottomRightY &&
					    col >= openCardIndexes.topLeftX && col <= openCardIndexes.bottomRightX) {
						continue;
					}
				}

				// Determine top and left offset based on the current row and column
				
				params = {};
				params.top    = (row * (this.options.closedOuterHeight + this.options.margin)) + 5;
				params.left   = (col * (this.options.closedOuterWidth + this.options.margin)) + 5;
				params.width  = this.options.closedInnerWidth;
				params.height = this.options.closedInnerHeight;

				// See if there are cards to position and skip the next one if it is the open card
				if (this.cards[cardIndex+1]) {
					if (this.cards[cardIndex+1].id == this.openCard) {
						if (this.cards[cardIndex+2]) {
							cardIndex += 2;
						} else {
							done = true;
							break;
						}

					} else {
						cardIndex++;
					}

					this.cards[cardIndex].position(params);
				}
			}
		}

		// Finally position the open card (if present)
		if (openCardIndexes) {			
			params.top    = (openCardIndexes.topLeftY * (this.options.closedOuterHeight + this.options.margin)) + 5;
			params.left   = (openCardIndexes.topLeftX * (this.options.closedOuterWidth + this.options.margin)) + 5;
			params.width  = (this.options.openCardWidth * (this.options.closedOuterWidth + this.options.margin)) - this.options.margin - (this.options.closedOuterWidth - this.options.closedInnerWidth);
			params.height = openCardHeight;

			var cardToOpen;
			cardToOpen = document.id(this.openCard).retrieve('instance');
			cardToOpen.position(params);		
		}
	}
});