
function DragControl() {
	this.selection = null; // element being dragged
	this.zIndex = 0; // use to put drag item on top
	this.x = 0; // current left/x position
	this.y = 0; // current top/y position
	this.errorCount = 0;
}
DragControl.prototype = {
	pickup : function(event, element) {
		if (event.button < 2) { // only pickup for left mouse button... 0 in opera, firefox, 1 in IE
			this.selection = element;
			if (self.pageYOffset) { // all except Explorer
                this.x = event.clientX + self.pageXOffset;
                this.y = event.clientY + self.pageYOffset;
            } else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict
                this.x = event.clientX + document.documentElement.scrollLeft;
                this.y = event.clientY + document.documentElement.scrollTop;
            } else if (document.body) { // all other Explorers
	            this.x = event.clientX + document.body.scrollLeft;
	            this.y = event.clientY + document.body.scrollTop;
            } else {
	            this.x = event.clientX;
	            this.y = event.clientY;
            }
			element.style.zIndex = ++this.zIndex; // put on top
			element.drag_panel.pickup(element); // tell the panel about the pickup
			event.cancelBubble = true; // TODO: needed, for what???? just for IE????
		}
	},
	drag : function(event) {
		if (this.selection == null)
			return true;
		// move to the new position
		var cursorX;
		var cursorY;
		if (self.pageYOffset) { // all except Explorer
            cursorX = event.clientX + self.pageXOffset;
            cursorY = event.clientY + self.pageYOffset;
        } else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict
            cursorX = event.clientX + document.documentElement.scrollLeft;
            cursorY = event.clientY + document.documentElement.scrollTop;
        } else if (document.body) { // all other Explorers
            cursorX = event.clientX + document.body.scrollLeft;
            cursorY = event.clientY + document.body.scrollTop;
        } else {
            cursorX = event.clientX;
            cursorY = event.clientY;
        }
		var newX = parseInt(this.selection.style.left, 10) + cursorX - this.x;
		var newY = parseInt(this.selection.style.top, 10) + cursorY - this.y;
		// make sure it is inside the boundary
		if (cursorX > this.selection.drag_panel.minX && cursorX < this.selection.drag_panel.maxX && cursorY > this.selection.drag_panel.minY && cursorY < this.selection.drag_panel.maxY) {
			this.selection.style.left = newX + 'px';
			this.selection.style.top = newY + 'px';
			// store the new position
			this.x = cursorX;
			this.y = cursorY;
			this.selection.drag_panel.drag(newX, newY); // tell the panel about the drag
		}
	},
	drop : function() {
		if (this.selection == null)
			return true;
		this.selection.drag_panel.drop(this.selection); // tell the panel about the drop
		this.selection = null;
	}
}
function DragPanel() {
	this.targets = new Array();
	this.homes = new Array();
	this.xfuzz = 45;
	this.yfuzz = 10;
	this.minX = 0;
	this.maxX = 0;
	this.minY = 0;
	this.maxY = 0;
}
DragPanel.prototype = {
	init : function(boundary) {
		var i, j, curEl, x, y;
		var cells = boundary.getElementsByTagName("td");
		for (i = 0; i < cells.length; i++) {
			if (cells[i].className == "target") { // add targets
				curEl = cells[i];
				j = parseInt(curEl.getAttribute("position"), 10) - 1;
				this.targets[j] = curEl;
				this.targets[j].element = null; // using two way references between a target and an element
				x = y = 0;
				while (curEl != null) {
					x += curEl.offsetLeft;
					y += curEl.offsetTop;
					curEl = curEl.offsetParent;
				}

		        var zeroElement = document.getElementById("origin");
		        var zeroX = 0;
		        var zeroY = 0;
		        while (zeroElement != null) {
			        zeroX += zeroElement.offsetLeft;
			        zeroY += zeroElement.offsetTop;
			        zeroElement = zeroElement.offsetParent;
		        }
		        x = x - zeroX;
		        y = y - zeroY;

				this.targets[j].x = x;
				this.targets[j].x0 = x - this.xfuzz;
				this.targets[j].x1 = x + this.xfuzz;
				this.targets[j].y = y;
				this.targets[j].y0 = y - this.yfuzz;
				this.targets[j].y1 = y + this.yfuzz;
			} else if (cells[i].className == "home") { // add homes
				curEl = cells[i];
				j = parseInt(curEl.getAttribute("position"), 10) - 1;
				this.homes[j] = curEl;
				x = y = 0;
				while (curEl != null) {
					x += curEl.offsetLeft;
					y += curEl.offsetTop;
					curEl = curEl.offsetParent;
				}

		        var zeroElement = document.getElementById("origin");
		        var zeroX = 0;
		        var zeroY = 0;
		        while (zeroElement != null) {
			        zeroX += zeroElement.offsetLeft;
			        zeroY += zeroElement.offsetTop;
			        zeroElement = zeroElement.offsetParent;
		        }
		        x = x - zeroX;
		        y = y - zeroY;

				this.homes[j].x = x;
				this.homes[j].y = y;
			}
		}
		// set the outer limits for dragging
		curEl = boundary;
		while (curEl != null) {
			this.minX += curEl.offsetLeft;
			this.minY += curEl.offsetTop;
			curEl = curEl.offsetParent;
		}
		this.maxX = this.minX + boundary.offsetWidth;
		this.maxY = this.minY + boundary.offsetHeight;
	},
	pickup : function(element) {
		// if the element is on a target, clear the target of the element
		if (element.target != null)
			element.target.element = null;
		// now re-set the target reference on the element
		element.target = null;
	},
	drag : function(x, y) {
		// highlight the target being dragged over
		for (var i = 0; i < this.targets.length; i++) {
			if (x >= this.targets[i].x0 && x <= this.targets[i].x1 && y >= this.targets[i].y0 && y <= this.targets[i].y1)
				this.targets[i].style.backgroundColor = "#ffffff";
			else
				this.targets[i].style.backgroundColor = "";
		}
	},
	drop : function(element) {
		var droppedOnGrid = false
		var x = parseInt(element.style.left, 10);
		var y = parseInt(element.style.top, 10);
		for (var i = 0; i < this.targets.length; i++) {
			if (x >= this.targets[i].x0 && x <= this.targets[i].x1 && y >= this.targets[i].y0 && y <= this.targets[i].y1) {
				droppedOnGrid = true;
				this.targets[i].style.backgroundColor = "";
				this.attachToTarget(element, i);
				break;
			}
		}
		if (!droppedOnGrid)
			this.sendHome(element)
	},
	attachToTarget : function(element, i) {
		element.target = this.targets[i];
		// if another element is on this target then send it home
		if (this.targets[i].element != null)
			this.sendHome(this.targets[i].element);
		this.targets[i].element = element;
		// center the element on the target
		var tempX = this.targets[i].x + (this.targets[i].offsetWidth/2) - (element.offsetWidth/2);
		var tempY = this.targets[i].y + (this.targets[i].offsetHeight/2) - (element.offsetHeight/2);
		element.style.left = tempX + 'px';
		element.style.top = tempY + 'px';
	},
	sendHome : function(element) {
		// reset the target and element references
		if (element.target != null && element.target.element != null)
			element.target.element = null;
		element.target = null;
		var homeX = this.homes[parseInt(element.getAttribute("home"), 10) - 1].x;
		var homeY = this.homes[parseInt(element.getAttribute("home"), 10) - 1].y;
		element.style.left = homeX + 'px';
		element.style.top = homeY + 'px';
	},
	getElementOnTarget : function(position) {
		if (this.targets[position - 1].element != null)
			return this.targets[position - 1].element.getAttribute("element");
		else
			return "";
	},
	clearTargets : function() {
		for (var i = 0; i < this.targets.length; i++) {
			if (this.targets[i].element != null)
				this.sendHome(this.targets[i].element);
		}
	},
	calculateLimits : function(boundary) {
	    this.minX = 0;
	    this.maxX = 0;
	    this.minY = 0;
	    this.maxY = 0;
		var _current = boundary;
		while (_current != null) {
			this.minX += _current.offsetLeft;
			this.minY += _current.offsetTop;
			_current = _current.offsetParent;
		}
		this.maxX = this.minX + boundary.offsetWidth;
		this.maxY = this.minY + boundary.offsetHeight;
	}
}

function setupElement(element, dp) {
	element.drag_panel = dp;
	var index = parseInt(element.getAttribute('target'), 10) - 1;
	if (index >= 0 && index < dp.targets.length)
		dp.attachToTarget(element, index);
	else
		dp.sendHome(element);
}

function setDNF(num) {
	for (var i = 1; document.getElementById('cb' + i) != null; i++)
		if (i != num)
			document.getElementById('cb' + i).checked = i > num;
}

var dc;
var qPanel, rPanel;

document.onmousemove = new Function ('e', 'if (dc) dc.drag(e || window.event)');
document.onmouseup = new Function ('if (dc) dc.drop()');
document.onselectstart = new Function ('return false');
