// Drag and drop by Peter Heil 2007 Eljakim IT BV
var droppables = new Droppables();

//Creates a new Draggable:
function Draggable(elementID,parentLevel)
{
	this.id = elementID;
	var element = document.getElementById(elementID);
	var dragObj = this;
	this.left=0;
	this.parentLevel = parentLevel;
	this.top=0;
	this.realLeft = 0;
	this.realTop = 0;
	this.z = 1;
	this.topOffset = 0;
	this.leftOffset = 0;
	this.revert = true;
	this.dragging = false;
	this.onDragBeginEvent 	= function(element,dragObject){};
	this.onDragEndEvent 	= function(element,dragObject){};
	this.onNoHoverEvent 	= function(element,dragObject){};
	this.onHoverEvent 		= function(element,dragObject,dropObject){};
	var node = document.getElementById(elementID);	

	element.onmousedown = function(e) {
										document.onmousedown = function(e){stopEvent(e)};
										dragObj.startDrag(e);
									  };
}
//Destroys the draggable:
Draggable.prototype.destroy = function()
{
	var element = document.getElementById(this.id);
	if(!element)return;
	if(this.parentLevel)
	{
		for(var i=0;i<this.parentLevel;i++)
		{
			element = element.parentNode;
		}
	}
	element.onmousedown = null;
	element.onmouseup = null;
	document.onmousemove = null;
	document.onmouseup   = null;
	this.element = null;
}
//Moves the draggable to his original position:
Draggable.prototype.doRevert = function()
{
	var element = document.getElementById(this.id);
	if(!element)return;
	if(this.parentLevel)
	{
		for(var i=0;i<this.parentLevel;i++)
		{
			element = element.parentNode;
		}
	}
	element.style.left = this.left + "px";
	element.style.top  = this.top + "px";
	element.style.zIndex = this.z;
	
}
//Moves the draggable to the mouse-coordinates:
Draggable.prototype.move = function(event)
{
	var element = document.getElementById(this.id);
	if(!element)return;
	if(this.parentLevel)
	{
		for(var i=0;i<this.parentLevel;i++)
		{
			element = element.parentNode;
		}
	}
	var mouse = getMouseXY(event);
	element.style.position = "relative";
	element.style.left = this.leftOffset+mouse.x + "px";
	element.style.top  = this.topOffset+mouse.y + "px";
	var hover = droppables.checkHover(element);
	if(hover)
	{this.onHoverEvent(element,this,hover);}
	else
	{this.onNoHoverEvent(element,this);}
	deselect();
	stopEvent(event);
}
//Initiate the drag:
Draggable.prototype.startDrag = function(e)
{
	if(this.dragging)return;
	var dragObj = this;
	var element = document.getElementById(this.id);
	if(!element)return;
	if(this.parentLevel)
	{
		for(var i=0;i<this.parentLevel;i++)
		{
			element = element.parentNode;
		}
	}
	var mouse = getMouseXY(e);
	
	this.realLeft = getRealLeftPos(element);
	this.realTop  = getRealTopPos(element);
	
	this.top = getStyleTopPos(element);
	this.left= getStyleLeftPos(element);
	
	this.topOffset = this.top - mouse.y;
	this.leftOffset = this.left - mouse.x;
	//alert(this.top + "~" +this.left + " " + mouse.x +"~"+ mouse.y + " " +this.leftOffset + "~" + this.topOffset)
	
	if(element.style.zIndex)
		this.z = element.style.zIndex;
		
	element.style.zIndex = 1000;
	this.dragging = true;
	
	document.onmousemove = function(event) {dragObj.move(event)};
	document.onmouseup   = function(event) {dragObj.endDrag(event)};
	deselect();
	this.onDragBeginEvent(element,this);
	
}
//Ends the drag:
Draggable.prototype.endDrag = function(e)
{
	var element = document.getElementById(this.id);
	if(!element)return;
	if(this.parentLevel)
	{
		for(var i=0;i<this.parentLevel;i++)
		{
			element = element.parentNode;
		}
	}
	var left = getRealLeftPos(element);
	var top  = getRealTopPos(element);
	var mouse = getMouseXY(e);
	if(top!=this.realTop || left!=this.realLeft)
		droppables.drop(element);
		
	document.onmousemove = "";
	document.onmouseup   = "";
	document.onmousedown = "";
	if(this.revert)this.doRevert();
	this.dragging = false;
	this.onDragEndEvent(element,this);
}

//Creates a new droppable:
function Droppable(elementID)
{
	this.id = elementID;
	this.onHoverEvent = function(draggable,droppable,dropObject,percentage){};
	this.onDropEvent = function(draggable,droppable,dropObject){};
	this.acceptedClasses = new Array();
	this.hoverPercentage =0;
	
}

//Droppables datastructure:
function Droppables()
{
	this.droplist = [];
}
Droppables.prototype.doFunction = function(func)
{
	for(var i = 0; i<this.droplist.length;i++)
	{
		var node = document.getElementById(this.droplist[i].id);
		func(node,this.droplist[i]);
	}
}
//Checks collisions between an element and the draggables:
Droppables.prototype.checkHover = function(element)
{
	var elX = getRealLeftPos(element);
	var elY = getRealTopPos(element);
	var elWidth = getElementWidth(element);
	var elHeight = getElementHeight(element);
	var elBottom = elY + elHeight;
	var elRight = elX + elWidth;
	
	for(var i = 0; i<this.droplist.length;i++)
	{
		var drop = document.getElementById(this.droplist[i].id);
		if(drop==null)
		{
			//if droppable doesn't exists remove from droppables
			this.droplist.splice(i,1);
			i--;
			continue;
		}
		if(this.droplist[i].acceptedClasses.length>0)
		{
			var bool = false;
			var dragClass = element.className.split(" ");
			for(var j=0;j<this.droplist[i].acceptedClasses.length;j++)
			{
				var curClass = this.droplist[i].acceptedClasses[j];
				for(var k = 0;k<dragClass.length;k++)
				{
					if(dragClass[k]==curClass)
					{
						bool = true;
						break;
					}
				}
				if(bool)break;
			}
			if(!bool) continue;
		}
		if(drop.id==element.id) continue;
		var dropX = getRealLeftPos(drop);
		var dropY = getRealTopPos(drop);
		var dropWidth = getElementWidth(drop);
		var dropHeight = getElementHeight(drop);
		var dropRight = dropX + dropWidth;
		var dropBottom = dropY + dropHeight;

		//fast check for collisions:
		if (elBottom < dropY) continue;
   		if (elY > dropBottom) continue;
   		if (elRight < dropX) continue;
     	if (elX > dropRight) continue;
		
		var percentage = 100;
		
		if(this.droplist[i].hoverPercentage>0)
		{
			//calculate percentage:
			var colHeight   = Math.min(elBottom,dropBottom)-Math.max(elY,dropY);
			var colWidth    = Math.min(elRight,dropRight)-Math.max(elX,dropX);
			var colSurface  = colHeight*colWidth;
			var dropSurface = (dropBottom-dropY)*(dropRight-dropX);
				percentage  = Math.round(colSurface/dropSurface*100);
			//advanced collision check:
			if(percentage<this.droplist[i].hoverPercentage)continue;
		}
		
		this.droplist[i].onHoverEvent(element,drop,this.droplist[i],percentage);
		return this.droplist[i];

	}
	return null;
}
//adds a droppable:
Droppables.prototype.add = function(droppable)
{
	this.droplist[this.droplist.length] = droppable;
}
//removes a droppable:
Droppables.prototype.remove = function(elementID)
{
	for(var i = 0; i<this.droplist.length;i++)
	{
		if(this.droplist[i].id==elementID)
		{
			this.droplist.splice(i,1);
			return true;
		}
	}
	return false;
}
//Removes all droppables:
Droppables.prototype.clear = function()
{
	this.droplist = [];
}
//drops an element
Droppables.prototype.drop = function(element)
{
	var drop = this.checkHover(element);
	if(drop!=null)
	{
		dropElement = document.getElementById(drop.id);
		drop.onDropEvent(element,dropElement,this);
		deselect();
		return true;
	}
	else
		return false;
}


