//This code is based on the drag and drop tutorial at:
//http://luke.breuer.com/tutorial/javascript-drag-and-drop-tutorial.aspx

//external globals
var NumDragTargets = 0;


//internal globals
var _startX = 0; // mouse starting positions
var _startY = 0;
var _offsetX = 0; // current element offset
var _offsetY = 0;
var _dragElement; // needs to be passed from OnMouseDown to OnMouseMove
var _dragElementClone; //clone with body as parent so can be dragged anywhere
var _debug = null; // if set to a div will output debug messages to it
var _dragTargets = [];
var _dragTargetInfo = []; //positions, answers etc.


function InitDragDrop() 
{
   document.onmousedown = OnMouseDown;
   document.onmouseup = OnMouseUp;
   
   UpdateDragTargetPositions();
}

function MakeDraggable(elem, dragItem)
{
   if(!elem.allowDrag) {
      elem.allowDrag = true;
      elem.dragItem  = dragItem;
   }
   NumDragTargets++;
}

function MakeDragTarget(elem, dragTargetFor)
{
   if(_debug)
      _debug.innerHTML = 'targets Length: '+_dragTargets.length;

   if(!(elem in _dragTargets)) {
      _dragTargets.push(elem);
      elem.dragTargetFor = dragTargetFor;
   }
   
   //Ensure the poisitions are all up to date
   UpdateDragTargetPositions();
}



function UpdateDragTargetPositions()
{
   _dragTargetInfo = [];
   
   for(i = 0; i < _dragTargets.length; i++) {
      var elem = _dragTargets[i];
      var targInfo = new Object();
      
      targInfo.left   = GetAbsX(elem);
      targInfo.top    = GetAbsY(elem);

      targInfo.right  = targInfo.left + elem.offsetWidth;
      targInfo.bottom = targInfo.top + elem.offsetHeight;
      targInfo.dragTargetFor = elem.dragTargetFor;
      targInfo.elem   = elem;
      
      _dragTargetInfo.push(targInfo);
   }
}

function debugObject(obj)
{
   var text="";
   for( prop in obj)
   {
      text += prop + " = " +obj[prop];
   }
   alert(text);
}

function FindDragTarget(mouseX, mouseY, dragElem)
{
   for(i = 0; i < _dragTargetInfo.length; i++) {
      var targInfo = _dragTargetInfo[i];
      
      if(dragElem.dragItem == targInfo.dragTargetFor) {
         if(mouseX >= targInfo.left && mouseX <= targInfo.right) {
            if(mouseY >= targInfo.top && mouseY <= targInfo.bottom) {
               return targInfo.elem;
            }
         } 
      } 
   }
   return null;
}

function IsDraggable(elem)
{
   return elem.allowDrag;
}

function GetAbsX(elem)
{
   var abs_x = 0;

   while( elem != null ) {
      abs_x += elem.offsetLeft;      
      
      if(elem.scrollLeft) {
         abs_x -= elem.scrollLeft;
      }

      elem = elem.offsetParent;
   }
   return parseInt(abs_x);
}

function GetAbsY(elem)
{
   var abs_y = 0;

   while( elem != null ) {
      abs_y += elem.offsetTop;
      
      if(elem.scrollTop) {
         abs_y -= elem.scrollTop;
      }
      elem = elem.offsetParent;
   }
   return parseInt(abs_y);
}

function OnMouseDown(e)
{
   // IE is retarded and doesn't pass the event object
   if (e == null)
      e = window.event;
   
   // IE uses srcElement, others use target
   var target = e.target != null ? e.target : e.srcElement; 
   
   if(_debug)
      _debug.innerHTML = IsDraggable(target) ? 'draggable element clicked' : 'NON-draggable element clicked';
   
   // for IE, left click == 1 
   // for Firefox, left click == 0
   if ((e.button == 1 && window.event != null || e.button == 0) && IsDraggable(target)) {
      _dragStarting = true;
      
      // grab the mouse position
      _startX = e.clientX;
      _startY = e.clientY; 
            
      // grab the clicked element's position relative to the page
      _offsetX = GetAbsX(target);
      _offsetY = GetAbsY(target); 
       
      //We want to drag an img outside its containing div.... we clone it (and use the body as the containing div
      _dragElementClone = target.cloneNode(true);
      if(_dragElementClone.parentNode) {
         _dragElementClone.parentNode.removeChild(_dragElementClone);
      }
      _dragElementClone.style.position = 'absolute';
      _dragElementClone.style.left = _offsetX+"px";
      _dragElementClone.style.top = _offsetY+"px";
      _dragElementClone.style.zIndex = 50;
      document.body.appendChild(_dragElementClone);
            
      //hide the original element while we display the clone
      target.style.visibility = 'hidden';
      
      // we need to access the element in OnMouseUp
      _dragElement = target; 
      
      // tell our code to start moving the element with the mouse
      document.onmousemove = OnMouseMove; 
      
      // cancel out any text selections
      document.body.focus(); 
      // prevent text selection in IE
      document.onselectstart = function () { return false; }; 
      
      // prevent IE from trying to drag an image 
      target.ondragstart = function() { return false; }; 
      _dragElementClone.ondragstart = function() { return false; }; 
      
      // prevent text selection (except IE)
      return false;
   } 
}

function OnMouseMove(e)
{ 
   if (e == null)
      var e = window.event; 
   
   // this is the actual "drag code"
   _dragElementClone.style.left = (_offsetX + e.clientX - _startX) + 'px';
   _dragElementClone.style.top = (_offsetY + e.clientY - _startY) + 'px'; 
   
   if(_debug){
      _debug.innerHTML = '(' + _dragElementClone.style.left + ', ' + _dragElementClone.style.top + ')';
   }
}

function OnMouseUp(e)
{
   if (_dragElement != null)
   {   
      if (e == null)
         var e = window.event; 

      _dragElement.style.visibility = 'visible';
      
      //Did we land on a matching drag target?
      var dragTarget = FindDragTarget(e.clientX, e.clientY, _dragElement);
      
      if(dragTarget) {
         CorrectDrag(dragTarget, _dragElement);
      } else {
         IncorrectDrag(dragTarget, _dragElement);
      }
      
      //destroy the clone
      _dragElementClone.parentNode.removeChild(_dragElementClone);

      // we're done with these events until the next OnMouseDown 
      
      document.onmousemove = null;
      document.onselectstart = null;
      _dragElement.ondragstart = null; 
      
      // this is how we know we're not dragging 
      _dragElement = null; 
      _dragElementClone = null;
      
      if(_debug) {
         _debug.innerHTML = 'mouse up';
      } 
   }
}

function ExtractNumber(value)
{
   var n = parseInt(value);
   return n == null || isNaN(n) ? 0 : n; 
} 
