
function Dragger(myId, minX, maxX, isMaxXRight, 
				 minY, maxY, isMaxYBottom, isMouseSeeking)
{
	var me = this;

	var WRAP = "Wrap";
	var debug = 0;	
	
	var curLeft = new Array();
	var curTop  = new Array();

	var minLefts = new Array();
	var maxLefts = new Array();
	var minTops = new Array();
	var maxTops = new Array();

	var isBottoms = new Array();
	var isRights = new Array();
	var isMouseSeeker = new Array();

	var beforeDrags = new Array();
	var onDrags = new Array();
	var afterDrags = new Array();

	var selectedObj;
	var offsetX, offsetY, tagWidth, tagHeight;

	var insaneMin = -10000;
	var insaneMax = 10000;

	
	this.getWrapName = function()
	{
		return WRAP;
	}
	
	
	this.setDragger = function (myId, minX, maxX, isMaxXRight, 
								minY, maxY, isMaxYBottom, isMouseSeeking)
	{
		me.setLimits(myId, minX, maxX, isMaxXRight, 
								minY, maxY, isMaxYBottom, isMouseSeeking);
		me.onBeforeDrag(myId);
		me.onDrag(myId);
		me.onAfterDrag(myId);
	}

	this.setLimits = function (myId, minX, maxX, isMaxXRight, 
								minY, maxY, isMaxYBottom, isMouseSeeking) 
	{
		if(debug) logger.dump("setLimits myId " + myId
			+ ' minX:' + minX + ' maxX:' + maxX + ' isMaxXRight:' + isMaxXRight
			+ ' minY:' + minY + ' maxY:' + maxY + ' isMaxYBottom:' + isMaxYBottom
			+ ' isMouseSeeking:' + isMouseSeeking);
		myId += WRAP;
		if(typeof(minX) != 'number') minX = insaneMin; 
		if(typeof(maxX) != 'number') maxX = insaneMax;
		if(typeof(minY) != 'number') minY = insaneMin;
		if(typeof(maxY) != 'number') maxY = insaneMax;
		isMaxYBottom = (isMaxYBottom == true);
		isMaxXRight = (isMaxXRight == true);
		minLefts[myId] = minX;
		maxLefts[myId] = maxX;
		minTops[myId]  = minY;
		maxTops[myId]  = maxY;
		isBottoms[myId] = isMaxYBottom;
		isRights[myId] = isMaxXRight;
		isMouseSeeker[myId] = isMouseSeeking;
		me.move(myId, minX, minY);
		aa.show(aa.get(myId));
	}
	
	this.seekId = function(evt) {
		var left = aa.getMouseX(evt);
		var top = aa.getMouseY(evt);
		if(debug)logger.dump('seekId left' + left + ' top ' + top);
		for(var thisId in minLefts) {
			if (!isMouseSeeker[thisId]) continue;
			if (left < minLefts[thisId]) continue;
			if (left > maxLefts[thisId]) continue;
			if (top < minTops[thisId]) continue;
			if (top > maxTops[thisId]) continue;
			if(debug)logger.dump('seekId found ' + thisId);
			return thisId;
		}
		return null;
	}
	
	this.getIdWithWrapper = function(id) {
		return id += WRAP;
	}
	
	this.onBeforeDrag = function(myId, myHandler) {
		myId += WRAP;
		if(debug)logger.dump('onBeforeDrag for [' + myId + ']');
		setHandler(beforeDrags, myId, myHandler);
	}

	this.onDrag = function(myId, myHandler) {
		myId += WRAP;
		if(debug)logger.dump('onDrag for [' + myId + ']');
		setHandler(onDrags, myId, myHandler);
	}

	this.onAfterDrag = function(myId, myHandler) {
		myId += WRAP;
		if(debug)logger.dump('onAfterDrag for [' + myId + ']');
		setHandler(afterDrags, myId, myHandler);
	}

	function setHandler(myEventArray, myId, myHandler) {
		if (debug && typeof(maxTops[myId]) == 'undefined') {
			alert(myId + ' is not defined');
			return;
		}
		if(debug)logger.dump('setHandler for [' + myId + '] typeof[' + typeof(myHandler));
		if (typeof(myHandler) != 'function' && typeof(myHandler) != 'string') {
			myHandler = function(){};
		}
/*
		var out = '';
		for(var h in myEventArray){
			out += h + ' as [' + myEventArray[h] + "]\n";
		}
		if(debug)logger.dump('setHandler for [' + myId + '] [' + myHandler 
			+ '] list is [' + out + ']');
*/
		if(debug)logger.dump('setHandler for [' + myId + '] [' + myHandler);
		myEventArray[myId] = myHandler;
	}
	
	this.getMaxX = function(myId)
	{
		myId += WRAP;
		return me.getMax(myId, true);
	}
	
	this.getMaxY = function(myId)
	{
		myId += WRAP;
		return me.getMax(myId, false);
	}
	
	this.getMax = function(myId, isX, myObj)
	{
		var myMax = isX? maxLefts[myId] : maxTops[myId];
		var isOthers = isX? isRights : isBottoms;
		if(isOthers[myId]) {
			if( typeof(myObj) == 'undefined') {
				myObj = aa.get(myId);
			}
			var adjust = isX? aa.getWidth(myObj) : aa.getHeight(myObj);
			myMax -= adjust;
		}
		return myMax;
	}
	
	this.setLeftPercentage = function(myId, percentage)
	{
		myId += WRAP;
		return me.setPercentage(myId, true, percentage);
	}

	this.setTopPercentage = function(myId, percentage)
	{
		myId += WRAP;
		return me.setPercentage(myId, false, percentage);
	}

	this.setPercentage = function(myId, isX, percentage)
	{
		var minpos = isX? minLefts[myId] : minTops[myId];
		var otherpos =  isX? curTop[myId] : curLeft[myId];
		var range = me.getMax(myId, isX) - minpos;
		var pos = minpos + (range * percentage);
		if (isX) {
	        me.move(myId, pos, otherpos);
		} else {
	        me.move(myId, otherpos, pos);
		}
	}
	
	this.move = function(myId, left, top){
		var selectedObj = aa.get(myId);
        aa.moveTo(selectedObj, left, top);
		curLeft[myId] = left;
		curTop[myId] = top;
	}

	this.getPercentage = function(myId, isX)
	{
		var mins = isX? minLefts : minTops;
		var curs =  isX? curLeft : curTop;
		var range = me.getMax(myId, isX) - mins[myId];
		var pos = curs[myId] - mins[myId];
		if(debug) logger.dump('myId ' + myId + ' range ' + range + ' pos ' + pos);
		if(isNaN(pos) || pos == 0)
		 	return 0;
		return pos / range;
	}

	this.getLeftPercentage = function(myId)
	{
		myId += WRAP;
		return me.getPercentage(myId, true);
	}

	this.getTopPercentage = function(myId)
	{
		myId += WRAP;
		return me.getPercentage(myId, false);
	}

	// Set global reference to element being engaged and dragged
	this.setSelectedElem = function(evt) {
	    var target = aa.getSrcElement(evt);
		var divID = (target.name && target.src) ? target.name + WRAP : "";
		
		if(debug) logger.dump('evt [' + evt + ']\n'
							+ 'div [' + divID + ']\n'
							+ 'target [' + target + ']\n'
							+ 'myId ' + myId);
		if (!divID) {
			divID = me.seekId(evt);
		}
	    if (divID) {
			if(debug) logger.dump('myIdWrap [' + myId + WRAP + ']');
	        selectedObj = aa.get(divID);
			selectedId = divID;
			if(debug) logger.dump('obj [' + selectedObj + ']');
	        return;
	    }
	    selectedObj = null;
		selectedId = null;
	    return;
	}


	// Drag an element
	this.dragIt = function(evt) {
	    evt = aa.getEvent(evt);
	    if (selectedObj) {
			var left = aa.getMouseX(evt) - offsetX;
			var top = aa.getMouseY(evt) - offsetY;
			if(debug)logger.dump(
				'getmouse left' + left + ' top ' + top);

			var minLeft = minLefts[selectedId];
			var maxLeft = me.getMax(selectedId, true, selectedObj);
			var minTop = minTops[selectedId];
			var maxTop = me.getMax(selectedId, false, selectedObj);
			if (left > maxLeft) {
				left = maxLeft;
			} else if (left < minLeft) {
				left = minLeft;
			}
			if (top > maxTop) {
				top = maxTop;
			} else if (top < minTop) {
				top = minTop;
			}

			if(debug)logger.dump(
				'selectedId ' + selectedId + ' range x ' + minLeft 
				+ ' - ' + maxLeft + ' cur ' + left
			    + '\nrange y ' + minTop + ' - ' + maxTop + ' cur ' + top);

	        me.move(selectedId, left, top);

			if(debug)logger.dump(
				'left % ' + me.getPercentage(selectedId, true)
			  + ' top % ' + me.getPercentage(selectedId, false) );
	        evt.cancelBubble = true;
			utils.exec(onDrags[selectedId]);
	        return false;
	    }
	}

	// Turn selected element on
	this.engage = function(evt) {
	    evt = aa.getEvent(evt);
		if(debug) logger.dump('engage evt [' + evt + ']');
	    me.setSelectedElem(evt);

	    if (selectedObj) {
			utils.exec(beforeDrags[selectedId]);
			if(debug) logger.dump('engage tagWidth [' + tagWidth 
								+ '] tagHeight [' + tagHeight + ']');
			if (isMouseSeeker[selectedId]) {
				offsetX = (aa.getWidth(selectedObj) /2);
				offsetY = (aa.getHeight(selectedObj) /2);
				me.dragIt(evt);
			} else {
		        offsetX = aa.getMouseX(evt) - aa.getLeft(selectedObj);
		        offsetY = aa.getMouseY(evt) - aa.getTop(selectedObj);
	    	}
		    return false;
	    }
	}
	
	
	// Turn selected element off
	this.release = function(evt) {
		if(debug) logger.dump('release evt [' + evt + ']');
	    if (selectedObj) {
			utils.exec(afterDrags[selectedId]);
	    }
        selectedObj = null;
		selectedId = null;
	}
	
	// Set event capture for Navigator 4
	this.setNSEventCapture = function() {
	    document.captureEvents(	Event.MOUSEDOWN | 
								Event.MOUSEMOVE | 
								Event.MOUSEUP	);
	}
	
	// Assign event handlers used by both Navigator and IE
	this.init = function() {
	    if (document.layers) {
	        me.setNSEventCapture();
	    }
	    document.onmouseup		= me.release;
	    document.onmousedown 	= me.engage;
	    document.onmousemove 	= me.dragIt;
	}
	if (typeof(myId) != 'undefined') {
		me.setDragger(myId, minX, maxX, isMaxXRight, 
								minY, maxY, isMaxYBottom, isMouseSeeking);
	}
	me.init();
}