// 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.

// Droppable class
function Droppable(o)
{
	var obj = o;
	var draggers = [];
	var draggerCount = 0;

	// Begin "getters"
	this.id = function()
	{
		return obj.id;
	}

	this.getObj = function()
	{
		return obj;
	}

	this.getDraggers = function()
	{
		return draggers;
	}
	
	this.getDraggerCount = function()
	{
		return draggerCount;
	}
	// end "getters"
	
	// add a draggable object to this drop zone
	this.AddDragger = function(dragger)
	{
		if (draggerCount == 0)
		{
			draggers = [ dragger ];
		}
		else
		{
			draggers = draggers.concat(dragger);
		}
		draggerCount++;
	}
	
	// get the position that an object at (x, y) will be dropped into
	this.getPosition = function(x, y)
	{
		var nextDragger = 0;
		var dragger;
		var i;
		for (i = 0; i < draggerCount; i++)
		{
			dragger = draggers[i];
			var offset = findPos(dragger);
			if (y > offset[1] + dragger.offsetHeight / 2)
			{
				nextDragger = i + 1;
			}
		}
		return nextDragger;
	}

	// returns true if (x, y) is within the drop zone
	this.IsHover = function(x, y)
	{
		var offset = findPos(obj);
		if (y > offset[1] && y < offset[1] + obj.offsetHeight)
		{
			if (x > offset[0] && x < offset[0] + obj.offsetWidth)
			{
				return true;
			}
		}
		return false;
	}
	
	// removes a draggable object from this drop zone
	// does not remove the DOM object
	this.RemoveDragger = function(dragger)
	{
		var i;
		for (i = 0; i < draggerCount; i++)
		{
			if (draggers[i] == dragger)
			{
				if (draggerCount > 1)
				{
					draggers.splice(i, 1);
					draggerCount--;
				}
				else
				{
					draggers = [];
					draggerCount = 0;
				}
				return;
			}
		}
	}
	
	// inserts a draggable object at (x, y)
	// will update the DOM by moving the draggable object into position
	this.InsertDragger = function(x, y, dragger)
	{
		var i = this.getPosition(x, y);
		if (i == draggerCount)
		{
			obj.appendChild(dragger);
		}
		else
		{
			obj.insertBefore(dragger, draggers[i]);
		}
		draggers.splice(i, 0, dragger);
		draggerCount++;
	}
	
	// moves a draggable object to a different position within this drop zone
	// will update the DOM
	this.MoveDragger = function(x, y, dragger)
	{
		var destPos = this.getPosition(x, y);
		var srcPos;
		var j;
		for (j = 0; j < draggerCount; j++)
		{
			if (draggers[j] == dragger)
			{
				srcPos = j;
			}
		}
		if (destPos == draggerCount)
		{
			obj.appendChild(dragger);
		}
		else
		{
			obj.insertBefore(dragger, draggers[destPos]);
		}
		if (destPos > srcPos)
		{
			draggers.splice(destPos, 0, dragger);
			draggers.splice(srcPos, 1);
		}
		else
		{
			draggers.splice(srcPos, 1);
			draggers.splice(destPos, 0, dragger);
		}
	}
	
	// returns true if the selected draggable object is actually draggable
	// used with inherited classes to restrict dragging
	this.IsValidDrag = function(drag)
	{
		return true;
	}
	
	// returns true if the object drag can be dropped at position (x, y)
	this.IsValidDrop = function(x, y, drag)
	{
		return this.IsHover(x, y);
	}
	
	// returns the DOM object that will be adjacent to an object dropped at
	// (x, y).  eg. if (x, y) would drop between the 1st and 2nd draggables,
	// the DOM object of the second draggable is returned
	this.getNext = function(x, y)
	{
		var i = this.getPosition(x, y);
		if (i == draggerCount)
		{
			return null;
		}
		else
		{
			return draggers[i];
		}
	}

}

