function PopupManager(EventManager, PopupMap) {
	var LayersToLoad = new Array();
	var HTTPObjects = new Array(); /* Tracks the multiple data streams */
	var MapId = PopupMap.getId();
	var PopupId = MapId+'-Popups';

	var MySelf = this;

	this.onAddLayer = function(mapXMLObj) {
		if(MAP_ASSUME_DATA || new String(mapXMLObj.getAttribute('data')).match(/true/i)) {
			LayersToLoad[mapXMLObj.getAttribute('title')] = mapXMLObj.getElementsByTagName('file')[0].firstChild.nodeValue;
			loadLayerData(mapXMLObj.getAttribute('title'));
		}

	}


	this.onRemoveLayer = function(layerTitle) {
		if(LayersToLoad[layerTitle]) {
			MySelf.cleanupHTTPObject(layerTitle);
			LayersToLoad[layerTitle] = null;
		}
	}

	this.cleanupHTTPObject = function(id) {
		if(HTTPObjects[id]) {
			HTTPObjects[id].abort();
			HTTPObjects[id] = null;
		}
	}

	this.cleanupAllHTTPObjects = function() {
		for(var v in HTTPObjects) {
			this.cleanupHTTPObject(v);
		}
	}

	function loadLayerData(id) {
		var additionalInputs = new Array();
		var layerUrl = LayersToLoad[id];
		if(layerUrl == null) { return false; }

		if(layerUrl.substring(0,1) == '/' || layerUrl.match(/[A-Za-z]\:/)) {
			additionalInputs['MAPFILE'] = layerUrl;
		} else {
			additionalInputs['MAPFILE'] = MAPSERVER_MAPFILE_ROOT + layerUrl;
		}

		additionalInputs['MODE'] = 'nquery';
		var dataURL = ProcessURLString(PopupMap, MAPSERVER_DATA_URL, new Array(), additionalInputs,' ',' '); 
		if(dataURL) {
			MySelf.loadData(id, dataURL);
			logDebugMessage('Data URL', false, dataURL);
		}

	}

	this.onNavigate = function() {
		if(MAP_POPUPS_ENABLED) {
			MySelf.cleanupAllHTTPObjects();

			for(var id in LayersToLoad) {
				loadLayerData(id);
			}
		}


	}

	this.loadData = function(id, dataCall) {
		var http = getHTTPObject();
		HTTPObjects[id] = http;		/* Register the HTTP Object, so it can be aborted if neccessary */
		var postData = '';
		var postGet = 'GET';
		if(dataCall.length > 1000) {
			var arr = dataCall.split('?');
			dataCall = arr[0];
			postData = arr[1];
			postGet = 'POST';
		}
		http.open(postGet, dataCall, true);
		http.onreadystatechange = function() {
			/* Need to check for http's existance because it may have been aborted */
			if(http && http.readyState == 4) {
				if(http.responseXML) {
					/* Load the XML and Transform it to an Imagemap using the XSL */
					
					var imagemapElements = http.responseXML.getElementsByTagName('imagemap');
					if(imagemapElements.length < 1) { return false; }
					
					imagemapElements[0].setAttribute('layerid', MapId+id);

					var d = document.getElementById(MapId+id+'-ImageMapParent');
					if(!d) {
						d = document.createElement('div');
						document.getElementById(PopupMap.getParentId()).appendChild(d);
						d.setAttribute('id',MapId+id+'-ImageMapParent');
						d.className = 'ImageMapParent';
					}
					processXMLWithXSLT(http.responseXML, XSL_IMAGEMAP, d.getAttribute('id'), correlateImagemap);
					if(http.responseXML.getElementsByTagName('popup').length > 0) {
						EventManager.triggerEvent('datalayer',id);
					}
				}
			}
		}
		http.send(postData);

	}

	function correlateImagemap(containerId) {
		var container = document.getElementById(containerId);
		var areas = container.getElementsByTagName('area');
		var circles = new Array();


		/* Insert the points into a "2D" B-Tree so they can be evaluated for "stacking" */
		var b2dTree = new BTree();
		for(var i = 0; i <  areas.length; i++) {
			var shape = new String(areas[i].getAttribute('shape')).toLowerCase();
			if(shape == 'circle') {
				var coords = areas[i].getAttribute('coords').split(',');
				var index = areas[i].getAttribute('index'); // Identifier
				b2dTree.insert(parseInt(coords[0]), parseInt(coords[1]), index);
			}
		}
	
		for(var i = 0; i < areas.length; i++) {
			areas[i].popups = new Array();
			areas[i].onmouseover = showPopups;
			areas[i].onclick = toggleSticky;
			areas[i].onmouseout = toggledHidePopups;
			areas[i].popups[0] = parseInt(areas[i].getAttribute('index')); // The actual relation popup
			var shape = new String(areas[i].getAttribute('shape')).toLowerCase();
			if(shape == 'circle') {
				/*var thisCircle = new Circle();*/
				var coords = areas[i].getAttribute('coords').split(',');
				var x = parseInt(coords[0]);
				var y = parseInt(coords[1]);
				var r = parseInt(coords[2]);
				var relatedNodes = b2dTree.searchByRange2D(x-r,y-r,x+r,y+r);
				if(relatedNodes) {
					for(var n = 0; n < relatedNodes.length; n++) {
						areas[i].popups[n] = relatedNodes[n].o;
					}
				}
			} else if(shape == 'line' || shape == 'rect') {
				var coords = areas[i].getAttribute('coords').split(/[, ]/);
				for(var c = 0; c < coords.length; c++) {
					coords[c] = parseInt(coords[c]);
				}
				var ptA = new Point(coords[0],coords[1]), ptB = new Point(coords[2], coords[3]);
				var seg = new LineSegment(ptA, ptB);
				seg = seg.buffer(3); // Returns a polygon representing the buffered linesegment

				areas[i].setAttribute('shape','poly');
				areas[i].setAttribute('coords', seg.toString(',',true));
				areas[i].onmousemove = showPopups;
				logDebugMessage('Imagemap-Line', false, areas[i].getAttribute('coords')+' '+areas[i].getAttribute('shape'));
			} else if(shape == 'poly') {
				areas[i].onmousemove = showPopups;
			}
		}

		// Use XPath if available, makes for a shorter list... and no testing!
		if(document.evaluate) {
			var ximages = document.evaluate("//div[@id = '"+containerId+"']//img[@class = 'closeButton']", document, null, XPathResult.ANY_TYPE, null);
			var obj;
			while(obj = ximages.iterateNext()) {
				obj.onclick = hidePopupSelf;
			}

			var xdivs = document.evaluate("//div[@id = '"+containerId+"']//div[@class = 'popupParent']", document, null, XPathResult.ANY_TYPE, null);
			while(obj = xdivs.iterateNext()) {
				obj.draggable = new Draggable(obj.getAttribute('id'), obj.getElementsByTagName('div')[0], true,true,true);
			}
		} else {
			var images = container.getElementsByTagName('img');
			for(var i = 0; i < images.length; i++) {
				if(images[i].className && images[i].className.match(/closeButton/)) {
					images[i].onclick = hidePopupSelf;
				}
			}
			var divs = container.getElementsByTagName('div');
			for(var d = 0; d < divs.length; d++) {
				if(divs[d].className == 'popupParent') {
					divs[d].draggable = new Draggable(divs[d].getAttribute('id'), divs[d].getElementsByTagName('div')[0], true,true,true);
				}
			}

		}
	}
	
	function showPopup(id,l,r,t,b,z) {
		var d = document.getElementById(id);
		if(!z) { z = 1; }
		if(d) { // Make sure it exists
			d.style.visibility = 'visible';
			d.style.left = l;
			d.style.right = r;
			d.style.top = t;
			d.style.bottom = b;
			d.style.zIndex = z;
		} else {
			logDebugMessage('Map-Popups', false, 'Trying to display a popup that does not exists: '+id);
		}
		d = null;
	}

	function hidePopup(id) {
		var d = document.getElementById(id);
		if(d) {
			d.style.visibility = 'hidden';
		} else {
			logDebugMessage('Map-Popups', false, 'Trying to hide a popup that does not exist: '+id);
		}
	}

	function hidePopups(event,popups,root) {
		if(!popups) { popups = this.popups; }
		if(!root) { root = this.getAttribute('root'); }
		for(var i = 0; i < popups.length; i++) {
			hidePopup(root+'-Popup-'+popups[i]);
		}

	}


	function toggledHidePopups(event) {
		if(this.sticky) {
		} else {
			hidePopups(event, this.popups, this.getAttribute('root'));
		}
	}

	function hidePopupSelf() {
		hidePopup(this.getAttribute('relation'));
	}

	function toggleSticky() {
		this.sticky = !this.sticky;
	}

	function showPopups(event) {
		if(window.event) { event = window.event; }
		var area = getEventTarget(event);
		var ImageControlId = PopupMap.getImageControlId();
		var ImageControl = document.getElementById(ImageControlId);
		var offsetPoint = objectClientPosition(ImageControl);
		var mouseY = event.clientY-offsetPoint.y;
		var mouseX = event.clientX-offsetPoint.x;
		var offsetX = 5;
		var offsetY = 5;
		var root = this.getAttribute('root');
		if(!area.popups) { return false; }

		for(var i = 0; i < area.popups.length; i++) {
			var z =  MAP_POPUP_ZINDEX+i;
			var left = 'auto', right = 'auto', top = 'auto', bottom = 'auto';
			if(mouseY < ImageControl.offsetHeight / 2) {
				top = mouseY+offsetY+'px';
			} else {
				bottom = (ImageControl.offsetHeight - mouseY)+offsetY+5+'px';
			}
			if(mouseX < ImageControl.offsetWidth /2 ) {
				left = mouseX+offsetX+'px';
			} else {
				right = (ImageControl.offsetWidth - (mouseX-offsetX))+'px';
			}
			if(!this.sticky) {
				showPopup(root+'-Popup-'+area.popups[i], left,right,top,bottom,z);
			} else {
				document.getElementById(root+'-Popup-'+area.popups[i]).style.visibility = 'visible';
			}

			offsetY += 10;
			offsetX += 10;
		}
		area = null;
		ImageControl = null;
	}

	this.initializeEvents = function () {
		EventManager.addEventListener('navigate', PopupId, MySelf.onNavigate);
		EventManager.addEventListener('addlayer', PopupId, MySelf.onAddLayer);
		EventManager.addEventListener('removelayer', PopupId, MySelf.onRemoveLayer);
	}


}
