function hookEvent(element, eventName, callback)
{
	
	if(typeof(element) == "string")
		element = document.getElementById(element);
		
	if(element == null)
		return;
		
	if(element.addEventListener)
	{
		element.addEventListener(eventName, callback, false);
	}
	
	else if(element.attachEvent)
		element.attachEvent("on" + eventName, callback);
		
}

function unhookEvent(element, eventName, callback)
{
	
	if(typeof(element) == "string")
		element = document.getElementById(element);
	
	if(element == null)
		return;
	
	if(element.removeEventListener)
		element.removeEventListener(eventName, callback, false);
		
	else if(element.detachEvent)
		element.detachEvent("on" + eventName, callback);
	
}

function cancelEvent(e)
{
	
	e = e ? e : window.event;
	
	if(e.stopPropagation)
	e.stopPropagation();
	
	if(e.preventDefault)
	e.preventDefault();
	
	e.cancelBubble 	= true;
	e.cancel 		= true;
	e.returnValue 	= false;
	
	return false;
	
}

function Position(x, y)
{
	
	this.X 	= x;
	this.Y 	= y;
	
	this.Add = function(val)
	{
		var newPos = new Position(this.X, this.Y);
		
		if(val != null)
		{
			if(!isNaN(val.X))
				newPos.X += val.X;
			if(!isNaN(val.Y))
				newPos.Y += val.Y
		}
		
		return newPos;
	}
	
	this.Subtract = function(val)
	{
		var newPos = new Position(this.X, this.Y);
		if(val != null)
		{
			if(!isNaN(val.X))
				newPos.X -= val.X;
			if(!isNaN(val.Y))
				newPos.Y -= val.Y
		}
		return newPos;
	}
	
	this.Min = function(val)
	{
		var newPos = new Position(this.X, this.Y)
		if(val == null)
			return newPos;
		
		if(!isNaN(val.X) && this.X> val.X)
			newPos.X = val.X;
		if(!isNaN(val.Y) && this.Y> val.Y)
			newPos.Y = val.Y;
		
		return newPos;  
	}
	
	this.Max = function(val)
	{
		var newPos = new Position(this.X, this.Y)
		
		if(val == null)
			return newPos;
		
		if(!isNaN(val.X) && this.X <val.X)
			newPos.X = val.X;
		if(!isNaN(val.Y) && this.Y <val.Y)
			newPos.Y = val.Y;
		
		return newPos;  
	}  
	
	this.Bound = function(lower, upper)
	{
		var newPos = this.Max(lower);
		return newPos.Min(upper);
	}
	
	this.Check = function()
	{
		var newPos = new Position(this.X, this.Y);
		
		if(isNaN(newPos.X))
			newPos.X = 0;
		if(isNaN(newPos.Y))
			newPos.Y = 0;
			
		return newPos;
	}
	
	this.Apply = function(element)
	{
		if(typeof(element) == "string")
			element = document.getElementById(element);
			
		if(element == null)
			return;
			
		if(!isNaN(this.X))
			element.style.left = this.X + 'px';
			
		if(!isNaN(this.Y))
			element.style.top = this.Y + 'px';  
	}
	
}

function absoluteCursorPostion(eventObj)
{
  eventObj = eventObj ? eventObj : window.event;
  
  if(isNaN(window.scrollX))
    return new Position(eventObj.clientX + 
              document.documentElement.scrollLeft + 
              document.body.scrollLeft, 
              eventObj.clientY + 
              document.documentElement.scrollTop + 
              document.body.scrollTop);
  else
    return new Position(eventObj.clientX + window.scrollX, 
              eventObj.clientY + window.scrollY);
}

function dragObject(element, attachElement, 
    lowerBound, upperBound, startCallback, 
    moveCallback, endCallback, attachLater)
{
	
	
	if(typeof(element) == "string") 
		element = document.getElementById(element);
	
	if(element == null) return;
	
	if(lowerBound != null && upperBound != null)
	{
		var temp 	= lowerBound.Min(upperBound);
		upperBound 	= lowerBound.Max(upperBound);
		lowerBound 	= temp;
	}
	
	var cursorStartPos 		= null;
	var elementStartPos 	= null;
	var dragging 			= false;
	var listening 			= false;
	var disposed 			= false;
	
	function dragStart(eventObj)
	{ 
		if(dragging || !listening || disposed)
			return;
			
		dragging = true;
		
		if(startCallback != null)
			startCallback(eventObj, element);
		
		cursorStartPos = absoluteCursorPostion(eventObj);
		
		elementStartPos = new Position(	
									   	parseInt(element.style.left),
										parseInt(element.style.top)
										);
		
		elementStartPos = elementStartPos.Check();
		
		hookEvent(document, "mousemove", dragGo);
		hookEvent(document, "mouseup", dragStopHook);
		
		return cancelEvent(eventObj);
		
	}
	
	function dragGo(eventObj)
	{
		
		if(!dragging || disposed) 
			return;
		
		var newPos = absoluteCursorPostion(eventObj);
		
		newPos = newPos.Add(elementStartPos).Subtract(cursorStartPos);
		newPos = newPos.Bound(lowerBound, upperBound)
		newPos.Apply(element);
		
		if(moveCallback != null)
			moveCallback(newPos, element);
			
		return cancelEvent(eventObj); 
		
	}
	
	function dragStopHook(eventObj)
	{
		dragStop();
		return cancelEvent(eventObj);
	}
	
	function dragStop()
	{
		if(!dragging || disposed) 
			return;
			
		unhookEvent(document, "mousemove", dragGo);
		unhookEvent(document, "mouseup", dragStopHook);
		cursorStartPos 	= null;
		elementStartPos = null;
		
		if(endCallback != null)
			endCallback(element);
			
		dragging = false;
	}
	
	this.Dispose = function()
	{
		if(disposed)
			return;
			
		this.StopListening(true);
		
		element			= null;
		attachElement 	= null
		lowerBound 		= null;
		upperBound 		= null;
		startCallback 	= null;
		moveCallback 	= null
		endCallback 	= null;
		disposed 		= true;
		
	}
  
	this.StartListening = function()
	{
		
		if(listening || disposed)
			return;
			
		listening = true;
		hookEvent(attachElement, "mousedown", dragStart);
		
	}
  
	this.StopListening = function(stopCurrentDragging)
	{
		
		if(!listening || disposed)
			return;
		
		unhookEvent(attachElement, "mousedown", dragStart);
		listening = false;
		
		if(stopCurrentDragging && dragging)
			dragStop();
			
	}
  
	this.IsDragging 		= function() { return dragging; }
	this.IsListening 		= function() { return listening; }
	this.IsDisposed 		= function() { return disposed; }
  
	if(typeof(attachElement) == "string")
		attachElement = document.getElementById(attachElement);
		
	if(attachElement == null)
		attachElement = element;
    
	if(!attachLater)
		this.StartListening();
	
}










