var genMoveHandler = {
	// if true then the dragged element is brought to front
	checkZIndex:	false,
	
	dragObject:		null,
	ty:				null,
	tx:				null,
	
	getMovableAncestor:	function (el) {
		if (el == null)
			return null;
		else if (hasClassName(el, "moveme") || hasClassName(el, "handle"))
			return el;
		else
			return this.getMovableAncestor(el.parentNode);
	},
	
	mouseDownHandler:	function (e) {
		var el = this.getMovableAncestor(e.target)
		var id;

		if (el != null) {
			if (hasClassName(el, "handle")) {
				id = el.getAttribute("handlefor");
				if (id == null) {
					this.dragObject = null;
					return;
				}
				else
					this.dragObject = document.getElementById(id);
			}
			else 
				this.dragObject = el;
			
			if (this.checkZIndex)
				this.makeOnTop(this.dragObject);
			
			this.tx = e.screenX - this.getComputedStyle(this.dragObject, "left");
			this.ty = e.screenY - this.getComputedStyle(this.dragObject, "top");
			
			e.stopPropagation();
			e.preventDefault();
		}
		else {
			this.dragObject = null;
		}
	},

	mouseUpHandler:		function (e) {
		if (this.dragObject != null) {
			this.dragObject = null;
			e.stopPropagation();
			e.preventDefault();
		}
	},

	mouseMoveHandler:	function (e) {
		if (this.dragObject != null) {
			this.dragObject.style.left = e.screenX - this.tx + "px";
			this.dragObject.style.top = e.screenY - this.ty + "px";
			e.stopPropagation();
			e.preventDefault();
		}
	},

	makeOnTop:			function (el) {
		var daiz;
		var max = 0;
		var da = document.getElementsByTagName("*");	// get all
		
		for (var i=0; i<da.length; i++) {
			daiz = da[i].style.zIndex;
			if (daiz != "" && daiz > max)
				max = daiz;
		}
		
		el.style.zIndex = max + 1;
	},
	
	getComputedStyle:	function (el, sProp) {
		return parseInt(document.defaultView.getComputedStyle(el,
				null).getPropertyValue(sProp));
	},
	
	start:		function () {
		
		// test DOM support
		// notice that CSS requires Views so there is no need to test that
		if ( typeof document.implementation != "undefined" &&
			document.implementation.hasFeature("HTML", "1.0") &&
			document.implementation.hasFeature("Events", "2.0") &&
			document.implementation.hasFeature("CSS", "2.0") ) {
			
			var oThis = this;
			document.addEventListener("mousedown", function (e) { oThis.mouseDownHandler(e); }, false);
			document.addEventListener("mouseup",   function (e) { oThis.mouseUpHandler(e); },   false);
			document.addEventListener("mousemove", function (e) { oThis.mouseMoveHandler(e); }, false);
		}
	}
};


function hasClassName(el, sClassName) {
	if (el == null) return false;
	var parts = String(el.className).split(/\s+/);
	for (var i = 0; i < parts.length; i++) {
		if (parts[i] == sClassName)
			return true;
	}
	return false;
}

genMoveHandler.start();