var Drag = {
	obj: null,
	init: function (o, oRoot, minX, maxX, minY, maxY, stepX, stepY, bSwapHorzRef, bSwapVertRef, fXMapper, fYMapper) {
		o.onmousedown = Drag.start;

		o.hmode = bSwapHorzRef ? false : true;
		o.vmode = bSwapVertRef ? false : true;

		o.root = oRoot && oRoot != null ? oRoot : o;

		if (o.hmode && isNaN(parseInt(o.root.style.left))) o.root.style.left = "0px";
		if (o.vmode && isNaN(parseInt(o.root.style.top))) o.root.style.top = "0px";
		if (!o.hmode && isNaN(parseInt(o.root.style.right))) o.root.style.right = "0px";
		if (!o.vmode && isNaN(parseInt(o.root.style.bottom))) o.root.style.bottom = "0px";

		o.minFX = o.minX = typeof minX != 'undefined' ? minX : null;
		o.minFY = o.minY = typeof minY != 'undefined' ? minY : null;
		o.maxFX = o.maxX = typeof maxX != 'undefined' ? maxX : null;
		o.maxFY = o.maxY = typeof maxY != 'undefined' ? maxY : null;

		o.stepX = typeof stepX != 'undefined' ? stepX : null;
		o.stepY = typeof stepY != 'undefined' ? stepY : null;
		o.stepXC=0;
		o.stepYC=0;

		o.PrevStepX=o.stepX;
		o.PrevStepY=o.stepY;

		if(o.minX!==null) o.root.style.left = o.minX+"px";
		if(o.minY!==null) o.root.style.top = o.minY+"px";

		o.root.lastX = o.minX;
		o.root.lastY = o.minY;

		o.xMapper = fXMapper ? fXMapper : null;
		o.yMapper = fYMapper ? fYMapper : null;

		o.root.onDragStart = new Function();
		o.root.onDragEnd = new Function();
		o.root.onDrag = new Function();
	},

	start: function (e) {
		var o = Drag.obj = this;
		e = Drag.fixE(e);
		var y = parseInt(o.vmode ? o.root.style.top : o.root.style.bottom);
		var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right);

		o.prevX=x; o.prevY=y;
		o.root.onDragStart(x, y);

		o.lastMouseX = e.clientX;
		o.lastMouseY = e.clientY;

		if (o.hmode) {
			if (o.minX != null) o.minMouseX = e.clientX - x + o.minX;
			if (o.maxX != null) o.maxMouseX = o.minMouseX + o.maxX - o.minX;
		} else {
			if (o.minX != null) o.maxMouseX = -o.minX + e.clientX + x;
			if (o.maxX != null) o.minMouseX = -o.maxX + e.clientX + x;
		}

		if (o.vmode) {
			if (o.minY != null) o.minMouseY = e.clientY - y + o.minY;
			if (o.maxY != null) o.maxMouseY = o.minMouseY + o.maxY - o.minY;
		} else {
			if (o.minY != null) o.maxMouseY = -o.minY + e.clientY + y;
			if (o.maxY != null) o.minMouseY = -o.maxY + e.clientY + y;
		}

		document.onmousemove = Drag.drag;
		document.onmouseup = Drag.end;

		return false;
	},

	drag: function (e) {
		e = Drag.fixE(e);
		var o = Drag.obj;

		var ey = e.clientY;
		var ex = e.clientX;

		var y = parseInt(o.vmode ? o.root.style.top : o.root.style.bottom);
		var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right);

		var nx, ny;

		if (o.minX != null) ex = o.hmode ? Math.max(ex, o.minMouseX) : Math.min(ex, o.maxMouseX);
		if (o.maxX != null) ex = o.hmode ? Math.min(ex, o.maxMouseX) : Math.max(ex, o.minMouseX);
		if (o.minY != null) ey = o.vmode ? Math.max(ey, o.minMouseY) : Math.min(ey, o.maxMouseY);
		if (o.maxY != null) ey = o.vmode ? Math.min(ey, o.maxMouseY) : Math.max(ey, o.minMouseY);

		nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1));
		ny = y + ((ey - o.lastMouseY) * (o.vmode ? 1 : -1));

		if (o.xMapper) nx = o.xMapper(y);
		else if (o.yMapper) ny = o.yMapper(x);

		if(o.stepX!==null){
			if(o.lastMouseX<ex){
				if((o.lastX+(o.stepX-2)) > nx) return false;
				else o.stepXC++;
				nx=o.minFX+Math.round(o.stepX*o.stepXC);
			}
			if(o.lastMouseX>ex){
				if((o.lastX-(o.stepX-2)) < nx) return false;
				else o.stepXC--;
				nx=o.minFX+Math.round(o.stepX*o.stepXC);
			}
			if(nx>o.maxX) nx=o.maxX;
		}
		if(o.stepY!==null){
			// na
		}

		Drag.obj.root.style[o.hmode ? "left" : "right"] = nx + "px";
		Drag.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px";
		Drag.obj.lastX = nx;
		Drag.obj.lastY = ny;
		Drag.obj.lastMouseX = ex;
		Drag.obj.lastMouseY = ey;

		Drag.obj.root.onDrag(nx, ny);
		return false;
	},

	move: function (o, x, y, stepX, stepY) {
		//if(y!==undefined) var y=o.minFY+y;
		//if(x!==undefined) var x=o.minFX+x;

		if(y!==undefined) var y=parseInt(o.vmode ? o.root.style.top : o.root.style.bottom)+y;
		if(x!==undefined) var x=parseInt(o.hmode ? o.root.style.left : o.root.style.right)+x;

		if(typeof stepX != 'undefined'){
			if(stepX=='last') stepX=Math.round((o.maxFX-o.minFX)/o.stepX);
			o.stepXC=stepX;
			x=o.minFX+Math.round(o.stepX*o.stepXC);
			if(x>o.maxX) x=o.maxX;
			if(x<o.minX) x=o.minX;
		}
		if(typeof stepY != 'undefined'){
			o.stepYC=stepY;
			y=o.minFY+Math.round(o.stepY*o.stepYC);
			if(y>o.maxY) y=o.maxY;
			if(y<o.minY) y=o.minY;
		}

		//if(y>o.maxY || y<o.minY || x>o.maxX || x<o.minX) return false;
		if(y!==undefined){
			if(y>o.maxY) y=o.maxY;
			if(y<o.minY) y=o.minY;
		}
		if(x!==undefined){
			if(x>o.maxX) x=o.maxX;
			if(x<o.minX) x=o.minX;
		}

		if(x!==undefined){
			o.root.style[o.hmode ? "left" : "right"] = x + "px";
			o.lastX = x;
		}
		if(y!==undefined){
			o.root.style[o.vmode ? "top" : "bottom"] = y + "px";
			o.lastY = y;
		}

		o.root.onDrag(x, y);
	},

	end: function () {
		document.onmousemove = null;
		document.onmouseup = null;

		Drag.obj.root.PrevStepX=Drag.obj.stepX;
		Drag.obj.root.PrevStepY=Drag.obj.stepY;

		Drag.obj.root.onDragEnd(parseInt(Drag.obj.root.style[Drag.obj.hmode ? "left" : "right"]), parseInt(Drag.obj.root.style[Drag.obj.vmode ? "top" : "bottom"]));
		Drag.obj = null;
	},

	fixE: function (e) {
		if (typeof e == 'undefined') e = window.event;
		if (typeof e.layerX == 'undefined') e.layerX = e.offsetX;
		if (typeof e.layerY == 'undefined') e.layerY = e.offsetY;
		return e;
	}
};
