function zwDragDrop()
{
	this.dragObj=null;

	this.idDrag=0;
	this.isDrag=false;
	this.offset={x: 0, y: 0};
	this.startPoint={x: 0, y: 0};
	this.dragSize={width: 0, height: 0}
	this.cancel=false;

	this.dummyDrg=null;
	this.dummyDrp=null;
	this.dropTarget=null;
	this.dropBefore=null;
	this.pageOffset=null;
	this.dropTargets;
	this.dropIsLast=false;
	this.forceChange=false;

	this.parentId=''; // Id de la zona contenedora del objeto drag.
	this.dropZone=''; // Id del contenedor de drop.	
	this.lock=''; // Bloqueo de movimiento
	this.transparency=6;
	this.targetClass=''; // Clase de los objetos sobre los que se podra hacer drop.
	this.dropMode=0; // 0 Normal drop, 1 Drop crea espacio, 2 Drop Objeto.
	this.minMoveDrag=10;
	this.maxX=undefined;
	this.maxY=undefined;
	this.minX=undefined;
	this.minY=undefined;
	this.desX=0;
	this.desY=0;
	
	// Callbacks
	this.dropCallBack=null;
	this.endCallBack=null;
	this.draggingCallback=null;
	
	// Handlers
	this.mouseMove=null;
	this.mouseUp=null;
	this.keyDown=null;
}
	
zwDragDrop.prototype = {
		
	startDrag:function(oDrg, iId, oEvt)
	{
		var oParent;				
		var oTarjet;
		var tmpThis;
		var oObj;
		var oParent;
		var iDifX=0;
		var iDifY=0;

		oEvt=(oEvt?oEvt:window.event);
		this.dragObj=oDrg;
		this.iId=iId;
		this.isDrag=true;
		this.cancel=false;
		this.unsetTarget();

		this.dummyDrg=null;
		this.dummyDrp=null;
		this.dropTarget=null;
		this.dropBefore=null;
		this.pageOffset=null;
		this.dropIsLast=false;
		this.forceChange=false;	

		this.dropTargets=new Array();
		oParent=document.getElementById(this.dropZone);
		if(!oParent) oParent=document.body;
		this.getDropTargets(oParent);
		
		//window.status=this.dropTargets.length+' targets.';
		
		if(this.dropMode!=2)
		{
			if(window.event)
			{
				this.startPoint.x=oEvt.clientX;
				this.startPoint.y=oEvt.clientY;
			} else {
				this.startPoint.x=oEvt.pageX;
				this.startPoint.y=oEvt.pageY;					
			}
	
			this.pageOffset=_getClientScrollOffset();
			this.offset=_getObjectPagePos(this.dragObj);	
			this.offset.x=this.startPoint.x-this.offset.x;
			this.offset.y=this.startPoint.y-this.offset.y;

		} else {
			oParent=document.getElementById('_zwcoloreditor_hue');

			oObj=(oEvt.srcElement?oEvt.srcElement:oEvt.target);
			while(oObj && oObj!=oParent)
			{
				value=parseInt(oObj.style.top);
				iDifY+=(isNaN(value)?0:value);

				value=parseInt(oObj.style.left);
				iDifX+=(isNaN(value)?0:value);

				oObj=(oObj.parentElement?oObj.parentElement:oObj.parentNode);
			}
						
			if(window.event)
			{
				if(this.lock=='' || this.lock=='H') this.dragObj.style.left=oEvt.offsetX+this.desX+iDifX;
				if(this.lock=='' || this.lock=='V') this.dragObj.style.top=oEvt.offsetY+this.desY+iDifY;
			} else {
				if(this.lock=='' || this.lock=='H') this.dragObj.style.left=oEvt.layerX+this.desX+iDifX;
				if(this.lock=='' || this.lock=='V') this.dragObj.style.top=oEvt.layerY+this.desY+iDifY;
			}
					
			this.startPoint.x=parseInt(this.dragObj.style.left)+this.desX;
			this.startPoint.y=parseInt(this.dragObj.style.top)+this.desY;
			this.offset.x=oEvt.screenX;
			this.offset.y=oEvt.screenY;

			if(this.draggingCallback)
				this.draggingCallback.call(this);
		}

		tmpThis=this;
		this.mouseMove=function (e) {_zwDragSetDrgDummyLocation(tmpThis, e)};
		this.mouseUp=function (e) {_zwDragEndDrag(tmpThis, e)};
		this.keyDown=function (e) {_zwDragKeyDown(tmpThis, e)};
		if(window.event)
		{
			document.body.attachEvent('onmousemove', this.mouseMove);
			document.body.attachEvent('onmouseup', this.mouseUp);
			document.body.attachEvent('onkeydown', this.keyDown);
		} else {
			document.body.addEventListener('mousemove', this.mouseMove, false);
			document.body.addEventListener('mouseup', this.mouseUp, false);
			document.body.addEventListener('keydown', this.keyDown, false);
		}
	},
	
	unsetTarget:function()
	{
		if(this.dropTarget)
		{
			switch(this.dropMode)
			{
				case 0:
					this.dropTarget.className=this.targetClass;
					this.dropTarget=null;
					break;
				case 1:
					break;	
			}
		}
	},
	
	getDropTargets:function(oParent)
	{
		var i;
		var oObj;
	
		for(i=0;i<oParent.childNodes.length;i++)
		{
			oObj=oParent.childNodes[i];
			if(oObj.className==this.targetClass)
			{
				this.dropTargets.push(oObj);	
			} else {
				this.getDropTargets(oObj);	
			}
		}
	},
	
	getDropTargetFromPoint:function(x, y)
	{
		var oTarget=null;
		var i, oObj, oRect;
		var bLast=false;
		var height;
		
		oPageOfs=_getClientScrollOffset();
		
		//Quitamos offset página.
		x+=oPageOfs.x;
		y+=oPageOfs.y;		
		
		oRect=_getObjRectangle(this.dragObj);
		height=oRect.bottom;
		
		for(i=0;i<this.dropTargets.length;i++)
		{
			oObj=this.dropTargets[i];
			oRect=_getObjRectangle(oObj);
			
			switch(this.dropMode)
			{
				case 0:
					if(x>=oRect.left && y>=oRect.top && x<=oRect.right && y<=oRect.bottom)
						oTarget=oObj;	
					break;
				case 1:
//				window.status='';
					// Açò Falla quan l'objecte és més petit
					//y>oRect.top && 
					if(x>=oRect.left && x<=oRect.right)
					{
						if((y>=oRect.top && y<=oRect.bottom))
						{
							oTarget=oObj;
							//y>oRect.top && 
							if(y>oRect.top+(oRect.height/2))//|| (y+height)>oRect.top+(oRect.height/2))
							{
								if(i<this.dropTargets.length-2)
								{
									oTarget=this.dropTargets[i+1];
									if(oTarget.parentElement!=oObj.parentElement)
									{
										bLast=true;
										oTarget=oObj;	
									}
								} else {
									bLast=true;
								}	
							}
						} else if(y<oRect.top && (y+height)>(oRect.top+oRect.height)) {
							if(i<this.dropTargets.length-1)
							{
								oTarget=this.dropTargets[i+1];
								if(oTarget.parentElement!=oObj.parentElement)
								{
									bLast=true;
									oTarget=oObj;
								}
							} else {
								bLast=true;	
								oTarget=oObj;
							}
						}
					}			
					break;
			}
			if(oTarget) break;
		}
		
		if(bLast!=this.dropIsLast)
		{
			this.dropIsLast=bLast;
			this.forceChange=true;
		}
		
		return oTarget;
	},
	
	removeDropDummy:function()
	{
		if(this.dummyDrp && this.dummyDrp.parentElement)
			this.dummyDrp.parentElement.removeChild(this.dummyDrp);
	},
	
	setParentId:function(sId)
	{
		var oDrop=document.getElementById(sId);
		
		this.parentId=sId;
		if(oDrop)
		{
			_addEventHandler(oDrop, 'ondragstart', this.stopPropagation);
			_addEventHandler(oDrop, 'onmousedown', this.stopPropagation);
			_addEventHandler(oDrop, 'onselectstart', this.stopPropagation);
		}
	},

	stopPropagation:function(oEvt)
	{
		oEvt=(window.event?window.event:oEvt);		
		if(window.event)
		{
			oEvt.cancelBubble=true;
		} else {
			oEvt.stopPropagation();
		}
		return false;
	},
	
	setTarget:function(oObj)
	{	
		if(oObj!=this.dropTarget || this.forceChange)
		{
			this.forceChange=false;
			this.unsetTarget();
			switch(this.dropMode)
			{
				case 0:
					this.dropTarget=oObj;
					if(this.dropTarget.className!='cmsdrop')
						this.targetClass=this.dropTarget.className;
					this.dropTarget.className='cmsdrop';
					break;
				case 1:
					this.removeDropDummy();
					this.dropTarget=oObj;

					this.dropBefore=this.dropTarget;
					if(this.dropIsLast) this.dropBefore=null;	
					this.dropTarget.parentElement.insertBefore(this.dummyDrp, this.dropBefore);
					break;
				case 2:
					
					break;
			}	
		}
	}
		
}
	
	
function _zwDragEndDrag(oSelf, oEvt)
{
	var oParent;
	
	if(oSelf.isDrag)
	{
		oEvt=(oEvt?oEvt:window.event);
		oSelf.idDrag=0;
		oSelf.isDrag=false;

		if(window.event)
		{
			document.body.detachEvent('onmousemove', oSelf.mouseMove );
			document.body.detachEvent('onmouseup', oSelf.mouseUp );
			document.body.detachEvent('onkeydown', oSelf.keyDown );
		} else {
			document.body.removeEventListener('mousemove', oSelf.mouseMove, false);
			document.body.removeEventListener('mouseup', oSelf.mouseUp, false);
			document.body.removeEventListener('onkeydown', oSelf.keyDown, false);
		}
		
		if(oSelf.dummyDrg && oSelf.dropMode!=2)
		{
			if(oSelf.parentId=='')
				oParent=document.body;						
			else
				oParent=document.getElementById(oSelf.parentId);
			oParent.removeChild(oSelf.dummyDrg);
		}
	
		if(oSelf.dropCallBack && oSelf.dropTarget && oSelf.dropTarget!=oSelf.dragObj && !oSelf.cancel)
			oSelf.dropCallBack.call(oSelf);
		
		if(oSelf.endCallBack)
			oSelf.endCallBack.call(oSelf);
	
		switch(oSelf.dropMode)
		{
			case 0:
				break;
			case 1:
				oSelf.dragObj.style.display='';
				oSelf.removeDropDummy();
				break;
			case 2:
				break;	
		}
	
		oSelf.dummyDrg=null;
		oSelf.dummyDrp=null;
		oSelf.dragObj=null;
		oSelf.unsetTarget();
		oSelf.dropTarget=null;
	}
}

	
function _zwDragKeyDown(oSelf, oEvt)
{
	oEvt=(oEvt?oEvt:window.event);
	if(oEvt.keyCode==27 && oSelf.isDrag)
	{
		oSelf.unsetTarget();
		oSelf.cancel=true;
		_zwDragEndDrag(oSelf, oEvt);
	}
}

function _zwDragSetDrgDummyLocation(oSelf, oEvt)
{
	var oObj;
	var iDifX;
	var iDifY;
	var iVal;
	var oOver=null;
	var oPageOfs;
	var oRect;

	oEvt=(oEvt?oEvt:window.event);
	if(oSelf.dummyDrg)
	{
		//oSelf.unsetTarget();
		if(oSelf.dropMode==2)
		{
			iDifX=parseInt(oSelf.dummyDrg.style.left);
			iDifY=parseInt(oSelf.dummyDrg.style.top);
			
	  		if(oSelf.lock=='' || oSelf.lock=='H') iDifX=oSelf.startPoint.x+(oEvt.screenX-oSelf.offset.x)-oSelf.desX;
			if(oSelf.lock=='' || oSelf.lock=='V') iDifY=oSelf.startPoint.y+(oEvt.screenY-oSelf.offset.y)-oSelf.desY;

	  		//window.status=oSelf.startPoint.y+' + '+(oEvt.screenY-oSelf.offset.y)+' = '+iDifY;
			
			if(oSelf.maxY!=undefined && iDifY>oSelf.maxY+oSelf.desY-1) iDifY=oSelf.maxY+oSelf.desY-1;
			if(oSelf.minY!=undefined && iDifY<oSelf.minY+oSelf.desY) iDifY=oSelf.minY+oSelf.desY;

			if(oSelf.maxX!=undefined && iDifX>oSelf.maxX+oSelf.desX-1) iDifX=oSelf.maxX+oSelf.desX-1;
			if(oSelf.minX!=undefined && iDifX<oSelf.minX+oSelf.desX) iDifX=oSelf.minX+oSelf.desX;
			
			oSelf.dummyDrg.style.left=iDifX;
			oSelf.dummyDrg.style.top=iDifY;
			
		} else {
			oPageOfs=_getClientScrollOffset();
		  	if(window.event)
		  	{
		  		if(oSelf.lock=='' || oSelf.lock=='H') oSelf.dummyDrg.style.left=oEvt.clientX-oSelf.offset.x+(oSelf.dropMode!=2?(oPageOfs.x-oSelf.pageOffset.x):0);
				if(oSelf.lock=='' || oSelf.lock=='V') oSelf.dummyDrg.style.top=oEvt.clientY-oSelf.offset.y+(oSelf.dropMode!=2?(oPageOfs.y-oSelf.pageOffset.y):0);
			} else {
				if(oSelf.lock=='' || oSelf.lock=='H') oSelf.dummyDrg.style.left=oEvt.pageX-oSelf.offset.x;
				if(oSelf.lock=='' || oSelf.lock=='V') oSelf.dummyDrg.style.top=oEvt.pageY-oSelf.offset.y;
			}

			oOver=oSelf.getDropTargetFromPoint(oEvt.clientX, oEvt.clientY);
		
			if(oOver) // && oOver.className==oSelf.targetClass
			{
				oSelf.setTarget(oOver);
				//window.status=oOver.id;
			} else {
				oSelf.unsetTarget();
			}

			if(window.event)
			{
				if(oEvt.clientY<=30 && oPageOfs.y>0) document.body.scrollTop-=(oPageOfs.y<15?oPageOfs.y:15);
				if(oEvt.clientX<=30 && oPageOfs.x>0) document.body.scrollLeft-=(oPageOfs.x<15?oPageOfs.x:15);
				if(oEvt.clientY+oSelf.dragSize.height>=document.body.clientHeight && oEvt.clientY+15<document.body.scrollHeight) document.body.scrollTop+=(oEvt.clientY+15>document.body.scrollHeight?document.body.scrollHeight-(oEvt.clientY+15):15);
				if(oEvt.clientX+oSelf.dragSize.width>=document.body.clientWidth && oEvt.clientX+15<document.body.scrollWidth) document.body.scrollLeft+=(oEvt.clientX+15>document.body.scrollWidth?document.body.scrollWidth-(oEvt.clientX+15):15);
			} else {
				iDifY=oEvt.pageY-oPageOfs.y;
				iDifX=oEvt.pageX-oPageOfs.x;
	
				if(iDifY<=30 && oPageOfs.y>0) window.scrollBy(0, oPageOfs.y<15?-oPageOfs.y:-15);
				if(iDifX<=30 && oPageOfs.x>0) window.scrollBy(oPageOfs.x<15?-oPageOfs.x:-15, 0);
				if(iDifY+oSelf.dragSize.height>=window.innerHeight) window.scrollBy(0, 15);
				if(iDifX+oSelf.dragSize.height>=window.innerWidth) window.scrollBy(15, 0);
			}
		}

		if(oSelf.draggingCallback)
			oSelf.draggingCallback.call(oSelf);	
			
	} else {
		if(oSelf.dragObj)
		{
			if(window.event)
			{
				iDifX=oEvt.clientX-oSelf.startPoint.x;
				iDifY=oEvt.clientY-oSelf.startPoint.y;
			} else {
				iDifX=oEvt.pageX-oSelf.startPoint.x;
				iDifY=oEvt.pageY-oSelf.startPoint.y;
			}
				
			if(oSelf.dropMode==2 || ((oSelf.lock=='' || oSelf.lock=='H') && Math.abs(iDifX)>oSelf.minMoveDrag) || ((oSelf.lock=='' || oSelf.lock=='V') && Math.abs(iDifY)>oSelf.minMoveDrag))
			{	
				if(oSelf.dropMode==2)
				{
					oSelf.dummyDrg=oSelf.dragObj;
					//oSelf.dummyDrg.style.left=iDifX;
					//oSelf.dummyDrg.style.top=iDifY;
				} else {
					oSelf.dummyDrg=oSelf.dragObj.cloneNode(true);
					oRect=_getObjRectangle(oSelf.dragObj);
					oSelf.dummyDrg.style.width=oRect.width;
					oSelf.dummyDrg.style.height=oRect.height;
					oSelf.dummyDrg.style.left=oRect.left;
					oSelf.dummyDrg.style.top=oRect.top;
					oSelf.dummyDrg.style.zIndex=2000;
					oSelf.dragSize.width=oRect.width;
					oSelf.dragSize.height=oRect.height;
					oSelf.dummyDrg.style.border='1px solid red';
	
					oSelf.dummyDrg.style.backgroundColor='#FFFFFF';
					oSelf.dummyDrg.style.position='absolute';

					if(window.event)
						oSelf.dummyDrg.style.filter='progid:DXImageTransform.Microsoft.Alpha( Style=0, Opacity='+oSelf.transparency+'0);';
					else
						oSelf.dummyDrg.style.opacity='.'+oSelf.transparency;
				}


				if(oSelf.dropMode==1)
				{
					oSelf.dummyDrp=document.createElement('DIV');
					oSelf.dummyDrp.style.width=oRect.width;   
					oSelf.dummyDrp.style.height=oRect.height; 
					oSelf.dummyDrp.style.border='1px dotted #888888';
					oSelf.dummyDrp.style.margin=oSelf.dragObj.style.margin;
					//oSelf.dummyDrp.style.display='block';
					//oSelf.dummyDrp.className='cmsthumb';
					oSelf.dragObj.style.display='none';

				}

				_zwDragSetDrgDummyLocation(oSelf, oEvt)
				oParent=document.getElementById(oSelf.parentId);
				oParent.appendChild(oSelf.dummyDrg);
				if(oSelf.dropMode==1) oSelf.setTarget(oSelf.dragObj);
			}
		}
	}
}

function _getObjectPagePos(oObj)
{
	var coords = {x: 0, y: 0};
	var sPos='';
	var lastX=0;
	var lastY=0;
	
	if(document.layers)
	{
		coords.x=oObj.x;
		coords.y=oObj.y;	
	} else {
		while (oObj)
		{
			if(oObj.style.position!='static' || oObj.style.position!='')
			{
				coords.x+=oObj.offsetLeft;
				coords.y+=oObj.offsetTop;
				sPos+=oObj.tagName+' - >'+oObj.style.position+'<: ('+oObj.offsetLeft+', '+oObj.offsetTop+')\n';
			}
		
			try 
			{
				oObj = oObj.offsetParent;
			} catch(e) { oObj=false; }
		}
	}
	//sPos+='\n\nLast: '+lastX+', '+lastY+'\n';
	//alert(sPos);

	return coords;
}

function _getObjectSize(oObj)
{
	var size={width: 0, height: 0};
	
	/*if(window.event)
	{ 
		size.width=oObj.style.pixelWidth;
		size.height=oObj.style.pixelHeight;
	} else {
		size.width=oObj.offsetWidth;
		size.height=oObj.offsetHeight;
	}*/
	size.width=oObj.offsetWidth;
	size.height=oObj.offsetHeight;
	
	return size;
}

function _getEventOffsets(evt)
{
  	var target = evt.target;

	if(window.event)
	{
		var offsets={
	    		offsetX: evt.offsetX,
	    		offsetY: evt.offsetY
	  	};
	} else {
	  	if(target.nodeType!=target.ELEMENT_NODE) target=target.parentNode;

		var pageCoords=_getObjectPagePos(target);
	  	var eventCoords={
	    		x: window.pageXOffset + evt.clientX,
	    		y: window.pageYOffset + evt.clientY
	  	};

		var offsets={
	    		offsetX: eventCoords.x - pageCoords.x,
	    		offsetY: eventCoords.y - pageCoords.y
	  	};
	}	
	return offsets;
}

function _getObjRectangle(oObj)
{
  	var iRight, iBottom;
  	
  	size=_getObjectSize(oObj);
  	coords=_getObjectPagePos(oObj);
 	
 	iRight=coords.x+size.width;
 	iBottom=coords.y+size.height;
 	
  	return {top: coords.y, left: coords.x, width: size.width, height: size.height, right: iRight, bottom: iBottom};
}

function _getClientScrollOffset()
{
	var x,y;

	if(window['pageYOffset']!=undefined)
	{
		// all but Explorer
		x = window.pageXOffset;
		y = window.pageYOffset;
	} else if (document.body) {
		// all other Explorers
		x = document.body.scrollLeft;
		y = document.body.scrollTop;
	}
	return {x: x, y: y};
}
