LayoutManager = function(wrapper, settings)
{
	Ali.log("instantiating new LayoutManager");
	this.wrapper = wrapper;
	this.boxes = [];
	
	this.wrapper.empty();
	this.enabled = true;
	this.page = -1;
	this._settings = settings;
	this.totalHeight = 0;
	this.fadeTimeoutIdentifier = null;
};
LayoutManager.prototype.initBoxes = function(boxes)
{
	for(var i = 0; i < boxes.length; i++)
	{
		var box = boxes[i];
		box.page = this.page;
		var e = box.element;
		if(this._settings.boxClass != undefined)
			e.addClass(this._settings.boxClass);
		//e.css("borderWidth", this._settings.borderWidth);
		//box.width+= 2 * this._settings.borderWidth;
		//box.height+= 2 * this._settings.borderWidth;
		//box.updateElementDimensions();
	}
};
LayoutManager.prototype.addBoxes = function(boxes, queuedFunction)
{
	this.page++;
	Ali.log("Adding boxes");
	this.initBoxes(boxes);
	for(var i = 0; i < boxes.length; i++)
		this.boxes.push(boxes[i]);
	this._addBoxesToView(boxes);	
	Ali.log("New boxes appended");
	this._rearrange();
	this._draw(this._settings.resizeDuration, this._settings.resizeEasing);
	this._performWaterfallEffect(false, queuedFunction);
};
LayoutManager.prototype.fadeIn = function(queuedFunction)
{
	Ali.log("Fading in " + this.boxes.length + " boxes");
	if(this.boxes.length == 0)
		return;
	
	this._rearrange();
	this.wrapper.empty();
	this._addBoxesToView(this.boxes);
	this._performWaterfallEffect(true, queuedFunction);
	Ali.log("Fade completed");
	
};
LayoutManager.prototype._initClickHandler = function(box)
{
	var finalThis = this;
	if(this._settings.clickable)
	{
		if(Ali.isTouch() && this._settings.clickHandler != undefined && this._settings.hoverHandler != undefined)
		{
			$(box.element, box.titleElement).unbind("click").click(function()
			{
				finalThis._settings.hoverHandler.inHandler(box);
				window.setTimeout(function()
				{
					finalThis._settings.clickHandler(box);
				}, 1000);
			});
		}
		else
		{
			if(this._settings.clickHandler != undefined)
			{
				$(box.element, box.titleElement).unbind("click").click(function()
				{
					finalThis._settings.clickHandler(box);
				});
			}
			if(this._settings.hoverHandler != undefined)
			{
				box.element.unbind("mouseenter").mouseenter(function()
				{
					finalThis._settings.hoverHandler.inHandler(box);
				});
				box.element.unbind("mouseleave").mouseleave(function()
				{
					finalThis._settings.hoverHandler.outHandler(box);
				});
			}
		}
	}
};
LayoutManager.prototype.showInstantly = function()
{
	this._draw(0, "linear");
};
LayoutManager.prototype._addBoxesToView = function(boxes)
{
	Ali.log("Adding " + boxes.length + " boxes to view");
	for(var i = 0; i < boxes.length; i++)
	{
		boxes[i].element.css("opacity", 0);
		this._initClickHandler(boxes[i]);
		this.wrapper.append(boxes[i].element);
	}
};
LayoutManager.prototype._performWaterfallEffect = function(flagFast, queuedFunction)
{
	var boxesToFade = [];
	var qf = function()
	{
		if(queuedFunction != undefined)
			queuedFunction();
	};
	for(var i = 0; i < this.boxes.length; i++)
	{
		var element = this.boxes[i].element;
		var visible = Ali.isElementInViewport(element);
		if(visible && element.css("opacity") == 0 && !this.boxes[i].fading)
		{
			this.boxes[i].fading = true;
			boxesToFade.push(this.boxes[i]);
		}
	};
	if(boxesToFade.length > 0)
	{
		Ali.log("Fading " + boxesToFade.length + " boxes");
			s = flagFast ? this._settings.fadeInFast : this._settings.fadeIn;
		var duration = Ali.layoutReadyd ? s.duration : 0;
		this._performFade(boxesToFade, 1, duration, s.easing, s.stepping, qf);
	}
	else 
		qf();
};
LayoutManager.prototype.fadeOut = function(queuedFunction, overrideViewport)
{
	if(this.boxes.length == 0)
	{
		if(queuedFunction != undefined)
			queuedFunction();
		return;
	}
	for(var i = 0; i < this.boxes.length; i++)
	{
		this.boxes[i].element.css("opacity", 1);
		if(!this.boxes[i].isTextBox)
			this.boxes[i].titleElement.css("opacity", 0);
	}
		
	//var fs = this._settings.fadeOutStepping;
	window.clearTimeout(this.fadeTimeoutIdentifier);
	var s = this._settings.fadeOut;
	this._performFade(this._getOrderedBoxes().reverse(), 0, s.duration, s.easing, s.stepping, queuedFunction, overrideViewport);
};
LayoutManager.prototype._performFade = function(boxesCopy, targetOpacity, fadeDuration, fadeEasing, stepping, queuedFunction, overrideViewport)
{
	//Ali.log("Fading, " + boxesCopy.length + " boxes to go");
	var fThis = this;
	var box = boxesCopy.shift();
	box.fading = false;
	var element = box.element;
	var inViewport = Ali.isElementInViewport(element) || overrideViewport;
	
	var fadeFunction = function(e, qf)
	{
		e.stop(true, true).animate({opacity: targetOpacity}, fadeDuration, fadeEasing, function()
		{
			if(qf != undefined)
				qf();
		});
	};
	
	if(boxesCopy.length > 0)
	{
		this.fadeTimeoutIdentifier = window.setTimeout(function()
		{
			if(inViewport)
				fadeFunction(element);
			fThis._performFade(boxesCopy, targetOpacity, fadeDuration, fadeEasing, stepping, queuedFunction, overrideViewport);
		}, stepping);
	}
	else if(inViewport)
	{
		window.setTimeout(function()
		{
			fadeFunction(element, queuedFunction);
		}, stepping);
	}
	else if(queuedFunction != undefined)
		queuedFunction();
};
LayoutManager.prototype._getOrderedBoxes = function()
{
	var topDownOrderedBoxes = new Array();
	for(var i = 0; i < this.boxes.length; i++)
		topDownOrderedBoxes.push(this.boxes[i]);
	
	topDownOrderedBoxes.sort( function(a, b)
	{
		return ((a.PositionY < b.PositionY) ? -1 : ((a.PositionY > b.PositionY) ? 1 : 0));
	});
	return topDownOrderedBoxes;
};

LayoutManager.prototype.onResize = function()
{
	this._rearrange();
	this._draw(this._settings.resizeDuration, this._settings.resizeEasing);
	this._performWaterfallEffect(false);
};
LayoutManager.prototype.onScroll = function()
{
	this._performWaterfallEffect(false);
};
LayoutManager.prototype._rearrange = function()
{
	Ali.log("Rearranging all boxes");
	var al = new AutoLayout(this.boxes, this._settings.gridTileSize);
	al.arrange();
	this.totalHeight = al.totalHeight;
	Ali.currentLayoutHeight = al.totalHeight;
	Ali.currentLayoutWidth = al.totalWidth;
	Ali.centerLayout();
	Ali.log("done");
	//this.totalHeight = AutoLayout.rearrange(this.boxes, , this._settings.offsetTop);
};

LayoutManager.prototype._draw = function(duration, easing)
{
	Ali.log("Drawing boxes (" + duration + "ms)");
	for(var i = 0; i < this.boxes.length; i++)
	{
		var b = this.boxes[i];
		var o = b.element.offset();
		if(Math.abs(o.left - b.x) > 5 || Math.abs(o.top - this._settings.offsetTop - b.y) > 0)
			b.element.animate(
			{
				left: b.x,
				top: this._settings.offsetTop + b.y
			}, duration, easing);
	}
};
