/* COPYRIGHT (C) Paul Davis 2010. All rights reserved. */

function Dragable () {
 
	this.mousex = null;
	this.offsetx = 0;
	this.mousey = null;
	this.offsety = 0;
	this.elm = null;
	this.ghost = null;
	this.container = null;
	this.things = new Array();
	this.dropping = true;
	this.command = null;
	this.constrain = "y";
	this.dragged = false;
	this.hilite = "5px dotted gray";
	
	//------------------------------------------------------------------------------------------------------
	
	this.drag = function (event) {
		if (this.ghost) {
			this.dragged = true;
			this.mouse(event);
			var sx = document.body.scrollLeft  + this.container.scrollLeft;
			var sy = document.body.scrollTop + this.container.scrollTop;
			if (this.constrain == "y")
				this.ghost.style.top  = (this.mousey - this.offsety - sy) + 'px';
			else if (this.constrain == "x")
				this.ghost.style.left = (this.mousex - this.offsetx - sx) + 'px';
			else {
				this.ghost.style.top  = (this.mousey - this.offsety - sy) + 'px';
				this.ghost.style.left = (this.mousex - this.offsetx - sx) + 'px';
			}
			// hilite position to drop
			for(var i = 0; i < this.things.length; i++) {
				var target  = this.things[i];
				var over = this.over(target);
				if (over) {
					if (this.dropping && !isInId(target.id, this.elm.id)) {
						switch (over) {
							case "above":
								target.style.borderTop = this.hilite;
								target.style.borderBottom = "none";
								break;
							case "below":
								target.style.borderTop = "none";
								target.style.borderBottom = this.hilite;
								break;
							case "left":
								target.style.borderLeft = this.hilite;
								target.style.borderRight = "none";
								break;
							case "right":
								target.style.borderLeft = "none";
								target.style.borderRight = this.hilite;
								break;
						}
					}
				} else
					target.style.border = "none";
			}
		}
		return false; // in IE this prevents cascading of events, thus text selection is disabled
	};
	
	//-----------------------------------------------------------------------------------------------------
	
	this.drop = function (event) {
		document.onmousemove = null;
		document.onmouseup = null;
		document.onmousedown = null;
		if (this.ghost) {
			document.body.removeChild(this.ghost);
			this.ghost = null;
		}
		if (this.dragged) {
			this.mouse(event);
			for(var i = 0; i < this.things.length; i++) {
				var target = this.things[i];
				var over = this.over(target);
				if (over) {
					if (this.dropping && !isInId(target.id, this.elm.id)) {
						switch (over) {
							case "above":
							case "left":
								this.container.insertBefore(this.elm, target);
								break;
							case "below": 
							case "right":
								this.container.insertBefore(this.elm, target.nextSibling);
								break;
						}
					}
				}
				target.style.border = "none";
			}
		}
		if (this.command)
			eval(this.command);
		this.dragged = false;
	};
			
	//--------------------------------------------------------------------------------------------------------
	
	this.grab = function (event, elm, containerid, classname, constrain, jsexecute, dropit, hilite) {
		if (typeof(elm) == "string")
			elm = document.getElementById(elm);
		if (!elm)
			return false;
		this.elm = elm;
		if (!event) 
			event = window.event; // works on IE, but not NS (we rely on NS passing us the event)
		this.container = document.getElementById(containerid);
		this.mouse(event);
		this.offsetx = this.mousex - findPos(this.elm, "x") - document.body.scrollLeft;
		this.offsety = this.mousey - findPos(this.elm, "y") - document.body.scrollTop;
		if (!this.container)
			return false;
		this.constrain = (constrain) ? constrain : "none";
		this.command = (jsexecute) ? jsexecute : null;
		this.makeGhost(elm);
		this.dragged = false;
		document.onmousedown = function () { return false; }; // prevents cascading of events, disabling text selection
		document.onmousemove = dragdragit;
		document.onmouseup   = dragdropit;
		if (dropit != null)
			this.dropping = dropit;
		// get things to sort etc	
		var tagtype = this.elm.tagName.toLowerCase();
		var descendants = this.container.getElementsByTagName(tagtype);
		if (!classname) { // use valid children (no whitespace nodes) of container
			var children = this.container.childNodes;
			for(var i = 0; i < children.length; i++) {
				if (children[i].nodeType == 1) {
					this.things.push(children[i]);
				}
			}
		} else { // allows hierarchical
			var re = new RegExp("(^| )" + classname + "($| )");
			for(var i = 0; i < descendants.length; i++) {
				if (descendants[i].className.match(re)) {
					this.things.push(descendants[i]);
				}
			}
		}
		if (hilite)
			this.hilite = hilite;
	};
	
	//--------------------------------------------------------------------------------------------------------
	
	this.makeGhost = function (elm) {
		this.ghost = elm.cloneNode(true);
		this.ghost.id = 'ghost' + this.container.id;
		this.ghost.style.position = "absolute";
		this.ghost.style.float = "none";
		this.ghost.onmousedown = null;
		this.ghost.onmouseover = null;
		var sx = this.container.scrollLeft;
		var sy = this.container.scrollTop;
		this.ghost.style.top  = (findPos(elm, "y") - sy) + 'px';
		this.ghost.style.left = (findPos(elm, "x") - sx) + 'px';
		this.ghost.style.opacity = 0.6;
		document.body.appendChild(this.ghost);
	};
			
	//--------------------------------------------------------------------------------------------------------
	
	this.mouse = function (event) {
		if (!event) 
			event = window.event; // works on IE, but not NS (we rely on NS passing us the event)
		if (event) { 
			if (event.pageX || event.pageY) { // this doesn't work on IE6!! (works on FF,Moz,Opera7)
				this.mousex = event.pageX;
				this.mousey = event.pageY;
			} else if (event.clientX || event.clientY) { // works on IE6,FF,Moz,Opera7
				this.mousex = event.clientX;
				this.mousey = event.clientY;
			}  
		}
	};
	
	//-----------------------------------------------------------------------------------------------------
	
	this.over = function (target) {
		var sx = this.container.scrollLeft;
		var sy = this.container.scrollTop;
		if (this.constrain == "y") {
			var targety = findPos(target, "y") - sy;
			var targetheight = Math.max(target.clientHeight, target.offsetHeight);
			if ((this.mousey > targety) && (this.mousey < (targety + (targetheight / 2))))
				return "above";
			else if ((this.mousey >= (targety + (targetheight / 2))) && (this.mousey < (targety + targetheight)))
				return "below";
		} else if (this.constrain == "x") {
			var targetx = findPos(target, "x") - sx;
			var targetwidth = Math.max(target.clientWidth, target.offsetWidth);
			if ((this.mousex > targetx) && (this.mousex < (targetx + (targetwidth / 2))))
				return "left";
			else if ((this.mousex >= (targetx + (targetwidth / 2))) && (this.mousex < (targetx + targetwidth)))
				return "right";
		} else {
			var targety = findPos(target, "y") - sy;
			var targetheight = Math.max(target.clientHeight, target.offsetHeight);
			var targetx = findPos(target, "x") - sx;
			var targetwidth = Math.max(target.clientWidth, target.offsetWidth);
			ok = ((this.mousey > targety) && (this.mousey < (targety + targetheight)));
			ok = ok && ((this.mousex > targetx) && (this.mousex < (targetx + targetwidth)));
			if (ok) {
				if ((this.mousex > targetx) && (this.mousex < (targetx + (targetwidth / 2))))
					return "left";
				else if ((this.mousex >= (targetx + (targetwidth / 2))) && (this.mousex < (targetx + targetwidth)))
					return "right";
			}
		}
		return "";
	};
	
	//--------------------------------------------------------------------------------------------------------
	
}

//------------------------------------------------------------------------------------------------------------

var drag = new Dragable();

function dragdragit (e) {
	drag.drag(e);
}

function dragdropit (evt) {
	drag.drop(evt);
}

