// Dynamic elements
// Hans Dybkjær 2008-05-16
// After idea by Matt Murphy (http://www.matts411.com/webdev/creating_draggable_html_element_panes)
//////////////////////////////////////////////////////////////////
// Manage a set of draggable nodes
// A draggable node must be embedded in (or be itself) a node with className "drag".
// This way a draggable may restrict its activation area to a subnode (which is the one in the queue).
// In: Queue queue: list of nodes to be draggable
// In: function ondrop(obj): callback when obj is dropped
// In: function ondrop(obj): callback when mouse is over obj 
// In: string tag: The classname the draggable is tagged with. This should be the node itself, or an ancestor node.
function Draggable(queue, ondrop, onover, tag) 
{
	var _this = this;  // because javascript spec is in deep shit
	var Queue = queue; // the draggable
	var OnDrop = ondrop;
	var OnOver = onover

	//-------------------------------------------------- Pane
	var currentNode;
	var offsetX = 0;
	var offsetY = 0;
	var currentNodeOpacity;
	
	// Given an activated node, locate the ancestor to drag
	// In: Node node: The activated node
	function LocateDrag(node)
	{
		while (node.tagName != "body" && !(node.className == tag)) // stop on "body" is just a safequard
		{
				node = node.parentNode;
		}
		return node;
	}

	//----------------------------------------------------- Event handlers
	// Setup the activated object
	// In: EventObject e
	this.onsetup = function(ev) 
	{	
		var e = Browser.EventRepair(ev);
		var o = Browser.Target(e);
		o.onmouseover = function(e) { OnOver(LocateDrag(Browser.Target(Browser.EventRepair(e)))); };
		o.onmousedown = _this.onactivate;
		OnOver(LocateDrag(o));
	};
	// Activate dragging
	// In: EventObject e
	this.onactivate = function(ev) 
	{
		var e = Browser.EventRepair(ev);
		currentNode = LocateDrag(Browser.Target(e));
		if(currentNode.tagName != "body") 
		{
			// Make sure it is positioned where it is
			var point = Node.FindPoint(currentNode);
			currentNode.style.left = point.X + "px";
			currentNode.style.top = point.Y + "px";

			// Store and change opacity
			currentNodeOpacity = currentNode.style.opacity;
			Browser.SetOpacity(currentNode, 0.3);
			
			// Put on top
			Queue.Upgrade(currentNode);

			// Initialize the movement
			currentNode.style.float = "none";
			currentNode.style.position = "absolute";

			offsetX = e.clientX - currentNode.offsetLeft;
			offsetY = e.clientY - currentNode.offsetTop;
			Browser.AddEventListener(document, "mousemove", _this.ondrag);
			Browser.AddEventListener(document, "mouseup", _this.ondeactivate);

		}
		return false;
	};

	// Register drag
	// In: EventObject e
	this.ondrag = function(ev) 
	{
		var e = Browser.EventRepair(ev);
		currentNode.style.left = (e.clientX - offsetX) + "px";
		currentNode.style.top = (e.clientY - offsetY) + "px";
		return false;
	};

	// Deactivate dragging
	// In: EventObject e
	this.ondeactivate = function(e) 
	{
		Browser.RemoveEventListener(document, "mousemove", _this.ondrag);
		Browser.RemoveEventListener(document, "mouseup", _this.ondeactivate);
		Browser.SetOpacity(currentNode, currentNodeOpacity);
		OnDrop(currentNode);
	};

	Queue.Apply(function(o, i, len) // setup as draggable panes
		{
				o.onmouseover = _this.onsetup;	
		});
	
}
