// wDRAG. Thin Drag&Drop Framework
// v2.0 Cedric Savarese 
// April. 2006

// Change Log
// v2.0 (04/10/2006) -  rewritten

 if(typeof helpers == "undefined" && wHELPERS) {
	var helpers = new wHELPERS();
 }
 if (!helpers) {
	alert('Sorry, whelpers.js is not correctly loaded. wDRAG is not active.');
  }
  
 function wDrag() { 
	var self     = this; 
	
	this.create = function(id) {
		this.rootId                = id;
		this.root                  = document.getElementById(id);		
		this.options               = arguments[1] || {};
		this.trashId 			   = this.options.trashId      || "dragTrash";	
		this.classNameHandle       = this.options.handleClass  || "dragHandle";	
		this.classNameDragged      = this.options.draggedClass || "dragged";	
		this.classNameTrashWarning = this.options.warningClass || "warning";		
		this.draggableElements     = this.options.draggable    || ["li"];
		this.containerElements     = this.options.containers   || ["ul"];		
		this.onUpdate              = this.options.onUpdate; 
		this.isReady               = false;
		this.isActive              = false;		
		this.element 	    	   = null;
		this.ghostElement 	       = null;
		this.targets			   = [];
		
		if(!this.root) { 
			return false;
		}
		
		var li = this.root.getElementsByTagName('a');
		var lg = li.length;
		for(var i=0;i<lg; i++) {
			if(helpers.hasClass(li[i],this.classNameHandle)) {		
				this.targets.push(li[i]);			
			}
		}	
		var trash = document.getElementById(this.trashId);
		if(trash) {		
			this.targets.push(trash);			
		}

		helpers.addEvent(this.root,'mousedown', this.start);
	}

	this.clear = function() {
		//helpers.removeEvent(self.root,'mousedown', self.start);  //prblm with IE6
	}
	
	this.start = function(e) {		
		if(self.isActive) {
			// wFORMS.debug('cleaning drag..');	
			self.stop();
		}		
		if(!e) e = window.event;
		if(self.isLeftClick(e)) {
			var n = helpers.getSourceElement(e);
			self.element = self.getDraggableElement(n);							
			if(self.element) {		
				// wFORMS.debug('drag ready');		
				self.isReady = true;
				self.isActiveTimout = setTimeout( function() { 
					// wFORMS.debug('drag start');										
					self.ghostElement = self.getGhostElement(self.element); 		
					self.element.style.visibility = 'hidden';					
					self.isActive = true; 
					self.ghostElement.className += self.classNameDragged;	
					self.root.style.cursor = 'move';	
				}, 400);
				//self.insertType	  = "before";			
				self.ghostOffsetLeft = helpers.getLeft(self.element) - self.pointerX(e);
				self.ghostOffsetTop  = helpers.getTop(self.element) - self.pointerY(e);
				helpers.addEvent(self.root,'mouseup', self.stop);
				helpers.addEvent(document.body,'selectstart', self.nothing);
				helpers.addEvent(document.body,'drag', self.nothing);				
				helpers.addEvent(self.root,'mousemove', self.move);
				helpers.addEvent(self.root,'keypress', self.cancelDrag);
				helpers.stopPropagation(e);
				return helpers.preventEvent(e);				
			}
		}	
		// wFORMS.debug('click');
		return true;		
	}
	
	this.stop = function(e) {
		
		if(self.isReady) {
			clearTimeout(self.isActiveTimout);
			if(!self.isActive) // wFORMS.debug('drag canceled');
			self.isReady = false;
			helpers.removeEvent(self.root,'mousemove', self.move);
			helpers.removeEvent(self.root,'keypress', self.cancelDrag);
			helpers.removeEvent(self.root,'mouseup', self.stop);
			helpers.removeEvent(document.body,'selectstart', self.nothing);
			helpers.removeEvent(document.body,'drag', self.nothing);			
		}
		if(self.isActive) {
			// wFORMS.debug('drag completed');
			self.isActive = false;
			self.ghostElement.parentNode.removeChild(self.ghostElement);	
			self.element.style.visibility = 'visible';	
			self.root.style.cursor = 'auto';
			/*
			if(self.isInTrash(self.element)) {
				if(!window.confirm("Do you want to empty your trash now?")) {
					helpers.stopPropagation(e);
					helpers.preventEvent(e); 
					return;	
				}
			} */
			self.onUpdate(self.root, self.element);			
			helpers.stopPropagation(e);
			return helpers.preventEvent(e); 
		}
		
	}
	
	this.cancelDrag = function(e) { 
		self.stop(e);
	}
	
	this.move = function(e) {
		if(self.isActive) {			
			var mouseX = self.pointerX(e);
			var mouseY = self.pointerY(e);
			self.ghostElement.style.left = (mouseX+ self.ghostOffsetLeft).toString()+"px";
			self.ghostElement.style.top  = (mouseY+ self.ghostOffsetTop).toString()+"px";
			
			var dragO  = self.getDimensions(self.ghostElement);
			var dragX  = dragO.x;
			var dragY  = dragO.y;
			var dragXW = dragO.x + dragO.w;
			var dragYH = dragO.y + dragO.h;
			
			for(var i = self.targets.length-1; i >= 0; i--) {
				var t = self.targets[i];
				
				var p = t.parentNode;
				while(p && p != self.element)
					p = p.parentNode;
				if (p) continue;
				
				var o = self.getDimensions(t);
				var x = o.x;
				var y = o.y;
				var w = o.w;
				var h = o.h;		
				//dragX > x && dragXW < (x+w)
				if((dragY > y && dragY < (y+h)) || 
				   (dragYH > y && dragYH < (y+h))) {
					// dragged over					
					if(self.isTrash(t)) {
						t.className += ' ' + self.classNameTrashWarning;
						var over = t.getElementsByTagName('ul')[0];						
						over.appendChild(self.element);
					} else {
						var trash = document.getElementById(self.trashId);
						if(trash && helpers.hasClass(trash, self.classNameTrashWarning) ) {		
							trash.className = trash.className.replace(self.classNameTrashWarning,'');			
						}
						var over = self.getDraggableElement(t);
						if(self.element.nextSibling != over) {											
							try {
								var container = self.getContainerElement(over);
								if(self.isContainerEmpty(container)) {
									container.appendChild(self.element);								
								} else {															
									over.parentNode.insertBefore(self.element, over);	
								}
							} catch(x) {
								// wFORMS.debug(over.id + ' ' + x.message);	
							}
							return;
						} 				
					}
				}
			}
		}
	}

	this.getDraggableElement = function(n) {
		while(n && n.tagName) {
			if(n.id == self.rootId) 
				return null;
			if(self.isDraggable(n))
				return n;
			n = n.parentNode;
		}
		return null;
	}

	this.isDraggable = function(n) {
		if(!n) return false;
		if(n.nodeType==3) n = n.parentNode;
		for(var i=0;i<self.draggableElements.length;i++) {
			if(n.tagName.toLowerCase() == self.draggableElements[i] && !self.isTrash(n) )
				return true;
		}
		return false;
	}

	this.getContainerElement  = function(n) {
		if(!n || n.nodeType!=1) return false;
		for(var j=0;j<n.childNodes.length;j++) {
			cn = n.childNodes[j];
			if(self.isContainer(cn)) return cn;
		}
		return null;
	}

	this.isContainer = function(n) {
		if(!n || n.nodeType!=1) return false;
		for(var j=0;j<self.containerElements.length;j++) {
			if(n.tagName.toLowerCase() == self.containerElements[j] && !self.isTrash(n) )
				return true;	
		}
		return false;
	}
	
	this.isContainerEmpty = function(n) {
		if(!n || n.nodeType!=1) return false;
		for(var j=0;j<n.childNodes.length;j++) {
			if(self.isDraggable(n.childNodes[j]) && n.childNodes[j] != self.element )
				return false;
		}
		return true;
	}
	
	this.isTrash = function(n) {
		return (n && n.id && n.id==self.trashId);
	}
	this.isInTrash = function(n) {
		n = n.parentNode;
		while(n) {
			if(self.isTrash(n)) {
				return true;
			}
			n = n.parentNode;
		}
		return false;
	}

	this.getDroppedOnElement = function(n) {
		while(n && n.tagName) {
			if(n.id == self.rootId) 
				return null;
			if(self.isDraggable(n))// not implemented, all draggable elements can be dropped on
				return n;
			if(self.isTrash(n)) 
				return n;
			n = n.parentNode;
		}
		return null;
	}
	
	this.getGhostElement = function(n) {
		if(self.ghostElement && self.ghostElement.parentNode) 
			self.ghostElement.parentNode.removeChild(self.ghostElement);
		
		var ghostElement = n.cloneNode(true);
		ghostElement.style.width = n.offsetWidth + 'px'; // forces width in IE
		ghostElement.style.position = "absolute";
		ghostElement.style.left = helpers.getLeft(n)+ "px";
		ghostElement.style.top = helpers.getTop(n) + "px";		
		ghostElement = self.root.insertBefore(ghostElement, self.root.firstChild);
		return ghostElement;
	}
	
	this.nothing = function(e) {
		if(!e) e = window.event;
		helpers.preventEvent(e);
		helpers.stopPropagation(e);		
		return false; 
	}
	
	this.getDimensions = function(n) {		
		var obj = {
		 	x: helpers.getLeft(n),
			w: n.offsetWidth,
			y: helpers.getTop(n),
			h: n.offsetHeight
		}		
		return obj;
	}
	
	this.isLeftClick = function(e) {
	    return ((e.which && e.which == 1) || (e.button && e.button == 1));
	}
	this.pointerX = function(e) {	
		if(!e) e = window.event;
		return e.pageX || (e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft));
	}
	this.pointerY = function(e) {
		if(!e) e = window.event;
		return e.pageY || (e.clientY + (document.documentElement.scrollTop || document.body.scrollTop));
	}
 }