// Part of the Low Pro extensions to Prototype, by Dan Webb
// Download the latest version of this file from:
// http://svn.danwebb.net/external/lowpro/trunk/behaviours/draggable.js

Draggable = Behavior.create({
  initialize : function(options) {
    this.options = Object.extend({
      onStart : Prototype.K,
      onComplete : Prototype.K,
      units : 'px',
      zindex : 1000,
      revert : true
    }, options || {});
    
    this.handle = this.options.handle || this.element;
    Draggable.Handle.attach(this.handle, this);
    
    this.element.makePositioned();
      
    this.startX = this.element.getStyle('left') || '0px';
    this.startY = this.element.getStyle('top') || '0px';
    this.startZ = this.element.getStyle('z-index');
      
    Draggable.draggables.push(this);  
  },
  move : function(x, y) {
    this.element.setStyle({
      left : (parseInt(this.element.getStyle('left')) || 0) + x + this.options.units,
      top : (parseInt(this.element.getStyle('top')) || 0) + y + this.options.units
    });
  },
  drag : function(e) {
    this.clientX = e.clientX;
		this.clientY = e.clientY;
		this.move(this.clientX - this.lastMouseX, this.clientY - this.lastMouseY)
    this.set(e);
		return false;
  },
  set :function(e) {
    this.lastMouseX = e.clientX;
		this.lastMouseY = e.clientY;
  },
  stop : function() {
    this.unbindDocumentEvents();
    
    Draggable.targets.each(function(target) {
      if (Position.within(target.element, this.clientX, this.clientY)) {
        target.onDrop(this);
      }
    }.bind(this));
    
    this.options.onComplete(this);
    
    if (this.options.revert) {
      if (typeof this.options.revert == 'function') {
        this.options.revert(this);
      } else this.element.setStyle({
        left : this.startX,
         top : this.startY
      });
    }
    
    this.element.style.zIndex = this.startZ;
  },
  bindDocumentEvents : function() {
    document.onmousemove = this.drag.bindAsEventListener(this);
    document.onmouseup = this.stop.bindAsEventListener(this);
  },
  unbindDocumentEvents : function() {
    document.onmousemove = document.onmouseup = null;
  }
});

Draggable.Handle = Behavior.create({
  initialize : function(draggable) {
    this.draggable = draggable;
  },
  onmousedown : function(e) {
		this.draggable.bindDocumentEvents();
		this.draggable.set(e);
		this.draggable.element.style.zIndex = this.draggable.options.zindex;
		this.draggable.options.onStart(this.draggable);
		return false;
  }
});

Draggable.draggables = [];
Draggable.targets = [];

Draggable.DropTarget = Behavior.create({
  initialize : function(options) {
    this.options = Object.extend({
      onDrop : Prototype.K
    }, options || {});
    
    Draggable.targets.push(this);
  },
  onDrop : function(draggable) {
    if (this.canDrop(draggable))
      return this.options.onDrop.call(this, draggable);
    else return false;
  },
  canDrop : function(draggable) {
    return !this.options.accepts || draggable.element.hasClassName(this.options.accepts);
  }
});
