// Drag.js
// Roger Garrett
// 12/9/2009
//
// This file contains a JavaScript "class" for dragging and dropping the objects within a Math equation.
//
// The inspiration for this comes from http://www.webreference.com/programming/javascript/mk/column2/
// and from the book JavaScript The Definitive Guide, by David Flanagan

// NOTES:
//
// All of the objects within the dragable area should probably be position="absolute", especially
// when I get to the equation manipulation version, because as soon as a dragable item is selected
// and start to drag (via the onMouseDown and onMouseMove), the remaining, non-absolute ites get
// re-flowed. And it looks just weird.
//

// CONSTRUCTOR for the ContainerConstrainedDrag class
//
function ContainerConstrainedDrag(container)
{
	// This is the constructor for the ContainerConstrainedDrag class. Calling this causes the construction of a ContainerConstrainedDrag obejct.
	//
	// A Constrained Drag is one which restricts the dragging of objects to within a specified container. Only objects
	// within the container may be slected for dragging and the objects may only be dropped or moved to new positions within
	// the container. Attempting to move an object outside of the container results in the object snapping back to
	// its original position (where it was dragged from).
	//
	// Note that creating an instance of a ContainerConstrainedDrag item, with its explicit association with an HTML container,
	// does NOT cause that container's objects to become dragable. You must also call the setActive method for
	// the ContainerConstrainedDrag instance AND set some of the objects inside of that container as being draggable,
	// via the makeDraggable method.
	//
	// Parameters:
	//
	//	container : This specifies the Document object within which our draggable items reside.
	//		For example, we may have a <div> item that contains a bunch of pictures and
	//		we are allowed to move the pictures within the area of the defined <div> section, but not
	//		outside that area.
	
	if (!container)
	{
	    alert("ContainerConstrainedDrag constructor called with no container specified");
	    return;
	}

	// MEMBER PROPERTIES

	// Define the properties (member variables) of the Drag class.

	//		CONTAINER
	//
	// Declare a container variable and have it hold our container for the drag.
	this.container = container;

	//		MOUSE OFFSET
	//
	// Declare a mouseOffset, which indicates the offset of the being-dragged object relative to the
	// upper left-hand corner of the document. mouseOffset will be null whenever an object is NOT being dragged.
	this.mouseOffset = null;

//	//		DRAGABLE OBJECTS
//	//
//	// Declare an array of dragTargets, which is a list of objects that are draggable.
//	this.dragableObjects = [];

//	//		DROP TARGET OBJECTS
//	//
//	// Declare an array of dropTargets, which is a list of objects on which it is valid to drop the
//	// currently being-dragged object.
//	this.dropTargetObjects = [];

	//		IS ACTIVE
	//
	// Declare an isActive member, which indicates whether (true) or not (false) the container is active
	// for dragging. Dragging of draggable items within the container will only occur if this isActive member
	// is true. The user may use the setActive and setInactive methods to effectively turn on and off
	// the ability of the draggable items to be dragged.
	this.isActive = false;

	//		IS MOUSE WITHIN CONTAINER
	// Declare an isMouseWithinContainer member, which indicates whether (true) or not (false) the
	// mouse is currently within the area of the container.
	this.isMouseWithinContainer = false;

//    //		DRAG OBJECT
//    //
//    // Declare a dragObject, which lets us know what object is being dragged from within the
//    // mouseMove and mouseUp methods. dragObject will be null whenever an object is NOT being dragged.
//    this.dragObject = null;
//
	// ON MOUSE MOVE PRIOR
	//
	// Declare a containerOnMouseMovePrior variable which will hold the prior (previous to activating the
	// ContainerConstrainedDrag container's area) onmousemove object for the container.
	// When the container is activated we set the container's onmousemove method to
	// our own version of onmousemove so that we can intercept the mouse move events and do our own processing.
	// When the conainer is deactivated we set the container's onmousemove method back
	// to its previous value. 
	this.containerOnMouseMovePrior = null;

	// ON MOUSE UP PRIOR
	//
	// Declare a containerOnMouseUpPrior variable which will hold the prior (previous to activating the
	// ContainerConstrainedDrag container's area) onmouseup object for the container.
	// When the container is activated we set the container's onmouseup method to
	// our own version of onmouseup so that we can intercept the mouse up events and do our own processing.
	// When the conainer is deactivated we set the container's onmouseup method back
	// to its previous value. 
	this.containerOnMouseUpPrior = null;

//	// ON MOUSE OUT (LEAVE) PRIOR
//	//
//	// Declare a containerOnMouseOutPrior variable which will hold the prior (previous to activating the
//	// ContainerConstrainedDrag container's area) onmouseout object for the container.
//	// When the container is activated we set the container's onmouseout method to
//	// our own version of onmouseout so that we can intercept the mouse up events and do our own processing.
//	// When the conainer is deactivated we set the container's onmouseout method back
//	// to its previous value. 
//	this.containerOnMouseOutPrior = null;

    ContainerConstrainedDrag.GetContainerLimits(container); // NOTE Will also have to call this whenever the container itself moves, so need another event hadler for that.
	
}

// NOTE I wish there were a way to make dragObject, etc. a member of the ContainerConstrainedDrag
// and somehow be able to access it via the ContainerConstrainedDrag object FROM WITHIN
// the event handlers. I tried setting a property of the event handlers to contain a refeence
// to ContainerConstrainedDrag but the property ends up being undefined when accessed from
// within the event handler.

//		DRAGABLE OBJECTS
//
// Declare an array of dragTargets, which is a list of objects that are draggable.
var ContainerConstrainedDrag_dragableObjects = [];
	
var ContainerConstrainedDrag_dragObject = null;

//		DROP TARGET OBJECTS
//
// Declare an array of dropTargets, which is a list of objects on which it is valid to drop the
// currently being-dragged object.
var ContainerConstrainedDrag_dropTargetObjects = [];

//      CONTAINER POSITION LIMITS
//
var ContainerConstrainedDrag_ConainerPositionLimits = {left:0,right:0,top:0,bottom:0};

	
// Now define the ContainerConstrainedDrag class member methods. 

function ContainerConstrainedDrag.prototype.setActive()
{
    //alert("IN ContainerConstrainedDrag.prototype.setActive()");
	// Call this method to enable the dragging of draggable items within the container.

	if (this.isActive)
	{
		// Then we are already active and everything should already be set up properly.
		return;
	}

    // We immediately set it active, even though we haven't finished setting everything up, because it's
    // possible that the user can move the mouse while this is going on and some draggable item might
    // get its onmousedown set to our onDragStart and have that onDragStart invoked before we finish
    // with all the rest. And in that case the drag object's onDragStart will report an error, i.e. that
    // it got called while isActive is false.
    // So, we set isActive to true right away. :)
	this.isActive = true;

	// ON MOUSE MOVE
	//
	// Save the container's prior onmousemove method.
	this.containerOnMouseMovePrior = this.container.onmousemove;
	//
	// Override the container's onmousemove method with our own onMouseMove method.
	this.container.onmousemove = this.onMouseMove;
	//this.container.onmousemove.ContainerConstrainedDragObject = this;
    //alert("IN ContainerConstrainedDrag.prototype.setActive()\n,this = " + this + " id = " + this.id);
    //alert("IN ContainerConstrainedDrag.prototype.setActive()\n,this.container.onmousemove.ContainerConstrainedDragObject = " + this.container.onmousemove.ContainerConstrainedDragObject + " id = " + this.container.onmousemove.ContainerConstrainedDragObject.id);
		
	// ON MOUSE UP
	//
	// Save the container's prior onmouseup method.
	this.containerOnMouseUpPrior = this.container.onmouseup;
	//
	// Override the container's onmouseup method with our own onMouseUp method.
	this.container.onmouseup = this.onMouseUp;

//	// ON MOUSE OUT (LEAVE)
//	//
//	// Save the container's prior onmouseout method.
//	this.containerOnMouseOutPrior = this.container.onmouseout;
//	//
//	// Override the container's onmouseout method with our own onMouseLeave method.
//	this.container.onmouseout = this.onMouseLeave;
//	//this.container.onmouseout.ContainerConstrainedDragObject = this;
//    //alert("IN ContainerConstrainedDrag.prototype.setActive()\,this.container.onmouseout.ContainerConstrainedDragObject = " + this.container.onmouseout.ContainerConstrainedDragObject + " id = " + this.container.onmouseout.ContainerConstrainedDragObject.id);
	
	//this.showAllDragableObjects();
	
    //alert("IN ContainerConstrainedDrag.prototype.setActive() Enable all of the draggable objects.");
	// Enable all of the draggable objects.
	
	for (var index = 0 ; index < ContainerConstrainedDrag_dragableObjects.length ; ++index)
	{
	    var item = ContainerConstrainedDrag_dragableObjects[index];
	    //alert("item = ContainerConstrainedDrag_dragableObjects[index]; >> item = " + item + " " + item.id);
	    if (item)
	    {
	        this.dragEnableItem(item);
        }
	}
	
    //alert("OUT FROM ContainerConstrainedDrag.prototype.setActive() with this.isActive = " + this.isActive);

}

function ContainerConstrainedDrag.prototype.showAllDragableObjects()
{
    // Just a helper function.
    var Text = "";

	for (var index = 0 ; index < ContainerConstrainedDrag_dragableObjects.length ; ++index)
	{
	    var item = ContainerConstrainedDrag_dragableObjects[index];
	    if (item)
	    {
	        Text += "item " + index + " = " + item + " id = " + item.id + "\n";
        }
	}
	alert("All Dragable Objects:\n" + Text);
}

function ContainerConstrainedDrag.prototype.setInactive()
{
	// Call this method to disable the dragging of draggable items within the container.

	if (!this.isActive)
	{
		// Then the container is not currently active so we don't need (shouldn't?) do anything.
		return;
	}

	ContainerConstrainedDrag.SnapDraggingObjectBackToOriginalPosition(); //if necessary

	// Restore the container's mouse methods to its prior methods.
	this.container.onmousemove = this.containerOnMouseMovePrior;
	this.container.onmouseup = this.containerOnMouseUpPrior;
//	this.container.onmouseout = this.containerOnMouseOutPrior;
	
	// Disable all of the draggable objects.
	
	for (var index = 0 ; index < ContainerConstrainedDrag_dragableObjects.length ; ++index)
	{
	    var item = ContainerConstrainedDrag_dragableObjects[index];
	    //alert("item = ContainerConstrainedDrag_dragableObjects[index]; >> item = " + item + " " + item.id);
	    if (item)
	    {
	        this.dragDisableItem(item);
        }
	}	

	dragObject = null;

	this.isActive = false;
}

function ContainerConstrainedDrag.SnapDraggingObjectBackToOriginalPosition() // This is a class method,no an instance method.
{
	//if (this.isActive)
	{
		if (ContainerConstrainedDrag_dragObject)
		{
			// It looks like we have an object that was being dragged.
			// NOTE Not finished.


			ContainerConstrainedDrag_dragObject = null;
		}
	}
}

//function ContainerConstrainedDrag.prototype.onMouseLeave(e)
//{
//	// Do not try to test for if (this.isActive) because the "this" keyword in this case
//	// refers to theevent object that caused the event, NOT the ContainerConstrainedDrag object,
//	// so this.isActive does not refer to OUR isActive, andin fact doesn't even exist in this context.
//	
//	// My experience is that this also gets called when the mouse ENTERS the area!!
//	
//	// This is not a safe way to detect it.
//	
//	if (ContainerConstrainedDrag_dragObject)
//	{
//    	alert("IN onMouseLeave with a drag object");
//
//    	ContainerConstrainedDrag.SnapDraggingObjectBackToOriginalPosition();
//	
//    	ContainerConstrainedDrag_dragObject = null;
//    }
//
//	return false; // So it doesn't call default or higher level event handlers. NOTE Should I provide a way for the
//			// constructor of the ContainerConstrainedDrag class to specify whether this should be done?
//}

function ContainerConstrainedDrag.getItemPosition(item) // a class method, not an instance method.
{
	// Given the specified item, this calculates its absolute position, relative to its top-most parent.
	var left = 0;
	var top  = 0;

	var width = item.offsetWidth;
	var height = item.offsetHeight;

	// Travel up through the sequence of parents, consecutively adding each parent's offset to
	// the x,y position. 
	while (item.offsetParent)
	{
		// NOTE Does this also need to take into account the scrolling status of the items?
		left += item.offsetLeft;
		top  += item.offsetTop;
		item = item.offsetParent;
	}

	// Add the final parent's offsets.
	left += item.offsetLeft;
	top  += item.offsetTop;
	

    //alert("IN getItemPosition("+item+")\nReturning\nx = " + left + "\ntop = " + top + "\nwidth = " + width + "\nheight = " + height);
	return {x:left, y:top, width:width, height:height};
}

function ContainerConstrainedDrag.getMousePosition(ev) // a class method, not an instance method.
{
	// NOTE I think this may be returning the absolute screen coordinates of the mouse.
	// Get and return the position of the mouse position.
	// calculated as relative to the upper left corner of the document, taking into account the scrolled position of the document.

	if(ev.pageX || ev.pageY)
	{
		// The ev.pageX and ev.pageY values are indeed available, indicating that we are NOT in Internet Explorer,
		// so return those values. They already take into account the scrolling of the document.
		return {x:ev.pageX, y:ev.pageY};
	}
	return {
		// It appears that we're in Internet explorer, which uses event,clientX and event.ClientY
		// as the position values.
		x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
		y:ev.clientY + document.body.scrollTop  - document.body.clientTop
	};
}

function ContainerConstrainedDrag.getMouseOffset(target, ev) // This is a class method, not an instance method.
{
	// Calculate and return the position on the ev object (presumably where the mouse event occurred)
	// relative to the target object (presumably, but not necessarily, the Document).

	ev = ev || window.event;

	var itemPos  = ContainerConstrainedDrag.getItemPosition(target);
	var mousePos = ContainerConstrainedDrag.getMousePosition(ev);
	return {x:mousePos.x - itemPos.x, y:mousePos.y - itemPos.y};
}

function ContainerConstrainedDrag.prototype.onDragStart(ev)
{
    //alert("Succeeded in setting ContainerConstrainedDrag.prototype.onDragStart for the item");
	// Do not try to test for if (this.isActive) because the "this" keyword in this case
	// refers to theevent object that caused the event, NOT the ContainerConstrainedDrag object,
	// so this.isActive does not refer to OUR isActive, andin fact doesn't even exist in this context.

    //alert("Succeeded in setting ContainerConstrainedDrag.prototype.onDragStart for the item WHILE ACTIVE");
   	// This is used to override the onmousedown event handlers for the draggable items.
    ContainerConstrainedDrag_dragObject  = this;
 
    mouseOffset = ContainerConstrainedDrag.getMouseOffset(this, ev); 

    return false; // So it doesn't call default or higher level event handlers. NOTE Should I provide a way for the
			// constructor of the ContainerConstrainedDrag class to specify whether this should be done?
}

function ContainerConstrainedDrag.prototype.dragEnableItem(item)
{
    //alert("IN ContainerConstrainedDrag.prototype.dragEnableItem(item = " + item + " id = " + item.id + ")");
    
    if (item)
    {
        // It is possible that the item does not yet have a style element.
        if (!item.style)
        {
            alert("IN ContainerConstrainedDrag.prototype.dragEnableItem(item)\nitem.style does not yet exist.");
   
            item.style = {};
            
            alert("item.style now = " + item.style);

            item.style = "Style"; // give it SOME value !?
            
            alert("item.style now = " + item.style);
        }
        
    
        //alert("Tring to do: item.onmousedownprior = item.onmousedown;")
   	    // Add some properties to the item that remembers its prior onmousedown method.
   	    item.onmousedownprior = item.onmousedown;
 
        //alert("Tring to item.onmousedown = this.onDragStart;");
   	    // Override this object's onmousedown event handler, using our own (privately defined)
   	    // function which remembers the object as the dragObject, remembers its positional offset as mouseOffset
   	    // and returns false in order to prevents the default onmousedown event handler from being called.
   	    item.onmousedown = this.onDragStart;
   	    
   	    item.style.position = 'absolute'; // NOTE perhaps we should remember and be able to restore its previous position style;
   	    
//   	    // Add a ContainerConstrainedDragObject property which references the ContainerConstrainedDrag object so
//  	    // that the event handlers for the draggable item can have access to it. This is necessary because the "this"
//   	    // operator within the event handlers refers to the event object, not our ContainerConstrainedDrag object.
//   	    item.ContainerConstrainedDragObject = this;
//   	    
//   	    //alert("item.ContainerConstrainedDragObject = " + item.ContainerConstrainedDragObject);
   	}
   	else
   	{
        alert("ContainerConstrainedDrag.prototype.dragEnableItem(item) CALLED WITH NO ITEM");
   	}

}

function ContainerConstrainedDrag.prototype.dragDisableItem(item)
{
    // Restore its onmousedown handler
    if (item.onmousedownprior)
    {
        item.onmousedown = item.onmousedownprior;
        item.onmousedownprior = null;
    }
}

function ContainerConstrainedDrag.prototype.draggableObjectAdd(item)
{
    //alert("IN ContainerConstrainedDrag.prototype.draggableObjectAdd(item = " + item + " " + item.id + ")\nthis = " + this + " " + this.id);
	// Before any object can be dragged we must explicitly make it draggable, by calling this method
	// and passing in the object itself.

	// This method makes the specified object "dragable".
	// We do this by overriding the object's onmousedown method with our own (private)
	// function.

	//alert("ContainerConstrainedDrag.prototype.draggableObjectAdd ENTER  item = " + item);

	if (!item)
	{
		// No object was passed in, so do nothing.
		alert("ContainerConstrainedDrag.prototype.draggableObjectAdd called with no item");
		return;
	}
	// Otherwise, we seem to have a valid object to deal with.
	//alert("ContainerConstrainedDrag.prototype.draggableObjectAdd Seems to have good item = " + item);
	// NOTE Is there any way to determine whether what was passed in is actually an object and not,
	// say, a number or some other such thing?
	
	for (var index = 0 ; index < ContainerConstrainedDrag_dragableObjects.length ; ++index)
	{
	    if (ContainerConstrainedDrag_dragableObjects[index] == item)
	    {
	        // The item is already in the list, so we do not add it again.
		    alert("ContainerConstrainedDrag.prototype.draggableObjectAdd ITEM ALREADY IN LIST");
		    return;
	    }
	}  
	
    if (this.isActive)
    {
        // We're already active and the user is adding even more items, so
        // so we need to do the modification of its handlers here.  
        this.dragEnableItem(item);
    }
	// Add the specified object to the ContainerConstrainedDrag_dragableObjects array.

	ContainerConstrainedDrag_dragableObjects.push(item); // Which also remembers its current (prior) onmousedown.
	
	//this.showAllDragableObjects();

}

function ContainerConstrainedDrag.prototype.draggableObjectRemove(draggableObjectToRemove)
{
	var item;

	for (var index = 0 ; index < ContainerConstrainedDrag_dragableObjects.length ; ++index)
	{
		item = ContainerConstrainedDrag_dragableObjects[index]; 
		if (item && (item == draggableObjectToRemove))
		{
		    if (isActive)
		    {
		        dragDisableItem(item);
		    }
			ContainerConstrainedDrag_dragableObjects[index] = null;
			return;
		}
	}
}

function ContainerConstrainedDrag.prototype.draggableObjectsPurge()
{
	var item;

	while(ContainerConstrainedDrag_dragableObjects.length > 0)
	{
		item = ContainerConstrainedDrag_dragableObjects[ContainerConstrainedDrag_dragableObjects.length-1]; 
		if (item) //not null
		{
		    if (isActive)
		    {
		        dragDisableItem(item);
		    }
			ContainerConstrainedDrag_dragableObjects.pop();
		}
	}

	ContainerConstrainedDrag_dragableObjects.length = 0;
}

function ContainerConstrainedDrag.prototype.onMouseMove(ev)
{
	// NOTE We probably only want to do this if we actually are dragging an object.
	// We probably want to invoke the default Docuent.onmousemove if we are not dragging an object.

	// This function, once it overrides the document's onmousemove method, will be called whenever the
	// mouse moves and is used to update the position of the being-dragged object so that
	// it tracks along with the mouse position.

	// Get and save the position of the mouse, as the variable mousePos, with the position
	// calculated as relative to the upper left corner of the document, taking into account the scrolled position of the documen.

	// Get the mouse move event.
	//  In Internet Explorer this event is global; it's stored in window.event.
	// In Firefox, and other browsers, this event is passed to whatever function is attached to the action.
	// Since we this mouseMove function is attached (overrides) document.onmousemove, mouseMove gets passed
	// the event object.
	//
	// To make ev correctly contain the event object in every browser we OR it with window.event.
	// In Firefox the " || window.event" posrtion of the expression will be ignored since ev will already contain the event.
	// In IE ev is null so it will get set to window.event.
	
    var dragObject = ContainerConstrainedDrag_dragObject;

	if(dragObject)
	{
	    //alert("IN onMouseMove with a drag object");
    	ev = ev || window.event;
    	var mousePos = ContainerConstrainedDrag.getMousePosition(ev);
    	
    	// Restrict the dragging of the item to be within the container.
    	// NOTE: We should actually take into account the extent of the thing we're dragging so that
    	// we dont end up with it overlapping the border of the container.
    	if (ContainerConstrainedDrag.isPositionWithinContainer(mousePos.x,mousePos.y))
    	{
    	    // The mouse is within the container.
    		//dragObject.style.position = 'absolute'; I don't think this is necessary here, done in enabledrag
	    	dragObject.style.top = mousePos.y - mouseOffset.y;
		    dragObject.style.left = mousePos.x - mouseOffset.x;
		}
		else
		{
		    // The mouse is outside the container.
		    // SO donot re-position the item.
		}

		return false;
	}

	return false; // So it doesn't call default or higher level event handlers. NOTE Should I provide a way for the
			// constructor of the ContainerConstrainedDrag class to specify whether this should be done?
}

function ContainerConstrainedDrag.prototype.dropTargetAdd(dropTarget)
{
	// Add the specified object to the dropTargetObjects array, but only if an object was actually specified
	// and it's not already in the array.
	if (dropTarget)
	{
		// We seem to have an object.
		// NOTE Is there any way to determine whether what was passed in is actually an object and not,
		// say, a number or some other such thing?
		
		for (var index = 0 ; index < ContainerConstrainedDrag_dropTargetObjects.length ; ++index)
		{
		    var item = ContainerConstrainedDrag_dropTargetObjects[index];
		    if (item == dropTarget)
		    {
		        // We already have it in our list of drop targets.
		        // We do not want duplicates in the list, so
		        return;
		    }
		}
		// It's not already in the list, so add it.
		ContainerConstrainedDrag_dropTargetObjects.push(dropTarget);
	}
	else
	{
	    alert("ContainerConstrainedDrag.prototype.dropTargetAdd(dropTarget) CALLED WITH NULL dropTarget")
	}
}

function ContainerConstrainedDrag.prototype.dropTargetRemove(dropTargetToRemove)
{
    if (dropTargetToRemove)
    {
    	var theObject;

    	for (var index = 0 ; index < ContainerConstrainedDrag_dropTargetObjects.length ; ++index)
    	{
    		theObject = ContainerConstrainedDrag_dropTargetObjects[index]; 
    		if (theObject && (theObject == dropTargetToRemove))
    		{
    			ContainerConstrainedDrag_dropTargetObjects[index] = null;
    			return;
    		}
    	}
    }
    else
    {
	    alert("ContainerConstrainedDrag.prototype.dropTargetRemove(dropTargetToRemove) CALLED WITH NULL dropTarget")
    }
}

function ContainerConstrainedDrag.prototype.dropTargetsPurge()
{
   	var item;

   	for (var index = 0 ; index < ContainerConstrainedDrag_dropTargetObjects.length ; ++index)
   	{
   		item = ContainerConstrainedDrag_dropTargetObjects[index]; 
   		if (item)
   		{
   			ContainerConstrainedDrag_dropTargetObjects[index] = null;
   		}
   	}
}

function ContainerConstrainedDrag.prototype.onMouseUp(ev)
{
	// NOTE We probably only want to do this if we actually are dragging an object.
	// We probably want to invoke the default container.onmouseup if we are not dragging an object.

	// NOTE Wait a minute! How can this be refering to "this" ??

	// Do not try to test for if (this.isActive) because the "this" keyword in this case
	// refers to theevent object that caused the event, NOT the ContainerConstrainedDrag object,
	// so this.isActive does not refer to OUR isActive, andin fact doesn't even exist in this context.
	
	//alert("IN onMouseUp");

	if (ContainerConstrainedDrag_dragObject)
	{
		// Get the event, presumably the mouse up event.
		ev = ev || window.event;
		// Get the position of the mouse whenthe event occurred.
		var mousePos = ContainerConstrainedDrag.getMousePosition(ev);
		
		// Go through our list of ContainerConstrainedDrag_dropTargetObjects and see if the position of the mouse
		// corresponds with the dropTarget,i.e. is within the area of the dropTarget.
		for(var i=0 ;  i < ContainerConstrainedDrag_dropTargetObjects.length ;  i++)
		{
			var curTarget  = ContainerConstrainedDrag_dropTargets[i];
			var targPos    = ContainerConstrainedDrag.getItemPosition(curTarget);
			var targWidth  = parseInt(curTarget.offsetWidth);
			var targHeight = parseInt(curTarget.offsetHeight);
		
			if (
				(mousePos.x > targPos.x)                &&
				(mousePos.x < (targPos.x + targWidth))  &&
				(mousePos.y > targPos.y)                &&
				(mousePos.y < (targPos.y + targHeight)))
				{
					// dragObject was dropped onto curTarget!
					// NOTE Here is where we need to actually DO something with it.
					
					// NOTE should probably RESTORE the object's style.position (e.g. to "relative") or whatever it was PRIOR.
		
					ContainerConstrainedDrag_dragObject = null;
					return ;
				}
		}
		
	    ContainerConstrainedDrag.SnapDraggingObjectBackToOriginalPosition();
	    
	    
		// If we get here then the mouse is not positioned on one of our dropTargets.
		// NOTE THis probably means that we want to move it back to where it was previously.
		ContainerConstrainedDrag_dragObject = null;
	
		return false; // So it doesn't call default or higher level event handlers. NOTE Should I provide a way for the
			// constructor of the ContainerConstrainedDrag class to specify whether this should be done?
	
	}
	else
	{
		// We actually aren't dragging anything.
			
		return false; // So it doesn't call default or higher level event handlers. NOTE Should I provide a way for the
			// constructor of the ContainerConstrainedDrag class to specify whether this should be done?
	}
}

function ContainerConstrainedDrag.GetContainerLimits(container)
{
    if (container)
    {
        var position = ContainerConstrainedDrag.getItemPosition(container);
        
        ContainerConstrainedDrag_ConainerPositionLimits.left = position.x;
        ContainerConstrainedDrag_ConainerPositionLimits.top = position.y;
        
        ContainerConstrainedDrag_ConainerPositionLimits.right = position.x + position.width - 1;
        ContainerConstrainedDrag_ConainerPositionLimits.bottom = position.y + position.height - 1;
        
        //alert("Container Limits left = " + ContainerConstrainedDrag_ConainerPositionLimits.left + " right = " + ContainerConstrainedDrag_ConainerPositionLimits.right + " top = " + ContainerConstrainedDrag_ConainerPositionLimits.top + " bottom = " + ContainerConstrainedDrag_ConainerPositionLimits.bottom);
        
    }
}

function ContainerConstrainedDrag.isPositionWithinContainer(x,y)
{
    var Limits = ContainerConstrainedDrag_ConainerPositionLimits;
    if ((x >= Limits.left) && (x <= Limits.right) && (y >= Limits.top) && (y <= Limits.bottom))
    {
        return true;
    }
    return false;
}


