/* 
	Copyright (c) 2005-2008 Metablocks, Inc, Metablocks, Ltd. and their affiliates. 
	This software is under non-exclusive licensed to the party using it. 
	For more information contact: info@metablocks.com
	The software cannot reused without permission. All Rights Reserved.
	
	Do not remove this copyright notice.
	
	v. 1.3.2
	@requires EventManager.js, v. 1.0.0
*/

if(!window.DragDropManagementObject)
	window.DragDropManagementObject={
		DDTargetsList:[],
		registerDDTarget:function(t, dragDropGroupId){ 
			dragDropGroupId = dragDropGroupId ? dragDropGroupId : '_defaultDragDropGroup';
			if(!this.DDTargetsList[dragDropGroupId])
				this.DDTargetsList[dragDropGroupId]=[];
			this.DDTargetsList[dragDropGroupId][this.DDTargetsList[dragDropGroupId].length]=t; 
		},
		unregisterDDTarget:function(t){
			dragDropGroupId = t.dragDropGroupId ? t.dragDropGroupId : '_defaultDragDropGroup';
			var dragDropGroup=this.DDTargetsList[dragDropGroupId];
			for(var i=0; i<dragDropGroup.length; ++i)
				if(dragDropGroup[i]==t){
					dragDropGroup.splice(i, 1);
					break;
				}
		},
		objectIsDragged:function(di, dragDropGroupId){ 
			dragDropGroupId = dragDropGroupId ? dragDropGroupId : '_defaultDragDropGroup';
			var dragDropGroup=this.DDTargetsList[dragDropGroupId];
			for(var target in dragDropGroup)
				dragDropGroup[target].objectIsDragged(di);
		},
		objectIsDropped:function(di, dragDropGroupId){
			dragDropGroupId = dragDropGroupId ? dragDropGroupId : '_defaultDragDropGroup';
			var dragDropGroup=this.DDTargetsList[dragDropGroupId];
			for(var target in dragDropGroup)
				dragDropGroup[target].objectIsDropped(di);
		}
	}
function Draggable(el, dragDropGroupId){
		this.init(el, dragDropGroupId);
}
Draggable.prototype={
	el:null,
	dragIcon:null,
	startX:-1,
	startY:-1,
	dragIconDeltaX:0,
	dragIconDeltaY:0,
	dragThreshold:0,
	dragHandles:null,
	dragCursor:'move',
	dragDropGroupId:'_defaultDragDropGroup',
	dragging:false,
	data:{}, /* a field to store custom information. it is sent with the di object */
	init:function(el, dragDropGroupId){ 
		this.dragHandles=[];
		this.el=this.util.get(el);
		this.dragDropGroupId=dragDropGroupId ? dragDropGroupId : '_defaultDragDropGroup';
		if(this.el)	this.setDragHandle(this.el);
	},
	mouseDownHandler:function(e){ 
		this.startX=this.util.documentX(e); 
		this.startY=this.util.documentY(e); 
		EventManager.addListener(document, 'mouseup', this.mouseUpHandler, this);
		EventManager.addListener(document, 'mousemove', this.mouseMoveHandler, this);
		if(this.dragThreshold==0)	this._doStartDrag(e);
		EventManager.stopEvent(e); 
	},
	mouseUpHandler:function(e){
		if(this.onb4MouseUp)
			this.onb4MouseUp(this, e);
		EventManager.removeListener(document, 'mouseup', this.mouseUpHandler);
		EventManager.removeListener(document, 'mousemove', this.mouseMoveHandler);
		if(this.dragging){
			document.body.style.cursor='';
			var posX=this.util.documentX(e);
			var posY=this.util.documentY(e);
			var dragInfo={sender:this, 'e':e, 'x':posX, 'y':posY, 'data':this.data};
			if(this.onDragDrop)
				this.onDragDrop(dragInfo);
			window.DragDropManagementObject.objectIsDropped(dragInfo, this.dragDropGroupId); 
			var endDragRet=this.onEndDrag?(this.onEndDrag(dragInfo)!=false):true; // return value to indicate weather drag icon shall be hidden
			if(this.dragIcon && endDragRet){	// if onEndDrag handler did not return false then hide the drag icon
				this.dragIcon.style.display='none';
				this.dragIcon.style.cursor='';
			}
			this.dragging=false;
			EventManager.stopEvent(e);
		}
	},
	mouseMoveHandler:function(e){ 
		if(this.dragging)
			this._doDrag(e);
		else if(this.dragThreshold<Math.abs(this.startX-this.util.documentX(e)) || this.dragThreshold<Math.abs(this.startY-this.util.documentY(e))){
			this._doStartDrag(e);			
			if(this.dragging)
				this._doDrag(e);			
		}
	},
	_doStartDrag:function(e){ 
		var dragInfo={sender:this, 'e':e, 'x':this.util.documentX(e), 'y':this.util.documentY(e), 'startX':this.startX, 'startY':this.startY};
		if(this.onStartDrag(dragInfo)!=false){
			document.body.style.cursor=this.dragCursor;
			if(this.dragIcon)
				this.dragIcon.style.display='block';
			EventManager.stopEvent(e);
			this.dragging=true;
		}		
	},
	_doDrag:function(e){
		var posX=this.util.documentX(e); 
		var posY=this.util.documentY(e);	
		if(this.dragIcon){ 
			this.dragIcon.style.top=(posY-this.dragIconDeltaY)+'px';
			this.dragIcon.style.left=(posX-this.dragIconDeltaX)+'px';
		}
		var dragInfo={sender:this, 'e':e, 'x':posX, 'y':posY, 'data':this.data};
		window.DragDropManagementObject.objectIsDragged(dragInfo, this.dragDropGroupId);
		this.onDrag(dragInfo);
		EventManager.stopEvent(e);
	},
	onStartDrag:function(di){ },
	onDrag:function(di){ },
	onb4MouseUp:function(di){ },	// called just before further event processing
	onDragDrop:function(di){ },	
	onEndDrag:function(di){ return true; }, // return true to hide drag icon
	setDragIcon:function(el){
		this.dragIcon=this.util.get(el);
		this.dragIcon.style.cursor=this.dragCursor;
		this.dragIconDeltaX=this.startX-this.dragIcon.offsetLeft;
		this.dragIconDeltaY=this.startY-this.dragIcon.offsetTop;
	},
	setDragHandle:function(dh){ 
		for(var i=0; i<this.dragHandles.length; ++i)
			EventManager.removeListener(this.dragHandles[i], 'mousedown', this.mouseDownHandler);
		this.dragHandles.splice(0, this.dragHandles.length);
		this.addDragHandle(dh);
	},
	addDragHandle:function(dh){
		dh=this.util.get(dh);
		if(dh){
			this.dragHandles[this.dragHandles.length]=dh; 
			EventManager.addListener(dh, 'mousedown', this.mouseDownHandler, this);
		}
	},
	util:{
		browserIsIE: (!navigator.userAgent.match(/opera/gi) && navigator.userAgent.match(/msie/gi)),
		get:function(el){
			return typeof(el)=='string' ? document.getElementById(el) : el;
		},
		getX:function(el){
			if(!el)	return 0;
			if(el.getBoundingClientRect){
				x=el.getBoundingClientRect().left;
				x+=(document.documentElement && document.documentElement.scrollLeft)?document.documentElement.scrollLeft:document.body.scrollLeft;
				x-=2;
			}else{ 
				var x = el.offsetLeft;
				var parent=el.offsetParent;
				while (parent) {
					x += parent.offsetLeft;
					parent = parent.offsetParent;
				}
				parent=el.parentNode;
				while(parent && parent.tagName!='BODY'){
					x -= parent.scrollLeft;
					parent=parent.parentNode;
				}
			}
			return x;
		},
		getY:function(el){ 
			if(!el)	return 0;
			if(el.getBoundingClientRect){
				y=el.getBoundingClientRect().top;
				y+=(document.documentElement && document.documentElement.scrollTop)?document.documentElement.scrollTop:document.body.scrollTop;
				y-=2;
			}else{ 
				var y = el.offsetTop;
				var parent=el.offsetParent;
				while (parent) {
					y += parent.offsetTop;
					parent = parent.offsetParent;
				}
				parent=el.parentNode;
				while(parent && parent.tagName!='BODY'){
					y -= parent.scrollTop;
					parent=parent.parentNode;
				}
			}
			return y;
		},
		getXY:function(el){
			return [this.getX(el), this.getY(el)];
		},
		documentX:function(evt){ 
			return (this.browserIsIE ? evt.clientX + document.documentElement.scrollLeft : evt.pageX);
		},
		documentY:function(evt){	
			return (this.browserIsIE ? evt.clientY + document.documentElement.scrollTop : evt.pageY);
		},
		pointIsInsideElement:function(x, y, el){
			var top=this.getY(el);
			var left=this.getX(el);
			var bottom=top+el.offsetHeight;
			var right=left+el.offsetWidth;
			if(x>=left && x<right && y>=top && y<bottom)	return true;
			else return false;
		}
	}
	
}
function DragDropTarget(el, dragDropGroupId){
	if(el){
		if(typeof el == 'object'){
			if(el.id)	el=el.id
			else{	// generate id if it does not have one
				var id='';
				do{
					id=''+Math.round(Math.random()*10000);
				}while(document.getElementById(id));
				el.id=id; 
				el=id;
			}
		}
		this.init(el, dragDropGroupId);
	}
}
DragDropTarget.prototype={
	el:null,
	dragObjectIsOver:false,
	dragDropGroupId:'_defaultDragDropGroup',
	init:function(el, dragDropGroupId){
		this.el= this.util.get(el);
		dragDropGroupId = dragDropGroupId ? dragDropGroupId : '_defaultDragDropGroup';
		this.dragDropGroupId=dragDropGroupId;
		window.DragDropManagementObject.registerDDTarget(this, this.dragDropGroupId);
	},
	objectIsDragged:function(di){
		di.sender=this;
		if(this.util.pointIsInsideElement(di.x, di.y, this.el)){
			di.targetX=di.x-this.util.getX(this.el);	// X and Y coordinates relative to
			di.targetY=di.y-this.util.getY(this.el);	// the drop target element
			if(this.dragObjectIsOver){ 
				this.onDragOver(di);
			}else{
				this.dragObjectIsOver=true;
				this.onDragEnter(di);
			}
		}else{
			if(this.dragObjectIsOver){
				this.dragObjectIsOver=false;
				this.onDragOut(di);
			}
		}
	},
	objectIsDropped:function(di){
		di.sender=this;
		if(this.dragObjectIsOver)
			this.onDragDrop(di);
		this.dragObjectIsOver=false;
	},
	onDragOver:function(di){ },	
	onDragEnter:function(di){ },	
	onDragOut:function(di){ },	
	onDragDrop:function(di){ }
}
DragDropTarget.prototype.util=Draggable.prototype.util;
