define(['jquery'], function (jQuery) {
	var $ = jQuery;
	var snapToGrid = false;
	var snapToRatio = true;
	
	function snap(v, gridSize)
	{		
		return gridSize * Math.floor((v / gridSize) + 0.5);
	}	
	
	function snap2grid(handle)
	{
		if (snapToGrid)
		{
			var $target = handle.$target;
			var $container = handle.$container;
			var gx = $container.width() / 100;
			var gy = $container.height() / 100;
			
			var offset = $target.offset();
			$target.offset({ left: snap(offset.left, gx), top: snap(offset.top, gy)});
			$target.width(snap($target.width(), gx));
			$target.height(snap($target.height(), gy));
			//console.log({width: $target.width() / gx, height: $target.height() / gy });
		}
	}
	
	function snap2ratio(handle, newWidth, newHeight)
	{
		if (snapToRatio)
		{
			var ratio = handle.ratio;
			var newRatio = (newWidth / newHeight);
			
			if (ratio > newRatio)
			{
				newHeight = (newWidth * handle.height) / handle.width;
			}
			else
			{
				newWidth = (newHeight * handle.width) / handle.height;
			}			
		}
		return { width: newWidth, height: newHeight };
	}

	function sizeX(handle, e)
	{
		var width = Math.max(e.pageX - handle.pX + handle.width, 0);
		return width;
	}
	
	function sizeY(handle, e)
	{
		var height = Math.max(e.pageY - handle.pY + handle.height, 0);	
		return height;
	}	
	
	function sizeXNeg(handle, e)
	{
		var width = Math.max(handle.width - (e.pageX - handle.pX), 0);		
		return width;
	}
	
	function sizeYNeg(handle, e)
	{
		var height = Math.max(handle.height - (e.pageY - handle.pY), 0);		
		return height;
	}	

	function handleDrag(handle, e)
	{	
		handle.$target.offset({ left: handle.tx, top: handle.ty });	
		snap2grid(handle);
	}	

	function handleResize_SouthEast(handle, e)
	{
		var targetWidth = sizeX(handle, e);
		var targetHeight = sizeY(handle, e);
		
		var snapped = snap2ratio(handle, targetWidth, targetHeight);
		handle.$target.width(snapped.width);
		handle.$target.height(snapped.height);
		snap2grid(handle);
	}	

	function handleResize_South(handle, e)
	{
        var targetHeight = sizeY(handle, e);			
		handle.$target.height(targetHeight);
		snap2grid(handle);
	}
	
	function handleResize_SouthWest(handle, e)
	{	
		var targetWidth = sizeXNeg(handle, e);		
        var targetHeight = sizeY(handle, e);
				
		var snapped = snap2ratio(handle, targetWidth, targetHeight);
		// anchors are top and right
		var right = handle.$target.offset().left+handle.$target.width();
		
		handle.$target.offset({ left: (right-snapped.width) });				
		handle.$target.width(snapped.width);
		handle.$target.height(snapped.height);	
		snap2grid(handle);
	}
	
	function handleResize_West(handle, e)
	{
		var targetWidth = sizeXNeg(handle, e);		
		handle.$target.offset({ left: handle.tx });		
		handle.$target.width(targetWidth);		
		snap2grid(handle);
	}
	
	function handleResize_NorthWest(handle, e)
	{
		var targetWidth = sizeXNeg(handle, e);		
		var targetHeight = sizeYNeg(handle, e);		

		var snapped = snap2ratio(handle, targetWidth, targetHeight);
		// anchors are bottom and right
		var bottom = handle.$target.offset().top+handle.$target.height();
		var right = handle.$target.offset().left+handle.$target.width();
		
		handle.$target.offset({ left: (right-snapped.width), top: (bottom-snapped.height) });				
		handle.$target.width(snapped.width);
		handle.$target.height(snapped.height);
		snap2grid(handle);		
	}
	
	function handleResize_North(handle, e)
	{		
		var targetHeight = sizeYNeg(handle, e);		
		handle.$target.offset({ top: handle.ty });	
		handle.$target.height(targetHeight);		
		snap2grid(handle);
	}
	
	function handleResize_NorthEast(handle, e)
	{		
		var targetWidth = sizeX(handle, e);
		var targetHeight = sizeYNeg(handle, e);
		
		var snapped = snap2ratio(handle, targetWidth, targetHeight);
		// anchors are bottom and left
		var bottom = handle.$target.offset().top+handle.$target.height();
		//var left = handle.$target.offset().left+handle.$target.width();
		
		handle.$target.offset({ top: (bottom-snapped.height) });				
		handle.$target.width(snapped.width);
		handle.$target.height(snapped.height);
		snap2grid(handle);		
	}
	
	function handleResize_East(handle, e)
	{
		var targetWidth = sizeX(handle, e);		
		handle.$target.width(targetWidth);
		snap2grid(handle);
	}		

	// Example: InteractiveBox( $('.box'), [ $e: element, move: handleDrag ] );
	function InteractiveBox($e, handles, callback, $container)
	{
		var self = this;
		self.$target = $e;					
		self.handles = handles;
		self.$container = $container || $(window);
		self.callback = callback;		
		self.mouseUpTimeout = null;		
		self.$document = $( self.$target[0].ownerDocument );
			
		function registerHandle(handle)
		{
			var handle = handle;
			handle.active = false;
			handle.$target = self.$target;
			handle.$container = self.$container;
			
			handle.$e.mousedown(
				function(e) 
				{
					handle.active = true;
					var p = handle.$target.offset();//position();
					handle.x = p.left;
					handle.y = p.top;
					handle.width = handle.$target.width();
					handle.height = handle.$target.height();
					handle.ratio = handle.width / handle.height; 
					handle.pX = e.pageX;
					handle.pY = e.pageY;					
					
					if(handle.start)
					{
						handle.start(handle, e);
					}
					
					e.stopPropagation();
				});	
									
			handle.mouseMove = function(e) 
			{					
				if (handle.active && handle.move)
				{
					snapToGrid = e.ctrlKey;
					snapToRatio = e.shiftKey ? false : true;
										
					handle.tx = handle.x + e.pageX - handle.pX;
					handle.ty = handle.y + e.pageY - handle.pY;
					
					handle.move(handle, e); // drag or resize target (x, y or xy)
				}
				
				e.stopPropagation();
			};
			
			handle.mouseUp = function(e) 
			{
				handle.active = false;
				if(handle.stop)
				{
					handle.stop(handle, e);
				}

				if (self.callback)
				{
					clearTimeout(self.mouseUpTimeout);
					self.mouseUpTimeout = setTimeout(function() {
						self.callback();
					}, 100);						
				}
				
				e.stopPropagation();
			}					
			
			// Let op deze events moeten geunbind worden!
			self.$document.mousemove(handle.mouseMove);
			self.$document.mouseup(handle.mouseUp);			
		}		
		
		for(i=0;i<self.handles.length;i+=1)
		{
			registerHandle(self.handles[i]);
		}
		
		return self;
	}
	InteractiveBox.prototype.unbind = function ()	
	{
		var self = this;
		clearTimeout(self.mouseUpTimeout);
		
		function unregisterHandle(handle)
		{			
			self.$document.unbind('mousemove', handle.mouseMove);
			self.$document.unbind('mouseup', handle.mouseUp);
			
			handle.$e.remove(); // remove element from DOM
		}
		
		for(i=0;i<self.handles.length;i+=1)
		{
			unregisterHandle(self.handles[i]);
		}
		
		self.$container = null;
		self.$target = null;
		self.handles = null;
	};
	
	var module = {};
	module.InteractiveBox = InteractiveBox;

	module.handleResize_East = handleResize_East;
	module.handleResize_SouthEast = handleResize_SouthEast;
	module.handleResize_South = handleResize_South;
	module.handleResize_SouthWest = handleResize_SouthWest;
	module.handleResize_West = handleResize_West;
	module.handleResize_NorthWest = handleResize_NorthWest;
	module.handleResize_North = handleResize_North;
	module.handleResize_NorthEast = handleResize_NorthEast;	
	
	module.handleDrag = handleDrag;
	
	return module;
});