/**
* EasyDrag 1.5 - Drag & Drop jQuery Plug-in
*
* Thanks for the community that is helping the improvement
* of this little piece of code.
*
* For usage instructions please visit http://fromvega.com/scripts
*/

(function(jQuery){

  // to track if the mouse button is pressed
  var isMouseDown    = false;

  // to track the current element being dragged
  var currentElement = null;

  // callback holders
  var dropCallbacks = {};
  var dragCallbacks = {};
  
  // bubbling status
  var bubblings = {};

  // global position records
  var lastMouseX;
  var lastMouseY;
  var lastElemTop;
  var lastElemLeft;
  
  // track element dragStatus
  var dragStatus = {};  

  // if user is holding any handle or not
  var holdingHandler = false;

  // returns the mouse (cursor) current position
  jQuery.getMousePosition = function(e){
    var posx = 0;
    var posy = 0;

    if (!e) var e = window.event;

    if (e.pageX || e.pageY) {
      posx = e.pageX;
      posy = e.pageY;
    }
    else if (e.clientX || e.clientY) {
      posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
      posy = e.clientY + document.body.scrollTop  + document.documentElement.scrollTop;
    }

    return { 'x': posx, 'y': posy };
  };

  // updates the position of the current element being dragged
  jQuery.updatePosition = function(e) {
    var pos = jQuery.getMousePosition(e);

    var spanX = (pos.x - lastMouseX);
    var spanY = (pos.y - lastMouseY);

    jQuery(currentElement).css("top",  (lastElemTop + spanY));
    jQuery(currentElement).css("left", (lastElemLeft + spanX));
  };

  // when the mouse is moved while the mouse button is pressed
  jQuery(document).mousemove(function(e){
    if(isMouseDown && dragStatus[currentElement.id] != 'false'){
      // update the position and call the registered function
      jQuery.updatePosition(e);
      if(dragCallbacks[currentElement.id] != undefined){
        dragCallbacks[currentElement.id](e, currentElement);
      }

      return false;
    }
  });

  // when the mouse button is released
  jQuery(document).mouseup(function(e){
    if(isMouseDown && dragStatus[currentElement.id] != 'false'){
      isMouseDown = false;
      if(dropCallbacks[currentElement.id] != undefined){
        dropCallbacks[currentElement.id](e, currentElement);
      }

      return false;
    }
  });

  // register the function to be called while an element is being dragged
  jQuery.fn.ondrag = function(callback){
    return this.each(function(){
      dragCallbacks[this.id] = callback;
    });
  };

  // register the function to be called when an element is dropped
  jQuery.fn.ondrop = function(callback){
    return this.each(function(){
      dropCallbacks[this.id] = callback;
    });
  };
  
  // disable the dragging feature for the element
  jQuery.fn.dragOff = function(){
    return this.each(function(){
      dragStatus[this.id] = 'off';
    });
  };
  
  // enable the dragging feature for the element
  jQuery.fn.dragOn = function(){
    return this.each(function(){
      dragStatus[this.id] = 'on';
    });
  };
  
  // set a child element as a handler
  jQuery.fn.setHandler = function(childDef , allowBubbling){
    return this.each(function(){
      var draggable = this;
      
      // enable event bubbling so the user can reach the handle
      //cyril : fix bug on select fields with safari
      bubblings[this.id] = true;
      
      // reset cursor style
      jQuery(draggable).css("cursor", "auto");
      
      // set current drag status
      dragStatus[draggable.id] = "handler";

      // change handle cursor type
      jQuery("#"+this.id+' '+childDef).css("cursor", "move");  
      
      // bind event handler
      jQuery("#"+this.id+' '+childDef).mousedown(function(e){
        holdingHandler = true;
        jQuery(draggable).trigger('mousedown', e);
      });
      
      // bind event handler
      jQuery("#"+this.id+'>'+childDef).mouseup(function(e){
        holdingHandler = false;
      });
    });
  }
  
  jQuery.fn.triggerDrag = function( e ) {
    return this.each(function(){
      holdingHandler = true;
      jQuery(this).trigger('mousedown', e);
    });
  };
  
  jQuery.fn.triggerDrop = function( e ) {
    return this.each(function(){
      holdingHandler = false;
      jQuery(this).trigger('mouseup', e);
    });
  };
  
  // set a child element as a handler
  jQuery.fn.setDropArea = function( areaDef , minimums ){
    return this.each(function(){
      var draggable = this;
      minimums = jQuery.extend( {}, { 'top': 0, 'right': 0, 'bottom': 0, 'left': 0 }, minimums );
      
      jQuery(this).ondrop(function(){
        
        var awp = jQuery(areaDef).windowPosition(); 
        var ah = jQuery(areaDef).height(); 
        var aw = jQuery(areaDef).width(); 
        
        var dwp = jQuery(draggable).windowPosition(); 
        var dh = jQuery(draggable).height() + ( isNaN( parseInt( jQuery(draggable).css('border-top-width') ) ) ? 0 : parseInt( jQuery(draggable).css('border-top-width') ) ) + ( isNaN( parseInt( jQuery(draggable).css('border-bottom-width') ) ) ? 0 : parseInt( jQuery(draggable).css('border-bottom-width') ) ); 
        var dw = jQuery(draggable).width() + ( isNaN( parseInt( jQuery(draggable).css('border-left-width') ) ) ? 0 : parseInt( jQuery(draggable).css('border-left-width') ) ) + ( isNaN( parseInt( jQuery(draggable).css('border-right-width') ) ) ? 0 : parseInt( jQuery(draggable).css('border-right-width') ) ); 
    

        if( dwp.x < awp.x + minimums.left ){
          jQuery(draggable).css("left", minimums.left );
        }else if( aw - dw < minimums.left ){
          jQuery(draggable).css("left", minimums.left );
        }else if( dwp.x + dw > awp.x + aw - minimums.right ){
          jQuery(draggable).css("left", aw - dw - minimums.right );
        }
        
        if( dwp.y < awp.y + minimums.top ){
          jQuery(draggable).css("top", minimums.top );
        }else if( ah - dh < minimums.top ){
          jQuery(draggable).css("top", minimums.top );
        }else if( dwp.y + dh > awp.y + ah - minimums.bottom ){
          jQuery(draggable).css("top", ah - dh - minimums.bottom );
        }
        
        
      });
    });
  }
  
  // set an element as draggable - allowBubbling enables/disables event bubbling
  jQuery.fn.easydrag = function(allowBubbling){

    return this.each(function(){

      // if no id is defined assign a unique one
      if(undefined == this.id || !this.id.length) this.id = "easydrag"+(new Date().getTime());
      
      // save event bubbling status
      bubblings[this.id] = allowBubbling ? true : false;

      // set dragStatus 
      dragStatus[this.id] = "on";
      
      // change the mouse pointer
      jQuery(this).css("cursor", "move");

      // when an element receives a mouse press
      jQuery(this).mousedown(function(e){
        
        // just when "on" or "handler"
        if((dragStatus[this.id] == "off") || (dragStatus[this.id] == "handler" && !holdingHandler))
          return bubblings[this.id];

        // set it as absolute positioned
        jQuery(this).css("position", "absolute");

        // set z-index
        //jQuery(this).css("z-index", parseInt( new Date().getTime()/1000 ));
        jQuery(this).css("z-index", ( new Date().getHours() * 10000 ) + ( new Date().getMinutes() * 100 ) + ( new Date().getSeconds() ) );

        // update track variables
        isMouseDown    = true;
        currentElement = this;

        // retrieve positioning properties
        var pos    = jQuery.getMousePosition(e);
        lastMouseX = pos.x;
        lastMouseY = pos.y;

        lastElemTop  = this.offsetTop;
        lastElemLeft = this.offsetLeft;

        jQuery.updatePosition(e);

        return bubblings[this.id];
      });
    });
  };

})(jQuery);

jQuery.fn.extend({
   windowPosition : function() {
       var obj = jQuery(this).get(0);
       var curleft = obj.offsetLeft || 0;
       var curtop = obj.offsetTop || 0;
       while (obj = obj.offsetParent) {
                curleft += obj.offsetLeft
                curtop += obj.offsetTop
       }
       return {x:curleft,y:curtop};
   }
});