// Tyler Spaulding, 2007
// http://www.arguingwithmyself.com
// The contents of this file are public domain.  Do with them what you want.  I
// would prefer if you left this comment block intact, but I'm not going to
// stop you.


// DragDrop object (a hashtable, really)
var DragDrop = function()
{
	var draggers = [];
	var droppers = [];
	var dragger;
	var hoverObj = document.createElement("div");
	hoverObj.className = "hover";

	return {
		// created Droppables out of all elements with the class name "droppable"
		// and makes all elements with the class name "draggable" draggable
		Init : function() {
			var droppers = getElementsByClassName("*", "droppable");
			for (var dropper in droppers)
			{
				var dropObj = DragDrop.AddDroppable(droppers[dropper]);
				for (var i = 0; i < droppers[dropper].childNodes.length; i++)
				{
					var draggerObj = droppers[dropper].childNodes[i];
					if (draggerObj.className == "draggable")
					{
						DragDrop.AddDraggable(draggerObj, dropObj);
					}
				}
			}
			dragger = document.getElementById("dragger");
		},

		// resets draggers and droppers
		Clear : function() {
			draggers = [];
			droppers = [];
		},

		// returns a new droppable object
		// this method should be overridden when using an inherited Droppable class
		NewDroppable : function(obj) {
			return new Droppable(obj);
		},
		
		// creates a new drop zone
		AddDroppable : function(obj) {
			disableSelection(obj);
			var newDropper = DragDrop.NewDroppable(obj);
			droppers = droppers.concat(newDropper);
			Log("Add droppable " + newDropper.id());
			return newDropper;
		},

		// creates a new draggable object
		AddDraggable : function(obj, drop) {
			if (!obj) return;
			disableSelection(obj);
			obj.className = "draggable";
			obj.onmousedown = function(e){DragDrop.BeginDrag(e, obj, drop);};
			drop.AddDragger(obj);
			draggers = draggers.concat(obj);
			Log("Add draggable " + obj.id + " to droppable " + drop.id());
		},
		
		BeginDrag : function(e, obj, drop) {
			if (!e) e = window.event;
			var body = document.getElementById("body");
			if (!body) return;
			if (drop.IsValidDrag(obj))
			{
				Log("Begin dragging " + obj.id + " from " + drop.id() + " at (" + e.clientX + ", " + e.clientY + ")");
				var offset = findPos(obj);
				var x = parseInt(offset[0]) - parseInt(e.clientX);
				var y = parseInt(offset[1]) - parseInt(e.clientY);
				dragger.style.left = offset[0] + "px";
				dragger.style.top = offset[1] + "px";
				dragger.style.width = obj.offsetWidth + "px";
				dragger.style.height = obj.offsetHeight + "px";
				dragger.className = "";
				obj.className = "draggable dragging";
				dragger.onmouseup = function(e){DragDrop.EndDrag(e, obj, drop);};
				body.onmousemove = function(e2){DragDrop.Drag(e2, obj, x, y);};
			}
		},

		// returns the index of the drop zone at (x, y)
		// or -2 if no drop zone is found
		GetDropZone : function(x, y, obj) {
			for (var i = 0; i < droppers.length; i++)
			{
				if (droppers[i].IsValidDrop(x, y, obj))
				{
					return i;
				}
			}
			return -2;
		},

		// inserts a 'hover' marker at (x, y) to show where the dragged item will
		// be dropped
		Hover : function(x, y, obj) {
			var dropper = DragDrop.GetDropZone(x, y, obj);
			if (dropper > -1)
			{
				var dropperObj = droppers[dropper].getObj();
				var dropperNext = droppers[dropper].getNext(x, y);
				if (!!dropperNext)
				{
					dropperObj.insertBefore(hoverObj, dropperNext);
				}
				else
				{
					dropperObj.appendChild(hoverObj);
				}
			}
			else
			{
				if (!!hoverObj.parentNode)
				{
					hoverObj.parentNode.removeChild(hoverObj);
				}
			}
		},

		// removes the hover marker
		UnHover : function() {
			if (!!hoverObj.parentNode)
			{
				hoverObj.parentNode.removeChild(hoverObj);
			}
		},
		
		Drag : function(e, obj, x, y) {
			if (!e) e = window.event;
			if (!e) return;
			if (!obj) return;
			dragger.style.left = (e.clientX + x) + "px";
			dragger.style.top = (e.clientY + y) + "px";
			DragDrop.Hover(e.clientX, e.clientY, obj);
		},

		EndDrag : function(e, obj, source) {
			if (!e) e = window.event;
			var body = document.getElementById("body");
			if (!body) return;
			Log("End dragging " + obj.id + " at (" + e.clientX + ", " + e.clientY + ")");
			body.onmousemove = null;
			obj.className = "draggable";
			dragger.className = "inactive";

			var dropper = DragDrop.GetDropZone(e.clientX, e.clientY, obj);
			if (dropper > -1)
			{
				var target = droppers[dropper];
				if (source == target)
				{
					Log("Drop onto " + target.id());
					source.MoveDragger(e.clientX, e.clientY, obj);
				}
				else
				{
					Log("Drop onto " + target.id());
					target.InsertDragger(e.clientX, e.clientY, obj);
					source.RemoveDragger(obj);
					obj.onmousedown = function(e){DragDrop.BeginDrag(e, obj, target);};
				}
			}
			DragDrop.UnHover();
		}

	};
}();

window.onload = DragDrop.Init;

