function MMO(){
	this.currentLeft = 0;
	this.currentTop = 0;
	this.deltaX = 0;
	this.deltaY = 0;
	this.onchange = new DOMEvent();
}
MMO.prototype.start = function(e){
	this.currentLeft = e.clientX;
	this.currentTop = e.clientY;
	this.offsetX = e.offsetX || e.layerX;
	this.offsetY = e.offsetY || e.layerY;
}
MMO.prototype.change = function(e){
	var ev = window.event || e;
	this.deltaX = ev.clientX - this.currentLeft;
	this.deltaY = ev.clientY - this.currentTop;
	this.currentLeft = ev.clientX;
	this.currentTop = ev.clientY;
	this.onchange.fire(this.deltaX, this.deltaY);

}
function DragDrop(oMov, handles){
	this.moveable = moveable.detectMoveable(oMov);
	this.mmo = new MMO();
	this.mmo.onchange.register("move", function(x, y){
		this.moveable.moveBy(x, y);
	}.bind(this))
	this.elem = this.moveable.elem;
	this.handles = DragDrop.detectHandles(handles, this.elem);
	this.currentMouseLeft = null;
	this.currentMouseTop = null;
	this.ondragstart = new DOMEvent(this);
	this.ondrag = DOMEvent.cloneEvent(this.moveable.onmove, this);
	this.ondrop = new DOMEvent(this);
	this.mouse_x = 0;
	this.mouse_y = 0;
	this.active_handle = null;
	this.IS_DRAGGING = false;
	this.init();
	if(this.constructor._TO_INSTANCES){
		this.constructor._instances.push(this);
	}
}
Object.extend(DragDrop.prototype, default_prototype_functions);
DragDrop.prototype.init = function(){
	this.init_events();
	this.init_handles();
};
DragDrop.prototype.init_handles = function(){
	this.handles.each(function(handle){
		handle.onselectstart = function(){return false;}
		handle.onmousedown = function(e, oHandle){
			var _handle = oHandle || e; //ev in case of IE
			var ev = window.event || e;
			var x = ev.offsetX || ev.layerX;
			var y = ev.offsetY || ev.layerY;
			this.active_handle = _handle;
			this.mouse_x = x;
			this.mouse_y = y;
			this.start(ev);
		}.bind(this, handle);
	}.bind(this));
};
DragDrop.prototype.start = function(e){
	var ev = e || window.event;
	this.mmo.start(ev);
	this.curr_pageXOffset = window.pageXOffset;
	this.curr_pageYOffset = window.pageYOffset;
	this._start();
	return false;
};
DragDrop.prototype._start = function(){
	this.IS_DRAGGING = true;
	DragDrop.current = this;
	window.onscroll = this.scroll.bind(this);
	DragDrop.mouseup = this.drop.bind(this);
	AttachEvent(document, "mouseup", DragDrop.mouseup);
	document.onselectstart = document.onmousedown = function(){
		return false;
	};
};
DragDrop.prototype.drop = function(e){
	this.IS_DRAGGING = false;
	DragDrop.current = null;
	window.onscroll = null;
	DetachEvent(document, "mouseup", DragDrop.mouseup);
	document.onselectstart = document.onmousedown = null;
	this.ondrop.fire();
};
DragDrop.prototype.scroll = function(e){
	var deltaX = window.pageXOffset - this.curr_pageXOffset;
	var deltaY = window.pageYOffset - this.curr_pageYOffset;
	this.moveable.moveBy(deltaX, deltaY);
	this.curr_pageXOffset = window.pageXOffset;
	this.curr_pageYOffset = window.pageYOffset;
};
DragDrop.prototype.start_from_dd = function(dd){
	var ev = {
		clientX: dd.mmo.currentLeft,
		clientY: dd.mmo.currentTop,
		offsetX: dd.mmo.offsetX,
		offsetY: dd.mmo.offsetY
	};
	this.start(ev);
}
DragDrop.prototype.__name = "DragDrop";
DragDrop.prototype._events = [
	{name: "dragstart", func_name: "_start", type: 'before'}	
];

DragDrop.detectHandles = function(handles, el){
	var ret;
	if(typeof handles == "string"){
		ret = $C(handles, el) || [el];
	}else if(handles instanceof Array){
		ret = handles;
	}else if(typeof handles == "object" && handles.nodeName){
		ret = [handles];
	}else if(typeof handles == "undefined" || typeof handles == "boolean"){
		ret = [el];
	}
	return ret;
};
DragDrop.current = null;
DragDrop.mouseup = null;
DragDrop._TO_INSTANCES = true;
DragDrop._instances = [];
DragDrop.__loaded = true;

document.onmousemove = function(e){
	if(DragDrop.current){
		DragDrop.current.mmo.change(e || window.event);
	}
};