		//**************************************************************
		//**************************************************************
		//**************************************************************
		// KARTTRICKET CLIENT V1.5.0.5
		// Copyright (C) 2007 Systemtricket AB
		// anders.bjorck@systemtricket.se
		//**************************************************************
		//**************************************************************
		//**************************************************************

		var _ClientVersion = "KARTTRICKET CLIENT V1.5.0.5";
		var _mapName = null;
		var _mapDescription = null;
		var _zoomLevelName = null;
		var _maxZoomLevel = null;
		var _minZoomLevel = null;
		var _preSelectedSymbol = null;

		var v2struktur = false;
		
		var _routeName = null;
		var _routeDescription = null;
		var _routePublic = null;
		var _routeCreatedBy = null;
		
		var isPostBack = false;

		var mapVariant = 'standard';
		
		var filePrefix = null;
		var fileExtension = null;

		var placeholder = null;		
		var map = null;
		var symbols = null;

		var placeHolderDivID = "_TricketMapDiv";

		var mapWidth = null;
		var mapHeight = null;
		var segmentWidth = null;
		var segmentHeight = null;
		var meterPerPixelX = null;
		var meterPerPixelY = null;
		var segmentCountX = 0;
		var segmentCountY = 0;
		var countX = null;
		var countY = null;
		var segmentDeltaX = 0;
		var segmentDeltaY = 0;
		var zoomLevelMeterOffsetX = 0;
		var zoomLevelMeterOffsetY = 0;
		
		
		var gcTimer = null;     // For the "Garbage collector", deletes no longer visible tiles
		var loadedSegmentIndexes = null;
		var mapNodeCount = 0;
		var tileLoaderTimer = null;
		var tileCounter = 0;
		var noneLoaded = false;
		var loadBurst = 3;

		var extendedObjectContainerElem = null;

		var blinkObject = null;
		var blinkShObject = null;
		var blinkMainTimer = null;
		var blinkSubTimer = null;

		var geoWest = 0;
		var geoNorth = 0;
		var geoEast = 0;
		var geoSouth = 0;


		// Vars
		var mapCenterX = null;
		var mapCenterY = null;

		// for scrolling
		var currentY = null;
		var currentX = null;
		var lastMX = 0;
		var lastMY = 0;
		var deltaX = 0;
		var deltaY = 0;

		var decelerateTimer = null;
		var deltaTimer = null;
		var decelerateFactor = 0.2;
		var decelerateInterval = 25;

		var smoothTimer = null;
		var smoothCoordsX = null;
		var smoothCoordsY = null;
		var smoothScrollInterval = 25;

		var mapList = null;
		var routeList = null;
		var layerList = null;
		var viewList = null;
		var mapVariantList = null;
		var colorList = null;
		var lineStyleList = null;
		var lineWeightList = null;
		var dotCheck = null;
		
		var dialogContainerElem = null;
		var dialogElem = null;

		var mapVariants = null;
		var variantPrefix = '';
		function s_MapVariant() {
			var _mapVariant = '';
			var _variantPrefix = '';
			var _variantName = '';
		}

		var layerId = null;
		var _layerName = null;
		var _layerDescription = null;

		var layerArray = null;
		function s_Layer() {
			var layerId = 0;
			var layerName = null;
			var layerDescription = null;
			var layerVisible = false;
		}				

		var routeArray = null;
		function s_Route() {
			var routeId = 0;
			var routeName = null;
			var routeDescription = null;
			var routeVisible = false;
			var routeCoordinates = null;
			var routeDistance = null;
			var routeColor = null;
			var routeWeight = null;
			var routeStyle = null;
			var routeDots = null;
			var route = null;
			var routePublic = null;
			var routeCreatedBy = null;
		}				


		var viewId = null;
		var _viewName = null;
		var _viewDescription = null;


		var routeId = null;

		var pointerDistanceOutput = null;
		var distanceOutput = null;
		var statusOutput = null;
		var route = null;

		var RT90WestElem = null;
		var RT90NorthElem = null;
		var RT90EastElem = null;
		var RT90SouthElem = null;
		
		function s_Dot() {
			var mX = 0;
			var mY = 0;
			var elem = null;
			var lineElem = null;
		}

		var _clickPixelX = 0;
		var _clickPixelY = 0;
		var _clickMeterX = 0;
		var _clickMeterY = 0;
		var _clickGeoX = 0;
		var _clickGeoY = 0;
		
		var cMX = 0;
		var cMY = 0;
		var isMouseOverMap = false;
		

        function s_EventHandler()
        {
            var element = null;
            var type = null;
            var funcRef = null;
        }

        var eventHandlers = new Array();        


		// Debug
		function debugprint(s) { document.getElementById('OutputDiv').innerHTML += s + '<br>'; return true; }
		function cls() { document.getElementById('OutputDiv').innerHTML = ''; return true; }

		function isOpera() { return navigator.userAgent.match('Opera'); }
		function isNS() { return navigator.userAgent.match('Netscape'); }
		function isSafari() { return navigator.userAgent.match('Safari'); }

		function _iTM() // initTricketMap
		{
			// Set new properties to their default value
			if(typeof(doubleClickZooms)!='boolean') doubleClickZooms = false;
			if(typeof(symbolOpacity)!='number') symbolOpacity = 80;
			if(typeof(disableObjectPopups)!='boolean') disableObjectPopups = false;
			
			if(enableViewState)
				loadViewState();

			placeholder = document.getElementById(placeHolderDivID);
			if(!placeholder)
			{
				alert('The required element ' + placeHolderDivID + ' cannot be found in the page.');
				return false;
			}
			
			initInfoBubbles();
			initControls();
			initInterface();

			if(isPostBack == false && ignoreUserStartPos == false)
				loadHomeSettings();


			if(!loadMap(mapId))
			{
				alert('ERROR: Could not load initial map.');
				return;
			}

			initMapCalc();

			if(routeId) if(distanceOutput) distanceOutput.innerHTML = calculateRouteDistance();
			
			return true;
		}
		
		function loadHomeSettings()
		{
			var response = tricket_sendGetRequest(mapCommandUrl, 'cmd=loadHomeSettings&key=' + key);
			
			if(!response || response.length == 0) return;
			if(response.indexOf('NOT AUTH') >= 0)
			{
				if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				return false;
			}
			
			var parts = response.split('$');
			if(parts[0].length > 0) mapId = parseInt(parts[0]);
			if(parts[1].length > 0) _zoomLevel = parseInt(parts[1]);
			if(parts[2].length > 0) startMeterX = parseInt(parts[2]);
			if(parts[3].length > 0) startMeterY = parseInt(parts[3]);
		}		
		
		
		// Creates map element and the viewport element (divs) and inserts into the placeholder in page
		function initControls()
		{
			placeholder.style.width = viewPortWidth.toString() + 'px';
			placeholder.style.height = viewPortHeight.toString() + 'px';
			placeholder.style.position = 'relative';
			placeholder.style.overflow = 'hidden';

			symbols = document.createElement('div');
			symbols.style.position = 'absolute';
			symbols.style.top = '0px';
			symbols.style.left = '0px';
			symbols.style.zIndex = '20';
			placeholder.appendChild(symbols);

			map = document.createElement('div');
			map.style.position = 'absolute';
			map.style.top = '0px';
			map.style.left = '0px';
			map.style.zIndex = '0';
			placeholder.appendChild(map);

			return true;
		}
		

		function initInterface()
		{
			routeList = document.getElementById('RouteList');		
			mapList = document.getElementById('MapList');
			layerList = document.getElementById('LayerList');
			mapVariantList = document.getElementById('MapVariantList');
			viewList = document.getElementById('ViewList');
			
			colorList = document.getElementById('ColorList');
			lineStyleList = document.getElementById('LineStyleList');
			lineWeightList = document.getElementById('LineWeightList');
			dotCheck = document.getElementById('DotCheck');

			if(colorList) colorList.value = routeLineColor;
			if(lineStyleList) lineStyleList.value = routeLineStyle;
			if(lineWeightList) lineWeightList.value = routeLineWeight;
			if(dotCheck) dotCheck.checked = enableDots;
			
			RT90WestElem = document.getElementById('RT90WestDiv');
			RT90NorthElem = document.getElementById('RT90NorthDiv');
			RT90EastElem = document.getElementById('RT90EastDiv');
			RT90SouthElem = document.getElementById('RT90SouthDiv');
			
			if(mapList) {
				populateMapList();
			}

			if(dialogContainerElemId) {
				dialogContainerElem = document.getElementById(dialogContainerElemId);
				if(!dialogContainerElem)
					dialogContainerElem = placeholder;
			}
			else
				dialogContainerElem = placeholder;
				
			if(extendedObjectContainterId) extendedObjectContainerElem = document.getElementById(extendedObjectContainterId);
		}

				
		// loadMap
		function _lM(id) { return loadMap(id); }

		function loadMap(loadMapId)
		{
			 if(route)
				 _eR();

			var mapChanged = (mapId != loadMapId);

			if(mapChanged) 
				clearAllInfoBubbles();

			if(initialViewId && isPostBack == false)
			{
				var viewIdTemp = initialViewId;
				initialViewId = null;
				_loadView(viewIdTemp);
			}

			var response = tricket_sendGetRequest(mapCommandUrl, 'cmd=loadmap&mapid=' + loadMapId.toString() + '&key=' + key);

			if(!response) return;
			
			if(response.indexOf('NOT AUTH') >= 0)
			{
				if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				return false;
			}
			if(response.indexOf('ERROR:') >= 0)
			{
				alert(response);
				return false;
			}
			
			//Namn$Beskrivning$Bildsegmentsökväg$Bildsegmentprefix$Bildsegmentsuffix$InitialZoomnivå$StartMeterX$StartMeterY$MinZoomnivå$MaxZoomnivå$RT90Väster$RT90Norr$LaddadKartId$V2Struktur$RT90Öster$RT90Söder$RektX1$RektY1$RektX2$RektY2
			// 0    1           2                 3                 4                 5               6           7           8           9             10        11          12          13        14        15      16     17     18     19

			var params = response.split('$');
//			if(params.length != 20 && params.length != 21)
//			{
//				alert('ERROR: LoadMap got wrong number of parameters from server.');
//				return false;
//			}
			
			mapId = parseInt(params[12]);
			_mapName = params[0];
			_mapDescription = params[1];
			filePrefix  = (params[3].length == 0 ? null : params[3]);
			fileExtension = params[4];
			if(_zoomLevel == null || _zoomLevel == 0)
				_zoomLevel = parseInt(params[5]);
			
			_minZoomLevel = parseInt(params[8]);
			_maxZoomLevel = parseInt(params[9]);
			geoWest = parseFloat(params[10]);
			geoNorth = parseFloat(params[11]);
			geoEast = parseFloat(params[14]);
			geoSouth = parseFloat(params[15]);

			boundGeoNorth = boundGeoWest = boundGeoSouth = boundGeoEast = 0;

			if(parseFloat(params[17]) != geoWest) boundGeoWest = parseFloat(params[17]);
			if(parseFloat(params[16]) != geoNorth) boundGeoNorth = parseFloat(params[16]);
			if(parseFloat(params[19]) != geoEast) boundGeoEast = parseFloat(params[19]);
			if(parseFloat(params[18]) != geoSouth) boundGeoSouth = parseFloat(params[18]);
			
			if(boundGeoNorth == 0) boundGeoNorth = geoNorth;
			if(boundGeoWest == 0) boundGeoWest = geoWest;
			if(boundGeoSouth == 0) boundGeoSouth = geoSouth;
			if(boundGeoEast == 0) boundGeoEast = geoEast;

			if(mapList && mapList.length > 0)
				mapList.value = mapId.toString();

			if(params[13] == '0') v2struktur = false;
			else v2struktur = true;				

			populateRouteList(routeId);
			populateViewList(viewId);
			populateLayerList(layerId);

			if(!loadZoomLevel(_zoomLevel))
				return false;
			
			if(route == null && routeId != null)
				_loadRoute(routeId, false);

            unSelectObject();
			loadInfoBubbles();


			if(onMapLoaded.length > 0) eval(onMapLoaded);

			return true;
		}
		

		function loadZoomLevel(loadZoomLevel)
		{
			if(loadZoomLevel < _minZoomLevel) loadZoomLevel = _minZoomLevel; else if(loadZoomLevel > _maxZoomLevel) loadZoomLevel = _maxZoomLevel;
			
			var cmdString = 'cmd=loadzoomlevel';
			cmdString += '&mapid=' + mapId;
			cmdString += '&zoomlevel=' + loadZoomLevel;
			cmdString += '&mapVariant=' + mapVariant;
			if(currentX)
			{
				cmdString += '&x=' + Math.floor(p2mX(document.body.scrollLeft + currentX + viewPortWidth / 2));
				cmdString += '&y=' + Math.floor(p2mY(document.body.scrollTop + currentY + viewPortHeight / 2));
			}
			cmdString += '&key=' + key;
		
			var response = tricket_sendGetRequest(mapCommandUrl, cmdString);

			if(!response) return;
			
			if(response.indexOf('NOT AUTH') >= 0)
			{
				if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				return false;
			}
			if(response.indexOf('ERROR:') >= 0)
			{
				alert(response);
				return false;
			}

			// Namn$Pixelbredd$Pixelhöjd$MeterPerPixelX$MeterPerPixelY$Segmentpixelbredd$Segmentpixelhöjd$LaddadZoomnivå$LaddadKartvariant$VariantLista$OffsetMeterX$OffsetMeterY
			//  0    1          2         3              4              5                 6                    7              8               9              10          11

			var params = response.split('$');
			if(params.length != 12)
			{
				alert('ERROR: LoadZoomLevel got wrong number of parameters from server.');
				return false;
			}

			clearSegments();
			
			var mXTemp = null;
			var mYTemp = null;
			// Center on same spot after zoom level change

			if(currentX && currentY) 
			{
				mXTemp = p2mX(Math.floor(currentX) + viewPortWidth / 2);
				mYTemp = p2mY(Math.floor(currentY) + viewPortHeight / 2);
			}

			_zoomLevelName = params[0];
			mapWidth = parseInt(params[1]);
			mapHeight = parseInt(params[2]);
			meterPerPixelX = parseFloat(params[3]);
			meterPerPixelY = parseFloat(params[4]);
			segmentWidth = parseInt(params[5]);
			segmentHeight = parseInt(params[6]);
			_zoomLevel = parseInt(params[7]);
			mapVariant = params[8];
			
			zoomLevelMeterOffsetX = parseFloat(params[10]);
			zoomLevelMeterOffsetY = parseFloat(params[11]);
			
			mapVariants = new Array();
			var varArray = params[9].split('#');
			for(i = 0; i < varArray.length; i++)
			{
				var variant = new s_MapVariant();
				var parts = varArray[i].split(':');
				variant._mapVariant = parts[0];
				variant._variantPrefix = parts[1];
				variant._variantName = parts[2];
				if(mapVariant == variant._mapVariant)
					variantPrefix = variant._variantPrefix;
				mapVariants.push(variant);
			}
			
			if(mapVariantList)
				populateMapVariantList(null);
			
			initMap();

			if(startGeoX != null && startGeoY != null)
			{
				_setGeoCenter(startGeoX, startGeoY);
			}

			// Center on same spot after zoom level change
			if(mXTemp != null && mYTemp != null)
			{
				_scrollToMeter(mXTemp, mYTemp);
			}
			else if(startMeterX == -1 || startMeterX == null && (startGeoX == null || startGeoY == null))
			{
				_scrollTo(mapCenterX, mapCenterY);
			}
			else if(startGeoX != null && startGeoY != null)
			{
				if(!_setGeoCenter(startGeoX, startGeoY))
					_scrollToMeter(startMeterX, startMeterY);
			}
			else
			{
				_scrollToMeter(startMeterX, startMeterY);
			}

			reRenderRoute();
			reRenderInfoBubbles();
			
			if(isPostBack)
				_setLayer(true, layerId);


			if(onZoomLevelLoaded.length > 0) eval(onZoomLevelLoaded);

			return true;
		}
		

		function _lH()
		{
			if(staticInfoBubbleId != null && homeIsStaticObject == true)
			{
			    _centerOnInfoBubble(staticInfoBubbleId, true);
			}
			else
			{
			    var response = tricket_sendGetRequest(mapCommandUrl, 'cmd=loadHome&key=' + key);
    			
			    if(!response) return;
    			
			    if(response.length == 0)
			    {
				    alert(msgMissingHomePostition);
				    return false;
			    }
			    else if(response.indexOf('NOT AUTH') >= 0)
			    {
				    if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				    return false;
			    }
			    else if(response.indexOf('ERROR:') >= 0)
			    {
				    alert(response);
				    return false;
			    }

			    var params = response.split('$');
			    if(params.length != 4)
			    {
				    alert('ERROR: LoadHome got wrong number of parameters from server.');
				    return false;
			    }
    			
			    var newMapId = parseInt(params[0]);
			    
			    var mapChanged = null;
			    
			    if(newMapId >= 10000) mapChanged = (virtualMapId != newMapId);
			    else mapChanged = (mapId != newMapId);

			    if(mapChanged)
				    _eR();

// KartId$StartZoomnivå$StartMeterX$StartMeterY
    			
			    loadMap(newMapId);
    			
				_setZoomLevel(parseInt(params[1]));
				_scrollToMeter(parseInt(params[2]), parseInt(params[3]));

            }

			return true;
		}



		function _hasMapVariant(mapVar)
		{
			for(i = 0; i < mapVariants.length; i++)
			{
				if(mapVariants[i]._mapVariant == mapVar)
					return true;
			}
			return false;
		}
		

		function _setMapVariant(mapVar)
		{
			for(i = 0; i < mapVariants.length; i++)
			{
				if(mapVariants[i]._mapVariant == mapVar)
				{
					mapVariant = mapVar;
					variantPrefix = mapVariants[i]._variantPrefix;
					clearSegments();
					doRefresh(false);
					return true;
				}
			}
			return false;
		}
		


		function _getMapVariantArray()
		{
			return mapVariants;
		}		


		function _setZoomLevel(lvl)
		{
			if(lvl >= _minZoomLevel && lvl <= _maxZoomLevel)
			{
				_eSS();
				stopDecelerate();
				return loadZoomLevel(lvl);
			}
			return false;
		}

		function _zI()
		{
			if(_zoomLevel == _maxZoomLevel)
			{
				setDelayedStatus(msgMaxZoomLevelReached, 2000);
				return;
			}

            _eSS();
            stopDecelerate();
			
			loadZoomLevel(_zoomLevel + 1);
		}
		

		function _zO()
		{
			if(_zoomLevel == _minZoomLevel)
			{
				setDelayedStatus(msgMinZoomLevelReached, 2000);
				return;
			}

            _eSS();
            stopDecelerate();

			loadZoomLevel(_zoomLevel - 1);
		}
		
		function cancelKeyPress(e)
		{
		    if(isMouseOverMap) {
			    if(!e) e = window.event;
			    e.cancelBubble = true;
			    if (e.preventDefault) e.preventDefault();
			    if (e.stopPropagation) e.stopPropagation();
			    return false;
			}
			else
			    return true;
		}

		function setNormalEventState()
		{
            unRegAllEventHandlers();

			if(mapList) regEventHandler(mapList, 'change', mapSelected);
			if(routeList) regEventHandler(routeList, 'change', routeSelected);
			if(layerList) regEventHandler(layerList, 'change', layerSelected); 
			if(mapVariantList) regEventHandler(mapVariantList, 'change', mapVariantSelected);
			if(viewList) regEventHandler(viewList, 'change', viewSelected);

			if(colorList) regEventHandler(colorList, 'change', colorSelected);
			if(lineStyleList) regEventHandler(lineStyleList, 'change', lineStyleSelected);
			if(lineWeightList) regEventHandler(lineWeightList, 'change', lineWeightSelected);
			if(dotCheck) regEventHandler(dotCheck, 'change', dotSelected);

            regEventHandler(placeholder, 'mousemove', displayPointerDistance);
            regEventHandler(placeholder, 'mouseout', mouseOutFromMap);
            regEventHandler(placeholder, 'mousedown', beginScrollMap);
            regEventHandler(placeholder, 'dblclick', mapDblClick);
            regEventHandler(placeholder, 'click', mapLmbClick);

			if(enableDistanceMeasuring)
			    regEventHandler(placeholder, 'contextmenu', mapClick);
			else 
			    regEventHandler(placeholder, 'contextmenu', function() { return false; });
			if(isOpera())
			    regEventHandler(document, 'keypress', cancelKeyPress);
            regEventHandler(document, 'keydown', keyHandler);
			return true;
		}
		
		function mouseOutFromMap() { isMouseOverMap = false; }

		function setScrollingEventState()
		{
		    unRegAllEventHandlers();
            regEventHandler(document, 'mousemove', scrollMap);
            regEventHandler(document, 'mouseup', endScrollMap);
			return true;
		}
		
		function setDialogEventState()
		{
            unRegAllEventHandlers();
			return true;
		}

        function regEventHandlerAndForget(element, typeWithoutOn, funcRef)
        {
            if(element.addEventListener)
                element.addEventListener(typeWithoutOn, funcRef, false);
            else if(element.attachEvent)
                element.attachEvent('on' + typeWithoutOn, funcRef);
        }

        function regEventHandler(element, typeWithoutOn, funcRef)
        {
            if(isHandlerRegistered(element, typeWithoutOn, funcRef))
                return;

            if(element.addEventListener)
                element.addEventListener(typeWithoutOn, funcRef, false);
            else if(element.attachEvent)
                element.attachEvent('on' + typeWithoutOn, funcRef);

            var handler = new s_EventHandler();
            handler.element = element;
            handler.type = typeWithoutOn;
            handler.funcRef = funcRef;
            eventHandlers.push(handler);
        }

        function isHandlerRegistered(element, typeWithoutOn, funcRef)
        {
            for(i = 0; i < eventHandlers.length; i++)
            {
                if(eventHandlers[i].element == element && eventHandlers[i].type == typeWithoutOn && eventHandlers[i].funcRef == funcRef)
                    return true;
            }
            return false;
        }
        
        function unregEventHandler(element, typeWithoutOn, funcRef)
        {
            if(element.removeEventListener)
                element.removeEventListener(typeWithoutOn, funcRef, false);
            else if(element.detachEvent)
                element.detachEvent('on' + typeWithoutOn, funcRef);
                
            for(i = 0; i < eventHandlers.length; i++)
            {
                if(eventHandlers[i].element == element && eventHandlers[i].type == typeWithoutOn && eventHandlers[i].funcRef == funcRef)
                {
                    eventHandlers.splice(i, 1);
                    break;
                }
            }                
        }

        function unRegAllEventHandlers()
        {
            while(eventHandlers.length > 0)
            {
                var handler = eventHandlers.pop();
                unregEventHandler(handler.element, handler.type, handler.funcRef);
            }
        }

		function keyHandler(e)
		{
			if(!e) e = window.event;

			var theKey = e.which ? e.which : e.keyCode;

			if(isOpera() && theKey == 0) theKey = 46; //Delete button opera fix. Reliable?

			if(!isMouseOverMap)
			    return true;

			e.cancelBubble = true;
			if (e.preventDefault) e.preventDefault();
			if (e.stopPropagation) e.stopPropagation();
			
			switch(theKey)
			{
				case 32:
					createDot(null, cMX, cMY);
					break;
				case 8:
					_eLP();
					break;
				case 88:
					_eLP();
					break;
				case 120:
					_eLP();
					break;
				case 46:
					if(selectedObjectElem && selectedObjectElem.bubbleId)
					{
						if(confirm('Är du säker på att du vill ta bort objektet?'))
							deleteObject(selectedObjectElem.bubbleId);
					}
					break;
				case 37:
					_autoPanWest();
					break;
				case 39:
					_autoPanEast();
					break;
				case 38:
					_autoPanNorth();
					break;
				case 40:
					_autoPanSouth();
					break;
			}
			return false;
		}

		function beginScrollMap(e)
		{
			if(!e) e = window.event;
			
			var btn = e.button == null ? e.which : e.button;
			
			if(btn == 2) return false;

			deltaX = deltaY = lastMX = lastMY = 0;
			
			setScrollingEventState();

			_eSS();

			if(enableGlide) stopDecelerate();

			return false;
		}


		function scrollMap(e)
		{
			if(!e) e = window.event;

			var cur = getPosition(e);

			if(lastMX > 0 && lastMY > 0)
			{
				deltaX = cur.x - lastMX;
				deltaY = cur.y - lastMY;
			}
			
			// Max glide speed limit
			if(enableGlide) {
				if(Math.abs(deltaX) > 60) deltaX = 60 * (deltaX / Math.abs(deltaX)); 
				if(Math.abs(deltaY) > 60) deltaY = 60 * (deltaY / Math.abs(deltaY));
			}

			setPos(currentX - deltaX, currentY - deltaY, true);
						
			lastMX = cur.x;
			lastMY = cur.y;

			if(deltaTimer == null)
				deltaTimer = window.setInterval('deltaX = deltaY = 0;', 200);

			return false;
		}
		
		function doRefresh(loadAsync)
		{
			if(Math.abs(segmentDeltaX) > segmentWidth || Math.abs(segmentDeltaY) > segmentHeight || map.childNodes.length == 0)
			{
				setSegmentsInView(loadAsync);
				segmentDeltaX = segmentDeltaY = 0;
			}
		}

		function endScrollMap(e)
		{

			if(!e) e = window.event;

			window.clearInterval(deltaTimer);
			deltaTimer = null;

			if(!dialogElem)
				setNormalEventState();

			lastMX = lastMY = 0;
			
			if(enableGlide && (deltaX != 0 || deltaY != 0))
				startDecelerate();

			return false;
		}
		
		// decelerateMap
		function _dM()
		{
			setPos(currentX - deltaX, currentY - deltaY, true);
			
			if(Math.abs(deltaX) % 100 < 0.01 && Math.abs(deltaY) % 100 < 0.01) 
			{
				stopDecelerate();
				return;
			}
			deltaY -= deltaY * decelerateFactor;
			deltaX -= deltaX * decelerateFactor;
		}
		
		function startDecelerate()
		{
			stopDecelerate();
			decelerateTimer = window.setInterval('_dM();', decelerateInterval);
			return true;
		}
		function stopDecelerate()
		{
		    if(decelerateTimer == null) return;
			window.clearInterval(decelerateTimer);
			decelerateTimer = null;
			deltaX = deltaY = 0;

			return true;
		}
		
		function checkBoundaries()
		{
			var CurrentRT90West = p2mX(currentX) + geoWest;
			var CurrentRT90North = geoNorth - p2mY(currentY);
			var CurrentRT90East = CurrentRT90West + p2mX(viewPortWidth);
			var CurrentRT90South = CurrentRT90North - p2mY(viewPortHeight);

//			if(RT90NorthElem) RT90NorthElem.innerHTML = CurrentRT90North;
//			if(RT90WestElem) RT90WestElem.innerHTML = CurrentRT90West;
//			if(RT90SouthElem) RT90SouthElem.innerHTML = CurrentRT90South;
//			if(RT90EastElem) RT90EastElem.innerHTML = CurrentRT90East;

			if(m2pX(boundGeoEast - boundGeoWest) <= viewPortWidth)
			{
				currentX = m2pX((boundGeoWest - geoWest) + ((boundGeoEast - boundGeoWest) / 2)) - viewPortWidth / 2;
				deltaX = 0;
			}
			else
			{
				if(CurrentRT90West < boundGeoWest)
				{
					currentX = m2pX(boundGeoWest - geoWest);
					deltaX = 0;
				}
				else if(CurrentRT90East > boundGeoEast)
				{
					currentX = m2pX(boundGeoEast - geoWest) - viewPortWidth;
					deltaX = 0;
				}
			}

			if(m2pX(boundGeoNorth - boundGeoSouth) <= viewPortHeight)
			{
				currentY = m2pY((geoNorth - boundGeoNorth) + ((boundGeoNorth - boundGeoSouth) / 2))  - viewPortHeight / 2;
				deltaY = 0;
			}
			else
			{
				if(CurrentRT90North > boundGeoNorth)
				{
					currentY = m2pY(geoNorth - boundGeoNorth);
					deltaY = 0;
				}
				else if(CurrentRT90South < boundGeoSouth)
				{
					currentY = m2pY(geoNorth - boundGeoSouth) - viewPortHeight;
					deltaY = 0;
				}
			}
		}


		function _scrollTo(x, y)
		{
			setPos(x - viewPortWidth / 2, y - viewPortHeight / 2, false);
			return true;
		}
		
		function _scrollToMeter(mx, my)
		{
			_scrollTo(m2pX(mx), m2pY(my));
			return true;
		}


		function setPos(x, y, loadAsync)
		{
			if(currentX != null && currentY != null) 
			{
				segmentDeltaX += currentX - x;
				segmentDeltaY += currentY - y;
			}

			currentX = Math.round(x);
			currentY = Math.round(y);

			checkBoundaries();

			doRefresh(loadAsync);


			map.style.left = symbols.style.left = -currentX.toString() + 'px';
			map.style.top = symbols.style.top = -currentY.toString() + 'px';
			
			return true;
		}



		function initMap()
		{
			map.innerHTML = '';
			map.style.width =  symbols.style.width = mapWidth.toString() + 'px';
			map.style.height = symbols.style.height = mapHeight.toString() + 'px';

			if(mapWidth % segmentWidth != 0)  alert('The sum of the segment widths does not equal the map width.');
			if(mapHeight % segmentHeight != 0)  alert('The sum of the segment heights does not equal the map height.');

			segmentCountX = mapWidth / segmentWidth;
			segmentCountY = mapHeight / segmentHeight;

			countX = Math.ceil(viewPortWidth / segmentWidth) + 3;
			if(countX > segmentCountX) countX = segmentCountX;
			countY = Math.ceil(viewPortHeight / segmentHeight) + 3;
			if(countY > segmentCountY) countY = segmentCountY;

			mapNodeCount = countX * countY;

			mapCenterX = Math.floor(mapWidth / 2);
			mapCenterY = Math.floor(mapHeight / 2);

			setNormalEventState();

			return true;
		}
		



		function createSegment(addToNode, index)
		{
			var rowNumber = Math.floor(index / segmentCountX);
			var x = (index - rowNumber * segmentCountX) * segmentWidth;
			var y = rowNumber * segmentHeight;

			x += m2pX(zoomLevelMeterOffsetX);
			y += m2pY(zoomLevelMeterOffsetY);

			var xFolder = '';
			if(v2struktur == true)
			{
				// Fix: nedre v hörnet på varje tile är koordinaten som bestämmer dess mapp...
				xFolder = (geoNorth - (rowNumber * (segmentHeight * meterPerPixelY)) - (segmentHeight * meterPerPixelY)).toString().substr(0, 3);
			}

			if(segmentElemType == 'Bg')
			{
				var elem = document.createElement('div');
				if(v2struktur == true)
					elem.style.backgroundImage = 'url(' + baseSegmentPath + mapId.toString() + '/' + (mapVariant == null ? 'standard' : mapVariant) + '/' + _zoomLevel.toString() + '/' + xFolder + '/' + index.toString() + '.' + fileExtension + ')';
				else
					elem.style.backgroundImage = 'url(' + baseSegmentPath + mapId.toString() + '/' + (variantPrefix == null ? '' : variantPrefix) + (filePrefix == null ? '' : filePrefix) + mapId.toString() + _zoomLevel.toString() + index.toString() + '.' + fileExtension + ')';
			}
			else
			{
				var elem = document.createElement('img');
				if(v2struktur == true)
					elem.src = baseSegmentPath + mapId.toString() + '/' + (mapVariant == null ? 'standard' : mapVariant) + '/' + _zoomLevel.toString() + '/' + xFolder + '/' + index.toString() + '.' + fileExtension;				
				else
					elem.src = baseSegmentPath + mapId.toString() + '/' + (variantPrefix == null ? '' : variantPrefix) + (filePrefix == null ? '' : filePrefix) + mapId.toString() + _zoomLevel.toString() + index.toString() + '.' + fileExtension;
			}

			
			elem.style.position = 'absolute';
			elem.style.top = y.toString() + 'px';
			elem.style.left = x.toString() + 'px';
			elem.style.width = segmentWidth.toString() + 'px';
			elem.style.height = segmentHeight.toString() + 'px';
			elem.style.overflow = 'hidden';
			elem.style.zIndex = '2';
			elem.id = 'trseg' + index.toString();
			
			
			addToNode.appendChild(elem);

            regEventHandlerAndForget(elem, 'mousedown', function() { return false; });
//			elem.onmousedown = new Function("return false;");
			return elem;
		}
		
		
		function setSegmentsInView(loadAsync)
		{
			if(!loadAsync && tileLoaderTimer != null)
				killLoader();
		
			var xIdx = Math.floor(currentX / segmentWidth) - 1;
			if(xIdx < 0) xIdx = 0;

			var yIdx = Math.floor(currentY / segmentHeight) - 1;
			if(yIdx < 0) yIdx = 0;

			var firstIdx = yIdx * segmentCountX + xIdx;

			loadedSegmentIndexes = new Array();
			for(var y = 0; y < countY; y++)
			{
				var segIdx = firstIdx + (y * segmentCountX);
				for(var x = 0; x < countX; x++)
				{
					if(segIdx < (segmentCountX * segmentCountY)) {
						if(!loadAsync) {
							if(!document.getElementById('trseg' + segIdx.toString()))
								createSegment(map, segIdx);
						}
						loadedSegmentIndexes.push(segIdx);
						segIdx++;
					}
				}
			}
			
			if(loadAsync) {
				if(!tileLoaderTimer)
					tileLoaderTimer = window.setInterval('_tileLoader();', 1);
			}
			
			if(!gcTimer)
				gcTimer = window.setInterval('_gc();', 50);
		}
		
		function killLoader()
		{
			window.clearInterval(tileLoaderTimer);
			tileLoaderTimer = null;
		}

		function _tileLoader()
		{
			if(!loadedSegmentIndexes || loadedSegmentIndexes.length == 0)
				return;

			for(i = 0; i < loadBurst; i++) {
				if(tileCounter == loadedSegmentIndexes.length) {
					if(noneLoaded)
						killLoader();
					tileCounter = 0;
					noneLoaded = true;
				}

				if(!document.getElementById('trseg' + loadedSegmentIndexes[tileCounter].toString())) {
					createSegment(map, loadedSegmentIndexes[tileCounter]);
					noneLoaded = false;
				}
				tileCounter++;
			}
		}
		
		function _gc()
		{
		
			if(map.childNodes.length == 0 || map.childNodes.length == mapNodeCount)
			{
				window.clearInterval(gcTimer);
				gcTimer = null;
				return;
			}

			var isValid = false;
			for(i = 0; i < map.childNodes.length; i++)
			{
				for(j = 0; j < loadedSegmentIndexes.length; j++)
				{
					if(map.childNodes[i].id == 'trseg' + loadedSegmentIndexes[j].toString())
					{
						isValid = true;
						break;
					}
				}
				if(!isValid)
				{
					map.removeChild(map.childNodes[i]);
					break;
				}
				isValid = false;
			}
		}


		function clearSegments()
		{
			map.innerHTML = '';
		}


		function getPosition(e) {
			e = e || window.event;
			var retCursor = {x:0, y:0};
			if (e.pageX || e.pageY) {
				retCursor.x = e.pageX;
				retCursor.y = e.pageY;
			} 
			else {
				retCursor.x = e.clientX + 
					(document.documentElement.scrollLeft || 
					document.body.scrollLeft) - 
					document.documentElement.clientLeft;
				retCursor.y = e.clientY + 
					(document.documentElement.scrollTop || 
					document.body.scrollTop) - 
					document.documentElement.clientTop;
			}

			var p = placeholder;
			while(p)
			{
				retCursor.x -= p.offsetLeft;
				retCursor.y -= p.offsetTop;
				p = p.offsetParent;
			}
			retCursor.x -= (document.body.clientLeft == null ? 0 : document.body.clientLeft);
			retCursor.y -= (document.body.clientTop == null ? 0 : document.body.clientTop);
			
			return retCursor;
		}


		function mapClick(e)
		{
			if(!enableDistanceMeasuring)
				return false;

			if(!e) e = window.event;

			var cur = getPosition(e);
			createDot(null, currentX + cur.x, currentY + cur.y);

		    e.cancelBubble = true;
		    if (e.preventDefault) e.preventDefault();
		    if (e.stopPropagation) e.stopPropagation();
			
			return false;
		}

		function mapLmbClick(e)
		{
			if(!e) e = window.event;

			var cur = getPosition(e);
			var geoCur = getMouseGeoPosition(e);

			if(cancelMove == false && dialogElem == null)
			{
				if(selectedObjectElem)
				{
					if(confirm('Är du säker på att du vill flytta objektet?'))
					{
					    for(i = 0; i < infoBubbles.length; i++)
					    {
						    if(infoBubbles[i].infoBubbleId == selectedObjectElem.bubbleId)
						    {
							    infoBubbles[i].mX = p2mX(currentX + cur.x);
							    infoBubbles[i].mY = p2mY(currentY + cur.y);
							    infoBubbles[i].bubbleElem.style.left = (currentX + cur.x + infoBubbles[i].elemOffsX - 2).toString() + 'px';		// -2 on account of the border of the selected element
							    infoBubbles[i].bubbleElem.style.top = (currentY + cur.y + infoBubbles[i].elemOffsY - 2).toString() + 'px';
							    if(infoBubbles[i].shadowElem) infoBubbles[i].shadowElem.style.left = (currentX + cur.x + infoBubbles[i].shElemOffsX).toString() + 'px';
							    if(infoBubbles[i].shadowElem) infoBubbles[i].shadowElem.style.top = (currentY + cur.y + infoBubbles[i].shElemOffsY).toString() + 'px';
    							
							    updateObjectPosition(infoBubbles[i]);
    							
							    break;
						    }
					    }
					}
					else
					    unSelectObject();
				}
			}
			else
				cancelMove = false;


			if(onMapClick.length == 0)
				return true;

			_clickPixelX = currentX + cur.x;
			_clickPixelY = currentY + cur.y;
			_clickMeterX = p2mX(currentX + cur.x);
			_clickMeterY = p2mY(currentY + cur.y);
			_clickGeoX = geoCur.x;
			_clickGeoY = geoCur.y;

			eval(onMapClick);
			
			return true;
		}

		
		function mapDblClick(e)
		{
			if(!e) e = window.event;

			var cur = getPosition(e);

			if(doubleClickZooms == false || _zoomLevel == _maxZoomLevel)
			{
				_smoothScrollTo(currentX + cur.x, currentY + cur.y);
			}
			else
			{
				var mxTmp = p2mX(currentX + cur.x);
				var myTmp = p2mY(currentY + cur.y);
				_zI();
				_scrollToMeter(mxTmp, myTmp);
			}
			return false;
		}
		
		function getMouseGeoPosition(e)
		{
			var geoCursor = {x:0, y:0};
			var cur = getPosition(e);
			if(geoWest > 0) geoCursor.y = geoWest + p2mX(currentX + cur.x);
			if(geoNorth > 0) geoCursor.x = geoNorth - p2mY(currentY + cur.y);
			return geoCursor;
		}


		function _smoothScrollTo(px, py)
		{
			_eSS();
			var dx, dy;

			dx = px - (currentX + (viewPortWidth / 2));
			dy = py - (currentY + (viewPortHeight / 2));

			var speed = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)) / 50;
			var stepsX = Math.abs(dx) / speed;
			var stepsY = Math.abs(dy) / speed;

			

			if(Math.round(Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)).toString()) > maxSmoothScrollPixels)
			{
				_scrollTo(px, py);
				return;
			}
			
			smoothCoordsX = new Array();
			smoothCoordsY = new Array();
			
			var vx_step = (Math.PI / 2) / stepsX;
			var vy_step = (Math.PI / 2) / stepsY;
			
			var vx = Math.PI / 2;
			var vy = Math.PI / 2;
			
			while(vx >= 0)
			{
				smoothCoordsX.push(currentX + Math.floor(dx * Math.sin(vx)));
				vx -= vx_step;
			}
			
			while(vy >= 0)
			{
				smoothCoordsY.push(currentY + Math.floor(dy * Math.sin(vy)));
				vy -= vy_step;
			}

			smoothTimer = window.setInterval('_doSS();', smoothScrollInterval);

		}
		
		function _doSS()
		{
			var x, y;
			if(smoothCoordsX && smoothCoordsX.length > 0) x = smoothCoordsX.pop();
			else x = currentX;
			if(smoothCoordsY && smoothCoordsY.length > 0) y = smoothCoordsY.pop();
			else y = currentY;
		
			setPos(x, y, true);

			if(smoothCoordsX.length == 0 && smoothCoordsY.length == 0) 
				_eSS();
		}		
		
		// endSmoothScroll
		function _eSS()
		{
			if(smoothTimer == null)
				return;
			window.clearInterval(smoothTimer);
			smoothTimer = null;
			smoothCoordsX = null;
			smoothCoordsY = null;
		}


		function _autoPanNorth() { _pan('n', viewPortHeight); }
		function _autoPanSouth() { _pan('s', viewPortHeight); }
		function _autoPanWest() { _pan('w', viewPortWidth); }
		function _autoPanEast() { _pan('e', viewPortWidth); }
		function _autoPanNorthWest() { _pan('nw', viewPortHeight); }
		function _autoPanNorthEast() { _pan('ne', viewPortHeight); }
		function _autoPanSouthWest() { _pan('sw', viewPortWidth); }
		function _autoPanSouthEast() { _pan('se', viewPortWidth); }

		function _centerOnInfoBubble(id) { _centerOnInfoBubble(id, false); }
		function _centerOnInfoBubble(id, smooth)
		{
			for(i = 0; i < infoBubbles.length; i++) 
			{
				if(parseInt(infoBubbles[i].infoBubbleId) == parseInt(id))
				{
					var zoomWillChange = false;
					if(infoBubbles[i].zoomLevel != null && infoBubbles[i].zoomLevel != _zoomLevel)
						zoomWillChange = true;

					if(smooth == true && zoomWillChange == false)
						_smoothScrollTo(m2pX(infoBubbles[i].mX), m2pY(infoBubbles[i].mY));
					else
						_scrollTo(m2pX(infoBubbles[i].mX), m2pY(infoBubbles[i].mY));
					
					if(zoomWillChange == true)
						_setZoomLevel(infoBubbles[i].zoomLevel);

					if(enableObjectBlink)
						_blinkObject(id, blinkTime, 500);
					return;
				}
			}

			if(loadInfoBubble(id, null))
			{
				_centerOnInfoBubble(id, smooth);
			}

			return;
		}

		function _centerOnInfoBubbleExternalId(eid, smooth)
		{
			for(i = 0; i < infoBubbles.length; i++) 
			{
				if(infoBubbles[i].externalId == eid)
				{
					var zoomWillChange = false;
					if(infoBubbles[i].zoomLevel != null && infoBubbles[i].zoomLevel != _zoomLevel)
						zoomWillChange = true;

					if(smooth == true && zoomWillChange == false)
						_smoothScrollTo(m2pX(infoBubbles[i].mX), m2pY(infoBubbles[i].mY));
					else
						_scrollTo(m2pX(infoBubbles[i].mX), m2pY(infoBubbles[i].mY));
						
					if(zoomWillChange == true)
						_setZoomLevel(infoBubbles[i].zoomLevel);

					if(enableObjectBlink)
						_blinkObject(id, blinkTime, 500);
	
					return;
				}
			}

			if(loadInfoBubble(null, eid))
				_centerOnInfoBubbleExternalId(eid);

			return;
		}

		function _blinkObject(id, timeout, intervalTime)
		{
			_killBlink();
			blinkObject = document.getElementById('trobj' + id.toString());
			blinkShObject = document.getElementById('trobjsh' + id.toString());
			blinkSubTimer = window.setInterval('_doBlink();', intervalTime);
			blinkMainTimer = window.setTimeout('_killBlink();', timeout);
		}
		function _doBlink()
		{
			if(!blinkObject) { return; }
			if(blinkObject.style.visibility == 'hidden') {
				blinkObject.style.visibility = 'visible';
				if(blinkShObject) blinkShObject.style.visibility = 'visible';
			}
			else {
				blinkObject.style.visibility = 'hidden';
				if(blinkShObject) blinkShObject.style.visibility = 'hidden';
			}
		}
		function _killBlink()
		{
			if(blinkObject) blinkObject.style.visibility = 'visible';
			if(blinkShObject) blinkShObject.style.visibility = 'visible';
			blinkObject = blinkShObject = null;
			window.clearInterval(blinkSubTimer);
			blinkSubTimer = null;
			window.clearTimeout(blinkMainTimer);
			blinkMainTimer = null;
		}
		

		function _pan(dir, pix)
		{
			_eSS();
			
			if(dir == 'n')
				_smoothScrollTo(currentX + (viewPortWidth / 2), currentY + (viewPortHeight / 2) - pix);
			else if(dir == 's')
				_smoothScrollTo(currentX + (viewPortWidth / 2), currentY + (viewPortHeight / 2) + pix);
			else if(dir == 'w')
				_smoothScrollTo(currentX + (viewPortWidth / 2) - pix, currentY + (viewPortHeight / 2));
			else if(dir == 'e')
				_smoothScrollTo(currentX + (viewPortWidth / 2) + pix, currentY + (viewPortHeight / 2));
			else if(dir == 'nw')
				_smoothScrollTo(currentX + (viewPortWidth / 2) - pix, currentY + (viewPortHeight / 2) - pix);
			else if(dir == 'ne')
				_smoothScrollTo(currentX + (viewPortWidth / 2) + pix, currentY + (viewPortHeight / 2) - pix);
			else if(dir == 'sw')
				_smoothScrollTo(currentX + (viewPortWidth / 2) - pix, currentY + (viewPortHeight / 2) + pix);
			else if(dir == 'se')
				_smoothScrollTo(currentX + (viewPortWidth / 2) + pix, currentY + (viewPortHeight / 2) + pix);
							
		}

		function initMapCalc()
		{
			pointerDistanceOutput = document.getElementById(mapPointerDistanceOutputElemId);
			distanceOutput = document.getElementById(mapDistanceOutputElemId);
			statusOutput = document.getElementById(mapStatusOutputElemId);

			return true;
		}
		

		function getRouteLineElem(addToNode, x, y, toX, toY, color, weight, style)
		{
			if(color == null) color = routeLineColor;
			if(weight == null) weight = routeLineWeight;
			if(style == null) style = routeLineStyle;
			
            var ln = document.createElement('div');
            ln.style.position = 'absolute';
            ln.style.backgroundRepeat = 'no-repeat';
            ln.style.backgroundImage = 'url(' + lineHandlerUrl + '?x1=' + x.toString() + '&x2=' + toX.toString() + '&y1=' + y.toString() + '&y2=' + toY.toString() + '&w=' + weight.toString() +'&c=' + escape(color) + '&ls=' + style + ')';

            ln.style.width = (Math.abs(x - toX) + weight).toString() + 'px';
            ln.style.height = (Math.abs(y - toY) + weight).toString() + 'px';
            if(x >= toX) ln.style.left = toX.toString() + 'px';
            else ln.style.left = x.toString() + 'px';
            if(y >= toY) ln.style.top = toY.toString() + 'px';
            else ln.style.top = y.toString() + 'px';
            addToNode.appendChild(ln);
            return ln;
		}

        function reCalcLine(ln, x, y, toX, toY, color, weight, style)
        {
			if(color == null) color = routeLineColor;
			if(weight == null) weight = routeLineWeight;
			if(style == null) style = routeLineStyle;

            ln.style.backgroundImage = 'url(' + lineHandlerUrl + '?x1=' + x.toString() + '&x2=' + toX.toString() + '&y1=' + y.toString() + '&y2=' + toY.toString() + '&w=' + weight.toString() +'&c=' + escape(color) + '&ls=' + style + ')';
            ln.style.width = (Math.abs(x - toX) + routeLineWeight).toString() + 'px';
            ln.style.height = (Math.abs(y - toY) + routeLineWeight).toString() + 'px';
            if(x >= toX) ln.style.left = toX.toString() + 'px';
            else ln.style.left = x.toString() + 'px';
            if(y >= toY) ln.style.top = toY.toString() + 'px';
            else ln.style.top = y.toString() + 'px';
        }

		function createDot(routeObj, x, y)
		{
			var dot = new s_Dot();
			dot.mX = p2mX(x);
			dot.mY = p2mY(y);

			if((routeObj == null && enableDots == true) || (routeObj != null && (routeObj.routeDots == true || enableRouteLines == false)))
				dot.elem = createDotElement(symbols, x, y);
				
			var routeTmp = null;

			if(routeObj == null)
				routeTmp = route;
			else
				routeTmp = routeObj.route;

			if(!routeTmp) {
				route = new Array();
				routeTmp = route;
			}

			if(routeTmp && enableRouteLines && routeTmp.length > 0) {
                routeTmp[routeTmp.length - 1].lineElem = getRouteLineElem(symbols, m2pX(routeTmp[routeTmp.length - 1].mX), m2pY(routeTmp[routeTmp.length - 1].mY), x, y, (routeObj == null ? null : routeObj.routeColor), (routeObj == null ? null : routeObj.routeWeight), (routeObj == null ? null : routeObj.routeStyle));
                if(routeObj && routeObj.distance)
	                routeTmp[routeTmp.length - 1].lineElem.title = routeObj.routeName + '\r\n' + routeObj.routeDistance.toString() + 'm';
			}

			
			routeTmp.push(dot);
			
			if(distanceOutput) distanceOutput.innerHTML = calculateRouteDistance();
			if(pointerDistanceOutput) pointerDistanceOutput.innerHTML = calculatePointerDistance(x, y);

		}
		


		function createMeterDot(routeObj, mx, my)
		{
			createDot(routeObj, m2pX(mx), m2pY(my));		
		}
		

		var markerElem = null;
		function _createMarker(x, y)
		{
			if(markerElem) symbols.removeChild(markerElem);
			markerElem = createDotElement(symbols, x, y);
		}
		function _createMeterMarker(mx, my)
		{
			_createMarker(m2pX(mx), m2pY(my));
		}



		function createDotElement(addToNode, x, y)
		{
			var dot = document.createElement('span');
			addToNode.appendChild(dot);
			dot.style.backgroundRepeat = 'no-repeat';
			dot.style.backgroundImage = 'url(' + dotImageUrl + ')';
			dot.style.width = dotWidth.toString() + 'px';
			dot.style.height = dotHeight.toString() + 'px';
			dot.style.position = 'absolute';
			dot.style.left = (x + dotOffsetX).toString() + 'px';
			dot.style.top = (y + dotOffsetY).toString() + 'px';
			dot.style.zIndex = '3';
			return dot;
		}
		


		function calculateRouteDistance()
		{
			if(route == null && routeArray == null)
				return;

			var visCount = 0;
			var rt = null;
			
			if(route == null && routeArray != null) {
				for(i = 0; i < routeArray.length; i++) {
					if(routeArray[i].routeVisible == true) {
						visCount++;
						if(visCount == 1)
							rt = routeArray[i].route;
						else if(visCount > 1) {
							rt = null;
							break;
						}
					}
				}
			}
			if(rt == null) rt = route;
			if(rt == null) return 0;
			
			var i = 0;
			var j = 0;
			var a, b;
			var distance = 0;

			for(i = 1; i < rt.length; i++) 
			{
				a = Math.pow(rt[i].mX - rt[j].mX, 2);
				b = Math.pow(rt[i].mY - rt[j].mY, 2);
				distance = distance + Math.sqrt(a + b);
				j++;
			}

			return Math.round(distance);
		}
		


		function calculatePointerDistance(px, py)
		{
			if(route == null || route.length == 0)
				return 0;

			var a = Math.pow(route[route.length - 1].mX - p2mX(px), 2);
			var b = Math.pow(route[route.length - 1].mY - p2mY(py), 2);

			return Math.round(Math.sqrt(a + b))
		}
		
		
		
		function displayPointerDistance(e)
		{
			if(!e) e = window.event;
			var cur = getPosition(e);

			// Save mouse position for keypress events in placeholder:
			cMX = currentX + cur.x;
			cMY = currentY + cur.y;

			isMouseOverMap = true;
			
			if(route == null || route.length == 0)
				return;

			if(pointerDistanceOutput) pointerDistanceOutput.innerHTML = calculatePointerDistance(currentX + cur.x, currentY + cur.y);

			return true;
		}
		


		function _eLP()
		{
			if(route == null || route.length == 0)
				return;

			if(route[route.length - 1].elem)
				symbols.removeChild(route[route.length - 1].elem);
			
			if(enableRouteLines && route.length >= 2) 
			{
    			symbols.removeChild(route[route.length - 2].lineElem);
    			route[route.length - 2].lineElem = null;
    		}
			route.pop();
			
			if(pointerDistanceOutput) pointerDistanceOutput.innerHTML = '0';
			if(distanceOutput) distanceOutput.innerHTML = calculateRouteDistance();

			return true;
		}


		function clearRoute(routeObj)
		{
			if(routeObj == null)
				return;
			for(var i = routeObj.length - 1; i >= 0; i--)
			{
				if(routeObj[i].elem) symbols.removeChild(routeObj[i].elem);
				if(enableRouteLines && routeObj.length >= 1)
				{
					if(routeObj[i] && routeObj[i].lineElem != null)
						symbols.removeChild(routeObj[i].lineElem);
				}
				routeObj.pop();
			}
		}
		
		function clearAllRoutes()
		{
			for(var i = 0; i < routeArray.length; i++)
			{
				if(routeArray[i].routeVisible == true)
				{
		
					clearRoute(routeArray[i].route);
					routeArray[i].routeVisible = false;
				}
			}
			_syncRouteChecks();

		}


		function _eR() // Erase Route
		{
			var reloadBubbles = false;

			if(routeId != null) {
				reloadBubbles = true;
				for(var i = 0; i < routeArray.length; i++) {
					if(routeArray[i].routeId == routeId) {
						routeArray[i].routeVisible = false;
						break;
					}
				}
			}

			routeId = null;
			_routeName = null;
			_routeDescription = null;
			_routePublic = null;

			if(reloadBubbles)
				loadInfoBubbles();

			if(!route) return false;
				
			clearRoute(route);

			if(pointerDistanceOutput) pointerDistanceOutput.innerHTML = '0';
			if(distanceOutput) distanceOutput.innerHTML = '0';	

			_syncRouteChecks();

			return true;
		}

		function reRenderInfoBubbles()
		{
			if(!infoBubbles)
				return;
				
			for(i = 0; i < infoBubbles.length; i++)
			{
				infoBubbles[i].bubbleElem.style.left = (m2pX(infoBubbles[i].mX) + infoBubbles[i].elemOffsX).toString() + 'px';
				infoBubbles[i].bubbleElem.style.top = (m2pY(infoBubbles[i].mY) + infoBubbles[i].elemOffsY).toString() + 'px';
				if(infoBubbles[i].shadowElem != null)
				{
					infoBubbles[i].shadowElem.style.left = (m2pX(infoBubbles[i].mX) + infoBubbles[i].shElemOffsX).toString() + 'px';
					infoBubbles[i].shadowElem.style.top = (m2pY(infoBubbles[i].mY) + infoBubbles[i].shElemOffsY).toString() + 'px';
				}
			}
		}


		function reRenderRouteObj(routeObj)
		{
			var routeTmp = null;
			if(routeObj == null) routeTmp = route;
			else routeTmp = routeObj.route;
			for(i = 0; i < routeTmp.length; i++)
			{
				if(routeObj != null && routeObj.routeDots == false && routeTmp[i].elem) {
					symbols.removeChild(routeTmp[i].elem);
					routeTmp[i].elem = null;
				}
				else if(routeTmp[i].elem) 
				{
					routeTmp[i].elem.style.left = (m2pX(routeTmp[i].mX) + dotOffsetX).toString() + 'px';
					routeTmp[i].elem.style.top = (m2pY(routeTmp[i].mY) + dotOffsetY).toString() + 'px';
				}	
				
				if(enableRouteLines && i < routeTmp.length - 1)
    				reCalcLine(routeTmp[i].lineElem, m2pX(routeTmp[i].mX), m2pY(routeTmp[i].mY), m2pX(routeTmp[i+1].mX), m2pY(routeTmp[i+1].mY), (routeObj == null ? null : routeObj.routeColor), (routeObj == null ? null : routeObj.routeWeight), (routeObj == null ? null : routeObj.routeStyle));
			}
		}

		function reRenderRoute()
		{
			if(route && routeId == null) reRenderRouteObj(null);
			for(var i = 0; i < routeArray.length; i++)
				if(routeArray[i].routeVisible) {
					reRenderRouteObj(routeArray[i]);
				}


		}

		function p2mX(p) { return p * meterPerPixelX; }
		function p2mY(p) { return p * meterPerPixelY; }
    	function m2pX(m) { return Math.round(m / meterPerPixelX); }
		function m2pY(m) { return Math.round(m / meterPerPixelY); }


		function setStatus(s)
		{
			if(statusOutput) statusOutput.innerHTML = s;
			if(onStatusSet.length > 0) eval(onStatusSet);
			return true;
		}



		var statusTimer = null;
		function setDelayedStatus(s, interval)
		{
			_clrS();
			setStatus(s);
			statusTimer = window.setTimeout('_clrS();', interval);
			return true;
		}



		function _clrS()
		{
			setStatus('');
			window.clearTimeout(statusTimer);
			if(onStatusCleared.length > 0) eval(onStatusCleared);
			return true;
		}
		
		
		//CHARSAFE
		function _sR()
		{
			var coords = new String();
			for(i = 0; i < route.length; i++)
				coords = coords.concat(route[i].mX + ',' + route[i].mY + ',');
			coords = coords.substr(0, coords.length - 1);
			
			var nameElem = document.getElementById('RouteNameText');
			var descElem = document.getElementById('RouteDescriptionText');
			var publicElem = document.getElementById('RoutePublicCheck');
			var routeLineColorElem = document.getElementById('RouteLineColorList');
			var routeLineStyleElem = document.getElementById('RouteLineStyleList');
			var routeLineWeightElem = document.getElementById('RouteLineWeightList');
			var routeLineDotsElem = document.getElementById('RouteLineDotCheck');

			var overwrite = checkOverwrite();

			if(nameElem.value.length == 0)
			{
				alert(msgMissingRouteName);
				return;
			}
			
			var cmdString = 'cmd=saveroute';
			cmdString += '&mapid=' + mapId;
			cmdString += '&routeid=' + (overwrite ? routeId.toString() : '');
			cmdString += '&distance=' + calculateRouteDistance();
			cmdString += '&public=' + (publicElem && publicElem.checked ? 'true' : 'false');
			cmdString += '&name=' + encode64(nameElem.value);
			cmdString += '&description=' + (descElem == null ? '' : encode64(descElem.value));
			cmdString += '&startx=' + Math.floor(p2mX(-currentX));
			cmdString += '&starty=' + Math.floor(p2mY(-currentY));
			cmdString += '&data=' + coords;
			cmdString += '&color=' + (routeLineColorElem == null ? routeLineColor : routeLineColorElem.value);
			cmdString += '&style=' + (routeLineStyleElem == null ? routeLineStyle : routeLineStyleElem.value);
			cmdString += '&weight=' + (routeLineWeightElem == null ? routeLineWeight : routeLineWeightElem.value);
			cmdString += '&dots=' + (routeLineDotsElem == null ? enableDots.toString() : routeLineDotsElem.checked.toString());
			cmdString += '&private=' + savePrivateRoutes.toString();
			cmdString += '&key=' + key;
			
			var response = tricket_sendPostRequest(mapCommandUrl, cmdString);

			if(!response) return;

			if(response.indexOf('NOT AUTH') >= 0)
			{
				if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				return false;
			}
			if(response.indexOf('ERROR:') >= 0)
				alert(response);
			else
			{
				_routeName = nameElem.value;
				_routeDescription = (descElem == null ? '' : descElem.value);
				_routePublic = (publicElem && publicElem.checked ? 'true' : 'false');
				
				setDelayedStatus(msgRouteSaved, 2000);
				routeId = parseInt(response);
				var routeIdTemp = routeId;
				
				populateRouteList(response);
				_eR();
				_setRoute(true, routeIdTemp);
				reRenderRoute();
				
				if(onRouteSaved.length > 0) eval(onRouteSaved);
				_syncRouteChecks();
			}
			_cancel();
		}
		
		function _sH() // Save home
		{
			var cmdString = 'cmd=saveHome';
			cmdString += '&mapid=' + mapId;
			cmdString += '&zoomlevel=' + _zoomLevel;
			cmdString += '&startx=' + Math.floor(p2mX(currentX + viewPortWidth / 2 + document.body.scrollLeft));
			cmdString += '&starty=' + Math.floor(p2mY(currentY + viewPortHeight / 2 + document.body.scrollTop));
			cmdString += '&key=' + key;
			
			var response = tricket_sendPostRequest(mapCommandUrl, cmdString);
			
			if(!response) return;
			
			if(response.indexOf('NOT AUTH') >= 0)
			{
				if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				return false;
			}
			if(response.indexOf('ERROR:') >= 0)
				alert(response);
			else
			{
				setDelayedStatus(msgHomePositionSaved, 2000);
			}
		}

		
		function removeDialog()
		{
			if(dialogElem)
			{
				dialogContainerElem.removeChild(dialogElem);
				dialogElem = null;
			}
		}
		
		function _cancel()
		{ 
			if(infoBubbles.length > 0 && infoBubbles[infoBubbles.length - 1].infoBubbleId == null) infoBubbles.pop();
			removeDialog();
			setNormalEventState(); 
		}
		
		function createDialog()
		{
			removeDialog();
			var dlgElem = document.createElement('div');
			dialogContainerElem.appendChild(dlgElem);
			dlgElem.style.position = 'relative';
			dlgElem.style.width = viewPortWidth.toString() + 'px';
			dlgElem.style.height = viewPortHeight.toString() + 'px';
			dlgElem.style.zIndex = '50';
			
			setDialogEventState();
			return dlgElem;
		}

		function initOverwritePanel(theId)
		{
			var owPnl = document.getElementById('OverwritePanel');
			if(owPnl && !theId)
			{
				owPnl.style.visibility = 'hidden';
				owPnl.style.display = 'none';
			}
			else if(owPnl)
			{
				owPnl.style.visibility = 'visible';
				owPnl.style.display = '';
			}
		}
		
		function checkOverwrite()
		{
			var overwriteElem = document.getElementById('OverwriteCheck');
			if(overwriteElem && overwriteElem.checked) return true;
			else return false;
		}
		
		function _sSRD()
		{
			if(!route || route.length < 2)
			{
				alert(msgMissingPoints);
				return;
			}
			dialogElem = createDialog();
			dialogElem.innerHTML = saveRouteDialogHtml;

			var routeLineColorElem = document.getElementById('RouteLineColorList');
			var routeLineStyleElem = document.getElementById('RouteLineStyleList');
			var routeLineWeightElem = document.getElementById('RouteLineWeightList');
			var routeLineDotsElem = document.getElementById('RouteLineDotCheck');
			if(routeLineColorElem && colorList) routeLineColorElem.value = colorList.value;
			if(routeLineStyleElem && lineStyleList) routeLineStyleElem.value = lineStyleList.value;
			if(routeLineWeightElem && lineWeightList) routeLineWeightElem.value = lineWeightList.value;
			if(routeLineDotsElem && dotCheck) routeLineDotsElem.checked = dotCheck.checked;
			
			initOverwritePanel(routeId);
			
			if(routeId)
			{
				var nameElem = document.getElementById('RouteNameText');
				var descElem = document.getElementById('RouteDescriptionText');
				var publicElem = document.getElementById('RoutePublicCheck');
				
				if(nameElem) nameElem.value = _routeName;
				if(descElem) descElem.value = (_routeDescription == null ? '' : _routeDescription);
				if(publicElem) publicElem.checked = _routePublic;
				
				for(var i = 0; i < routeArray.length; i++)
					if(routeArray[i].routeId == routeId)
						break;
				
				if(routeLineColorElem && routeArray[i].routeColor != null) routeLineColorElem.value = routeArray[i].routeColor;
				if(routeLineStyleElem && routeArray[i].routeStyle != null) routeLineStyleElem.value = routeArray[i].routeStyle;
				if(routeLineWeightElem && routeArray[i].routeWeight != null) routeLineWeightElem.value = routeArray[i].routeWeight;
				if(routeLineDotsElem && routeArray[i].routeDots != null) routeLineDotsElem.checked = routeArray[i].routeDots;
			}
			
		}
	
		// ShowInfo
		function _sI()
		{
			dialogElem = createDialog();
			var str = new String();
			dialogElem.innerHTML = mapInfoDialogHtml.replace(/\$mapname/g, _mapName).replace(/\$mapdescription/g, (_mapDescription == null ? '' : _mapDescription)).replace(/\$routename/g, (_routeName == null ? '' : _routeName)).replace(/\$routecreatedby/g, (_routeCreatedBy == null ? '' : _routeCreatedBy)).replace(/\$routedescription/g, (_routeDescription == null ? '' : _routeDescription));

		}

		function _sSLD()
		{
			dialogElem = createDialog();
			dialogElem.innerHTML = saveLayerDialogHtml;

			if(layerId)
			{
				var nameElem = document.getElementById('LayerNameText');
				var descElem = document.getElementById('LayerDescriptionText');
				
				if(nameElem) nameElem.value = _layerName;
				if(descElem) descElem.value = _layerDescription;
			}

			initOverwritePanel(layerId);
		}


		// SaveViewDialog
		function _sSVD()
		{
			dialogElem = createDialog();
			dialogElem.innerHTML = saveViewDialogHtml;

			initOverwritePanel(viewId);

			if(viewId) 
			{
				var nameElem = document.getElementById('ViewNameText');
				var descElem = document.getElementById('ViewDescriptionText');
				
				if(nameElem) nameElem.value = _viewName;
				if(descElem) descElem.value = _viewDescription;
			}
			
		}

		
		function _sHlp() // Show help
		{
			dialogElem = createDialog();
			dialogElem.innerHTML = helpDialogHtml;
		}
		

		function showSaveInfoBubbleDialog()
		{
			dialogElem = createDialog();
			dialogElem.innerHTML = saveObjectDialogHtml;

			var infoBubbleBelongsGr = document.getElementsByName('ObjectBelongsGroup');
			if(infoBubbleBelongsGr && infoBubbleBelongsGr.length > 0)
			{
				if(!routeId) infoBubbleBelongsGr[1].disabled = true; 
				else infoBubbleBelongsGr[1].disabled = false;
				
				if(!layerId) infoBubbleBelongsGr[2].disabled = true;
				else infoBubbleBelongsGr[2].disabled = false;
				
//				if(layerId) infoBubbleBelongsGr[2].checked = true;
//				else if(routeId) infoBubbleBelongsGr[1].checked = true;
//				else infoBubbleBelongsGr[0].checked = true;

			}
			populateSymbolList();
			populateObjectCategoryList();
		}
		

		function populateObjectCategoryList()
		{
			var catList = document.getElementById('ObjectCategoryList');
			if(!catList) return;
			var response = tricket_sendGetRequest(mapCommandUrl, 'cmd=objectcategorylist&key=' + key);
			if(response.indexOf('NOT AUTH') >= 0)
			{
				if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				return false;
			}
			if(response.indexOf('ERROR:') >= 0)
			{
				alert(response);
				return;
			}
			populateSelect(catList, response, 'Okategoriserad', null);

		}


		function populateSymbolList()
		{
			var symbolList = document.getElementById('ObjectSymbolList');
			if(!symbolList) return;
			var response = tricket_sendGetRequest(mapCommandUrl, 'cmd=symbollist&key=' + key);
			if(!response) return;
			if(response.indexOf('NOT AUTH') >= 0)
			{
				if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				return false;
			}
			if(response.indexOf('ERROR:') >= 0)
			{
				alert(response);
				return;
			}

			populateSelect(symbolList, response, null, _preSelectedSymbol);
		}


		function _rR()
		{
			var layerIdString = new String();
			var routeIdString = new String();

			if(layerArray) 
			{
				for(i = 0; i < layerArray.length; i++)
					if(layerArray[i].layerVisible)
						layerIdString += layerArray[i].layerId + ',';

				if(layerIdString.length > 0)
					layerIdString = layerIdString.substr(0, layerIdString.length - 1);
			}
			else if(layerId)
				layerIdSring = layerId.toString();

//			if(routeId)
//				routeIdString = routeId.toString() + ',';
			if(routeArray) 
			{
				for(i = 0; i < routeArray.length; i++)
					if(routeArray[i].routeVisible)
						routeIdString += routeArray[i].routeId + ',';
			}
			if(routeIdString.length > 0)
				routeIdString = routeIdString.substr(0, routeIdString.length - 1);

					
			var uri = printPageUrl + '?id=' + mapId.toString() + '&key=' + key + '&r=' + routeIdString + '&l=' + layerIdString + '&m=' + _distMarkerEvery.toString() + '&z=' + _zoomLevel.toString() + '&v=' + (viewId == null ? '' : viewId.toString()) + '&rsize=' + routeSetsRenderArea.toString() + '&mx=' + Math.floor(p2mX(currentX)).toString() + '&my=' + Math.floor(p2mY(currentY)).toString() + '&vpwm=' + Math.floor(p2mX(viewPortWidth)).toString() + '&vphm=' + Math.floor(p2mY(viewPortHeight)).toString() + '&always=' + (alwaysVisibleList == null ? '' : escape(alwaysVisibleList));
			window.open(uri, 'printMap', 'location=yes,resizable=yes,scrollbars=yes,top=10,left=10,width=' + RENDERPOPUPWIDTH.toString() + ',height=' + RENDERPOPUPHEIGHT.toString());
		}

		function _rRStrict(imgWidth, imgHeight)
		{
			var layerIdString = new String();
			var routeIdString = new String();

			if(layerArray) 
			{
				for(i = 0; i < layerArray.length; i++)
					if(layerArray[i].layerVisible)
						layerIdString += layerArray[i].layerId + ',';

				if(layerIdString.length > 0)
					layerIdString = layerIdString.substr(0, layerIdString.length - 1);
			}
			else if(layerId)
				layerIdSring = layerId.toString();
			if(routeArray) 
			{
				for(i = 0; i < routeArray.length; i++)
					if(routeArray[i].routeVisible)
						routeIdString += routeArray[i].routeId + ',';
			}
			if(routeIdString.length > 0)
				routeIdString = routeIdString.substr(0, routeIdString.length - 1);

			var RT90Y = p2mX(currentX + (viewPortWidth / 2)) + geoWest;
			var RT90X = geoNorth - p2mY(currentY + (viewPortHeight / 2));
					
			var uri = printPageUrl + '?m=' + mapId.toString() + '&u=' + key + '&r=' + routeIdString + '&l=' + layerIdString + '&d=' + _distMarkerEvery.toString() + '&z=' + _zoomLevel.toString() + '&v=' + (viewId == null ? '' : viewId.toString()) + '&x=' + Math.floor(RT90X).toString() + '&y=' + Math.floor(RT90Y).toString() + '&w=' + imgWidth.toString() + '&h=' + imgHeight.toString() + '&o=' + (alwaysVisibleList == null ? '' : escape(alwaysVisibleList));
			window.open(uri, 'printMap', 'menubar=no,status=no,toolbar=no,scrollbars=yes,resizable=yes,width=' + RENDERPOPUPWIDTH.toString() + ',height=' + RENDERPOPUPHEIGHT.toString());
		}


		// ***********************************************************************************************************
		// ***********************************************************************************************************
		// *** INFO BUBBLE
		// ***********************************************************************************************************
		// ***********************************************************************************************************

		var tempBubbleId = -1;

		var infoBubbles = null;

		// InfoBubble 'struct'
		function s_InfoBubble() {
			var infoBubbleId = null;
			var categoryId = null;
			var mapId = null;
			var routeId = null;
			var mX = null;
			var mY = null;
			var title = '';
			var description = null;
			var numbered = null;
			var linkUrl = null;
			var linkTitle = null;
			var fileUrl = null;
			var fileTitle = null;
			var shElemOffsX = 0;
			var shElemOffsY = 0;
			var elemOffsX = 0;
			var elemOffsY = 0;
			var bubbleElem = null;
			var shadowElem = null;
			var externalId = null;
			var symbolId = null;

			var breadText = null;
			var img1Url = null;
			var img1Alt = null;
			var img1LinkUrl = null;
			var img2Url = null;
			var img2Alt = null;
			var img2LinkUrl = null;
			var templateId = null;
			var showExtended = null;
			var zoomLevel = null;
		}

		function initInfoBubbles()
		{
			infoBubbles = new Array();
		}

		function _bIB() // beginInfoBubble
		{
			if(selectedObjectElem)
			{
				showSaveInfoBubbleDialog();

				for(i = 0; i < infoBubbles.length; i++)
				{
					if(infoBubbles[i].infoBubbleId == selectedObjectElem.bubbleId)
					{
						var titleElem = document.getElementById('ObjectTitleText');
						var descElem = document.getElementById('ObjectDescriptionText');
						var extidElem = document.getElementById('ExternalIdText');
						var categoryElem = document.getElementById('ObjectCategoryList');
						var symbolElem = document.getElementById('ObjectSymbolList');
						var belongsElem = document.getElementsByName('ObjectBelongsGroup');
						var numberedElem = document.getElementById('ObjectNumberedCheck');
						var infoBubbleLinkElem = document.getElementById('ObjectLinkText');
						var infoBubbleLinkTitleElem = document.getElementById('ObjectLinkTitleText');
						
						if(titleElem) titleElem.value = infoBubbles[i].title;
						if(descElem) descElem.value = infoBubbles[i].description.replace(/<br \/>/g, '\r\n');
						if(extidElem) extidElem.value = infoBubbles[i].externalId;
						if(categoryElem && infoBubbles[i].categoryId) categoryElem.value = infoBubbles[i].categoryId;
						if(symbolElem) symbolElem.value = infoBubbles[i].symbolId;
						if(numberedElem) numberedElem.checked = infoBubbles[i].numbered; //(infoBubbles[i].numbered == 'true' ? true : false);
						if(infoBubbleLinkElem) infoBubbleLinkElem.value = infoBubbles[i].linkUrl;
						if(infoBubbleLinkTitleElem) infoBubbleLinkTitleElem.value = infoBubbles[i].linkTitle;
						
						// Kartan, Rutten, Lagret
						// Om rutt laddad och ruttid i objekt satt, ruttradio = checked
						// Om laddat lager och objektet tillhör lagret, lagerradio = checked
						// Annars kartaradio = checked
						
						if(routeId && infoBubbles[i].routeId == routeId)
						    belongsElem[1].checked = true;
						else if(layerId && objectBelongsToLayer(infoBubbles[i].infoBubbleId, layerId))
						    belongsElem[2].checked = true;
						else
						    belongsElem[0].checked = true;
						
						break;
					}
				}
			}
			else
			{
			    unRegAllEventHandlers();
			    regEventHandler(placeholder, 'mousedown', doInfoBubble);
				setStatus(msgClickMap);
			}
		}
		
		function objectBelongsToLayer(oId, lId)
		{
			var cmdString = 'cmd=objectbelongstolayer';
			cmdString += '&id=' + oId.toString();
			cmdString += '&l=' + lId.toString();
			cmdString += '&key=' + key;
			
			response = tricket_sendPostRequest(mapCommandUrl, cmdString);
			if(response.indexOf('NOT AUTH') >= 0)
			{
				if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				return false;
			}
			if(response.indexOf('ERROR:') >= 0)
			{
				alert(response);
				return false;
			}
			
			if(response.toLowerCase() == 'true') return true;
			else return false;
		}
		
		function doInfoBubble(e)
		{
			if(!e) e = window.event;
			_clrS();
			
			var cur = getPosition(e);
			createBubble(currentX + cur.x, currentY + cur.y);
			
			showSaveInfoBubbleDialog();
		}
		

		function createBubble(x, y)
		{
			var bubble = new s_InfoBubble();
			bubble.mX = p2mX(x);
			bubble.mY = p2mY(y);
			bubble.mapId = mapId;			
			bubble.routeId = routeId;

			infoBubbles.push(bubble);
			
			return bubble;
		}



		function displayBubbleText(e)
		{
			if(disableObjectPopups == true)
				return;
				
			if(!e) e = window.event;

			var srcBubble = null;
			if(e.target) srcBubble = e.target;
			else if(e.srcElement) srcBubble = e.srcElement;

//			if(currentlyDisplayedId == srcBubble.bubbleId) 
//			{
//				hideBubbleText();
//				return;
//          }
//else 
            if(currentlyDisplayedId != null)
				hideBubbleText();

//			var cur = getPosition(e);
			if(infoDisplayDelay && infoDisplayDelay > 0)
				displayTimer = window.setTimeout('_doDisplayBubbleText(' + (srcBubble.offsetLeft + srcBubble.offsetWidth).toString() + ', ' + (srcBubble.offsetTop).toString() + ', ' + srcBubble.bubbleId.toString() + ');', infoDisplayDelay);
			else
				_doDisplayBubbleText(srcBubble.offsetLeft + srcBubble.offsetWidth, srcBubble.offsetTop, srcBubble.bubbleId);
			moveBubbleText(e);
		}

		var displayBubbleBox = null;
		var currentlyDisplayedId = null;
		var displayTimer = null;
		function _doDisplayBubbleText(x, y, bubbleId)
		{
			for(i = 0; i < infoBubbles.length; i++)
			{
				if(infoBubbles[i].infoBubbleId == bubbleId)
				{
					if(infoBubbles[i].showExtended && extendedObjectContainerElem != null)
						createExtendedBox(infoBubbles[i]);
					else
						createDisplayBubbleBox(x + 4, y - 4, infoBubbles[i]);
					currentlyDisplayedId = bubbleId;
					break;
				}
			}
		}



		function _hideObject() { hideBubbleText();	}
		function hideBubbleText()
		{
			cancelDisplayDelay();
			
			if(displayBubbleBox != null) {
				symbols.removeChild(displayBubbleBox);
				displayBubbleBox = null;
			}
			if(extendedObjectContainerElem != null) {
				extendedObjectContainerElem.innerHTML = '';
			}
			currentlyDisplayedId = null;
			if(onObjectClosed.length > 0) eval(onObjectClosed);
		}

		function cancelDisplayDelay()
		{
			if(displayTimer)
			{
				window.clearTimeout(displayTimer);
				displayTimer = null;
			}
		}

		function moveBubbleText(e)
		{
			if(displayBubbleBox == null)
				return;

			if(!e) e = window.event;

			if(e.target) srcBubble = e.target;
			else if(e.srcElement) srcBubble = e.srcElement;

			if((e.target ? e.target : e.srcElement).bubbleId != currentlyDisplayedId)
				return;
				
			var cur = getPosition(e);

			displayBubbleBox.style.left = (srcBubble.offsetLeft + srcBubble.offsetWidth) + 'px';  //(currentX + cur.x + srcBubble.offsetWidth).toString() + 'px';
			displayBubbleBox.style.top = (currentY + cur.y - 20).toString() + 'px';


			var newX = (srcBubble.offsetLeft + srcBubble.offsetWidth), newY = (currentY + cur.y - 20);
			if(displayBubbleBox && (displayBubbleBox.offsetLeft + displayBubbleBox.offsetWidth > currentX + viewPortWidth))
				newX = srcBubble.offsetLeft - displayBubbleBox.offsetWidth;
			if(displayBubbleBox && (displayBubbleBox.offsetLeft < currentX))
				newX = currentX + 4;
			if(displayBubbleBox && (displayBubbleBox.offsetTop + displayBubbleBox.offsetHeight > currentY + viewPortHeight))
				newY = newY - ((displayBubbleBox.offsetTop + displayBubbleBox.offsetHeight) - (currentY + viewPortHeight) + 4);

			displayBubbleBox.style.left = newX.toString() + 'px';
			displayBubbleBox.style.top = newY.toString() + 'px';

//			if(cur.x >= (displayBubbleBox.offsetLeft - currentX) 
//				&& cur.x <= ((displayBubbleBox.offsetLeft - currentX) + displayBubbleBox.offsetWidth)
//				&& cur.y >= (displayBubbleBox.offsetTop - currentY)
//				&& cur.y <= ((displayBubbleBox.offsetTop - currentY) + displayBubbleBox.offsetHeight)
//			)
//			{
//				unregEventHandler(srcBubble, 'mouseout', hideBubbleText);
//				unregEventHandler(srcBubble, 'mousemove', moveBubbleText);
//			}
		}


		function createExtendedBox(object)
		{
			
			extendedObjectContainerElem.innerHTML = getObjectContents(object);
			if(onObjectDisplayed.length > 0) eval(onObjectDisplayed);
		
		}

		function createDisplayBubbleBox(px, py, object)
		{
			var elem = document.createElement('div');
//infoBubbles[i].title, infoBubbles[i].description, infoBubbles[i].linkUrl, infoBubbles[i].linkTitle, infoBubbles[i].fileUrl, infoBubbles[i].fileTitle, bubbleId
			displayBubbleBox = elem;

			symbols.appendChild(displayBubbleBox);
			
			elem.innerHTML = getObjectContents(object);

			if(bubblePopupCssClass)
			{
				elem.className = bubblePopupCssClass;
			}
			else
			{
				elem.style.padding = '6px';
				elem.style.border = 'solid 4px #4367b3';
				elem.style.color = 'black';
				elem.style.backgroundColor = '#ffffff';
				elem.style.filter = 'alpha(opacity=90)';
				elem.style.opacity = 0.9;
			}

			if(constantInfoDisplayWidth) elem.style.width = constantInfoDisplayWidth.toString() + 'px';
			if(constantInfoDisplayHeight) elem.style.height = constantInfoDisplayHeight.toString() + 'px';


			elem.style.position = 'absolute';
			elem.style.left = px.toString() + 'px';
			elem.style.top = py.toString() + 'px';
			elem.style.zIndex = '23';
			
			regEventHandlerAndForget(elem, 'click', hideBubbleText);
//			elem.onclick = hideBubbleText;
			elem.style.cursor = 'pointer';
			
			if(maxInfoDisplayWidth && (displayBubbleBox.offsetWidth > maxInfoDisplayWidth)) displayBubbleBox.style.width = maxInfoDisplayWidth.toString() + 'px';
			if(maxInfoDisplayHeight && (displayBubbleBox.offsetHeight > maxInfoDisplayHeight)) displayBubbleBox.style.height = maxInfoDisplayHeight.toString() + 'px';
			
			if(onObjectDisplayed.length > 0) eval(onObjectDisplayed);
		}

		function getObjectContents(object)
		{
			if(object.templateId == null)
				return getStandardObjectContents(object);

			var cmdString = 'cmd=getobjecttemplate';
			cmdString += '&id=' + object.templateId.toString();
			cmdString += '&key=' + key;
			
			var response = tricket_sendPostRequest(mapCommandUrl, cmdString);

			if(!response) return;
			
			if(response.indexOf('NOT AUTH') >= 0)
			{
				if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				return false;
			}
			else if(response.indexOf('ERROR:') >= 0)
			{
				alert(response);
				return false;
			}
			else if(response.length == 0)
				return false;

//if(geoWest > 0) geoCursor.y = geoWest + p2mX(currentX + cur.x);
//if(geoNorth > 0) geoCursor.x = geoNorth - p2mY(currentY + cur.y);

			var rt90X = geoNorth - object.mY;
			var rt90Y = geoWest + object.mX;

			return response.replace(/\{TITLE}/g, object.title).replace(/\{BREAD}/g, object.breadText).replace(/\{TEXT}/g, object.description).replace(/\{LINKURL}/g, object.linkUrl).replace(/\{LINKTITLE}/g, object.linkTitle).replace(/\{FILEURL}/g, object.fileUrl).replace(/\{FILETITLE}/g, object.fileTitle).replace(/\{IMG1URL}/g, object.img1Url).replace(/\{IMG1ALT}/g, object.img1Alt).replace(/\{IMG1LINKURL}/g, object.img1LinkUrl).replace(/\{IMG2URL}/g, object.img2Url).replace(/\{IMG2ALT}/g, object.img2Alt).replace(/\{IMG2LINKURL}/g, object.img2LinkUrl).replace(/\{RT90X}/g, rt90X).replace(/\{RT90Y}/g, rt90Y);
		}

		function getStandardObjectContents(object)
		{
			var outHtml = new String();

			outHtml = '<div class="' + bubbleTitleCssClass + '">' + object.title + '</div>';
			if(object.breadText && object.breadText.length > 0)
				outHtml += '<div class="' + bubbleBreadCssClass + '">' + object.breadText + '</div>';
			outHtml += '<div class="' + bubbleTextCssClass + '">' + object.description + '</div>';
			if(object.linkUrl && object.linkUrl.length > 0)
			{
				var linkTarget = '_self';
				if(linkTarget.substr(0, 4) == 'http') linkTarget = '_blank';			
				if(object.linkTitle && object.linkTitle.length > 0)
					outHtml += '<div class="' + bubbleLinkCssClass + '"><a class="' + bubbleLinkCssClass + '" href="' + object.linkUrl + '" target="' + linkTarget + '">' + object.linkTitle + '</a></div>';
				else
					outHtml += '<div class="' + bubbleLinkCssClass + '"><a class="' + bubbleLinkCssClass + '" href="' + object.linkUrl + '" target="' + linkTarget + '">' + object.linkUrl + '</a></div>';
			}
			
			if(object.fileUrl && object.fileUrl.length > 0)
			{
				outHtml += '<div class="' + bubbleFileCssClass + '"><a class="' + bubbleFileCssClass + '" href="' + object.fileUrl + '">' + object.fileTitle + '</a></div>';
			}
			
			if(debugMode)
				outHtml += '<div style="margin-top: 8px;"><b>ObjectID: ' + object.infoBubbleId.toString() + '</b></div>';
				
			return outHtml;
		}

		var selectedObjectElem = null;
		var cancelMove = false;
		function selectObject(e)
		{
			if(!e) e = window.event;

			hideBubbleText();

			var srcBubble = null;
			if(e.target) srcBubble = e.target;
			else if(e.srcElement) srcBubble = e.srcElement;

			if(srcBubble == selectedObjectElem)
			{
				unSelectObject();
				return;
			}
			unSelectObject();
			srcBubble.style.border = 'solid 2px red';
			selectedObjectElem = srcBubble;
			cancelMove = true;
		}
		
		function unSelectObject()
		{
			if(!selectedObjectElem) return;
			selectedObjectElem.style.border = '';
			selectedObjectElem = null;
		}


		function createInfoBubbleElement(addToNode, x, y, url, w, h, offsX, offsY, hasLink)
		{
			var imgelem = null;
			
			if(segmentElemType == 'Bg') 
			{
				imgelem = document.createElement('div');
				addToNode.appendChild(imgelem);
				imgelem.style.backgroundRepeat = 'no-repeat';
				imgelem.style.backgroundPositionX = '0px';
				imgelem.style.backgroundPositionY = '0px';
				imgelem.style.backgroundImage = 'url(' + url + ')';
				imgelem.style.width = (w + 3).toString() + 'px';
				imgelem.style.height = (h + 3).toString() + 'px';
			}
			else 
			{
				imgelem = document.createElement('img');
				addToNode.appendChild(imgelem);
				imgelem.src = url;
				imgelem.style.width = w.toString() + 'px';
				imgelem.style.height = h.toString() + 'px';
			}

			
			if(enableObjectSelection)
			    regEventHandlerAndForget(imgelem, 'click', selectObject);
//				imgelem.onclick = selectObject;
			
			imgelem.style.position = 'absolute';
			imgelem.style.left = (x + offsX).toString() + 'px';
			imgelem.style.top = (y + offsY).toString() + 'px';
			imgelem.style.zIndex = '22';

			if(symbolOpacity != null) 
			{
				if(document.all) imgelem.style['filter'] = 'alpha(opacity=' + symbolOpacity.toString() + ')';
				else imgelem.style['opacity'] = (symbolOpacity/100).toString();
			}

			imgelem.style.cursor = 'pointer';

            regEventHandlerAndForget(imgelem, enableObjectSelection ? 'mouseover' : openObjectMethod, displayBubbleText);
//				imgelem.onmouseover = displayBubbleText;
			if(hasLink == false && (openObjectMethod == 'mouseover' || enableObjectSelection == true)) regEventHandlerAndForget(imgelem, 'mouseout', hideBubbleText); //imgelem.onmouseout = hideBubbleText;
			else regEventHandlerAndForget(imgelem, 'mouseout', cancelDisplayDelay);  //imgelem.onmouseout = cancelDisplayDelay;
			regEventHandlerAndForget(imgelem, 'mousemove', moveBubbleText);
//				imgelem.onmousemove = moveBubbleText;

			return imgelem;
		}		

		function createInfoBubbleShadowElement(addToNode, x, y, url, w, h, offsX, offsY)
		{
			var imgelem = document.createElement('div');
			
			addToNode.appendChild(imgelem);
			
			imgelem.style.backgroundRepeat = 'no-repeat';
			imgelem.style.backgroundImage = 'url(' + url + ')';
			imgelem.style.width = w.toString() + 'px';
			imgelem.style.height = h.toString() + 'px';
			imgelem.style.position = 'absolute';
			imgelem.style.left = (x + offsX).toString() + 'px';
			imgelem.style.top = (y + offsY).toString() + 'px';
			imgelem.style.zIndex = '21';
			
			if(symbolOpacity != null) 
			{
				var shadowOpacity = 40;
				if(symbolOpacity < 60) shadowOpacity = 20; 
				if(document.all) imgelem.style['filter'] = 'alpha(opacity=' + shadowOpacity.toString() + ')';
				else imgelem.style['opacity'] = (shadowOpacity/100).toString();
			}
			
			return imgelem;
		}		

		
		
		//SaveObject
		// CHARSAFE
		function _sO(iBubble)
		{
			if(iBubble == null && selectedObjectElem)
			{
				for(i = 0; i < infoBubbles.length; i++)
				{
					if(infoBubbles[i].infoBubbleId == selectedObjectElem.bubbleId)
					{
						iBubble = infoBubbles[i];
						break;
					}
				}
			}
			else if(iBubble == null)
				iBubble = infoBubbles[infoBubbles.length - 1];

			var titleElem = document.getElementById('ObjectTitleText');
			var descElem = document.getElementById('ObjectDescriptionText');
			var extidElem = document.getElementById('ExternalIdText');
			var categoryElem = document.getElementById('ObjectCategoryList');
			var symbolElem = document.getElementById('ObjectSymbolList');
			var belongsElem = document.getElementsByName('ObjectBelongsGroup');
			var numberedElem = document.getElementById('ObjectNumberedCheck');
			var infoBubbleLinkElem = document.getElementById('ObjectLinkText');
			var infoBubbleLinkTitleElem = document.getElementById('ObjectLinkTitleText');

			if(titleElem != null && titleElem.value.length == 0)
			{
				alert(msgMissingObjectTitle);
				return;
			}

			var hasLink = false;
			if(infoBubbleLinkElem && (infoBubbleLinkElem.value.length > 0)) hasLink = true;

			if(!selectedObjectElem || (iBubble.symbolId != parseInt(symbolElem.value)))
			{
				if(selectedObjectElem)
				{
					if(iBubble.shadowElem) 
					{
						symbols.removeChild(iBubble.shadowElem);
						iBubble.shadowElem = null;
					}
					symbols.removeChild(iBubble.bubbleElem);
					iBubble.bubbleElem = null;
				}

				// Get symbol graphics data
				var cmdString = 'cmd=symboldata&symbolid=' + symbolElem.value;
				cmdString += '&key=' + key;
				var response = tricket_sendPostRequest(mapCommandUrl, cmdString);
				
				if(!response) return;
				
				if(response.indexOf('NOT AUTH') >= 0)
				{
					if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
					return false;
				}
				if(response.indexOf('ERROR:') >= 0)
					alert(response);
				else
				{
					var parts = response.split('$');
					// s.Klient_Bredd, s.Klient_Höjd, s.Klient_OffsetX, s.Klient_OffsetY, s.Klient_Sökväg, s.Klient_Skugga_Bredd, s.Klient_Skugga_Höjd, s.Klient_Skugga_OffsetX, s.Klient_Skugga_OffsetY, s.Klient_Skugga_Sökväg
					//      0               1               2                 3                4                5                          6                     7                          8                     9         
					if(parts[9].length > 0) 
						iBubble.shadowElem = createInfoBubbleShadowElement(symbols, m2pX(iBubble.mX), m2pY(iBubble.mY), baseSymbolPath + parts[9], parseInt(parts[5]), parseInt(parts[6]), parseInt(parts[7]), parseInt(parts[8]));

					iBubble.bubbleElem = createInfoBubbleElement(symbols, m2pX(iBubble.mX), m2pY(iBubble.mY), baseSymbolPath + parts[4], parseInt(parts[0]), parseInt(parts[1]), parseInt(parts[2]), parseInt(parts[3]), hasLink);
					iBubble.shElemOffsX = parseInt(parts[7]);
					iBubble.shElemOffsY = parseInt(parts[8]);
					iBubble.elemOffsX = parseInt(parts[2]);
					iBubble.elemOffsY = parseInt(parts[3]);
				}
			}
			else
			{
				if(hasLink)
				{
					unregEventHandler(iBubble.bubbleElem, 'mouseout', hideBubbleText);
					//iBubble.bubbleElem.onmouseout = null;
					regEventHandlerAndForget(iBubble.bubbleElem, 'mouseout', cancelDisplayDelay);
					//iBubble.bubbleElem.onmouseout = cancelDisplayDelay;
				}
				else
				{
				    unregEventHandler(iBubble.bubbleElem, 'mouseout', cancelDisplayDelay);
//					iBubble.bubbleElem.onmouseout = null;
					regEventHandlerAndForget(iBubble.bubbleElem, 'mouseout', hideBubbleText);
//					iBubble.bubbleElem.onmouseout = hideBubbleText;
				}
			}

			var belongs = '';
			for(i = 0; i < belongsElem.length; i++)
			{
				if(belongsElem[i].checked)
					belongs = belongsElem[i].value;
			}

			iBubble.title = titleElem.value;
			iBubble.categoryId = (categoryElem == null ? '' : categoryElem.value);
			iBubble.description = (descElem == null ? '' : descElem.value);
			iBubble.externalId = (extidElem == null || extidElem.value.length == 0 ? '' : extidElem.value);
			if(infoBubbleLinkElem && infoBubbleLinkElem.value.length > 0) 
			{
				if(infoBubbleLinkElem.value.substring(0, 4) != 'http')
					iBubble.linkUrl = 'http://' + infoBubbleLinkElem.value;
				else
					iBubble.linkUrl = infoBubbleLinkElem.value;
			}
			else
				iBubble.linkUrl = '';
			iBubble.linkTitle = (infoBubbleLinkTitleElem == null ? '' : infoBubbleLinkTitleElem.value);
			iBubble.numbered = (numberedElem && numberedElem.checked ? true : false);
			iBubble.symbolId = symbolElem.value;

			if(belongs == 'route')
				iBubble.routeId = routeId;
			else
				iBubble.routeId = null;

			cmdString = 'cmd=saveinfobubble';
			cmdString += '&infobubbleid=' + (iBubble.infoBubbleId == null ? '' : iBubble.infoBubbleId);
			cmdString += '&mapid=' + iBubble.mapId;			
			cmdString += '&routeid=' + (iBubble.routeId == null ? '' : iBubble.routeId);
			cmdString += '&extid=' + encode64(iBubble.externalId);
			cmdString += '&meterx=' + iBubble.mX;
			cmdString += '&metery=' + iBubble.mY;
			cmdString += '&title=' + encode64(iBubble.title);
			cmdString += '&description=' + encode64(iBubble.description);

			cmdString += '&linkurl=' + (iBubble.linkUrl == null ? '' : encode64(iBubble.linkUrl));
			cmdString += '&linktitle=' + (iBubble.linkTitle == null ? '' : encode64(iBubble.linkTitle));

			cmdString += '&symbolid=' + symbolElem.value;
			cmdString += '&categoryid=' + iBubble.categoryId;
			cmdString += '&belongs=' + belongs;
			cmdString += '&layerid=' + (layerId == null ? '' : layerId);
			cmdString += '&numbered=' + (numberedElem && numberedElem.checked ? 'true' : 'false');
			cmdString += '&key=' + key;
			
			response = tricket_sendPostRequest(mapCommandUrl, cmdString);
			
			if(!response) return;

			if(response.indexOf('NOT AUTH') >= 0)
			{
				if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				return false;
			}
			if(response.indexOf('ERROR:') >= 0)
				alert(response);
			else
			{
				iBubble.infoBubbleId = parseInt(response);
				iBubble.bubbleElem.bubbleId = iBubble.infoBubbleId;
				
				iBubble.bubbleElem.id = 'trobj' + iBubble.infoBubbleId.toString();
				if(iBubble.shadowElem) iBubble.shadowElem.id = 'trobjsh' + iBubble.infoBubbleId.toString();
				
				iBubble.description = (iBubble.description == null ? '' : iBubble.description.replace(/\r\n/g, '<br />'));
				setDelayedStatus(msgObjectSaved, 2000);
				unSelectObject();
			}

			_cancel();
		}
		
		function updateObjectPosition(object)
		{
			var cmdString = 'cmd=updateobjectposition';
			cmdString += '&infobubbleid=' + (object.infoBubbleId == null ? '' : object.infoBubbleId);
			cmdString += '&meterx=' + object.mX;
			cmdString += '&metery=' + object.mY;
			cmdString += '&key=' + key;
			
			response = tricket_sendPostRequest(mapCommandUrl, cmdString);
			if(response.indexOf('NOT AUTH') >= 0)
			{
				if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				return false;
			}
			if(response.indexOf('ERROR:') >= 0)
				alert(response);
			
			return;
		}
		
		function deleteObject(id)
		{
			var cmdString = 'cmd=deleteobject';
			cmdString += '&infobubbleid=' + id.toString();
			cmdString += '&key=' + key;
			
			response = tricket_sendPostRequest(mapCommandUrl, cmdString);
			if(response.indexOf('NOT AUTH') >= 0)
			{
				if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				return false;
			}
			if(response.indexOf('ERROR:') >= 0)
				alert(response);

			for(var i = 0; i < infoBubbles.length; i++)
			{
				if(infoBubbles[i].infoBubbleId == selectedObjectElem.bubbleId)
				{
					symbols.removeChild(infoBubbles[i].bubbleElem);
					if(infoBubbles[i].shadowElem) symbols.removeChild(infoBubbles[i].shadowElem);
					infoBubbles.splice(i, 1);
					break;
				}
			}
			
//			setDelayedStatus(msgObjectSaved, 2000);
			unSelectObject();
			
			return;
		}
		
				
		function loadInfoBubbles()
		{
			if(disableObjects)
				return;

			clearAllInfoBubbles();

			var layerIdString = new String();

			if(layerId)
				layerIdSring = layerId.toString() + ',';

			if(layerArray) 
			{
				for(i = 0; i < layerArray.length; i++)
					if(layerArray[i].layerVisible)
						layerIdString += layerArray[i].layerId + ',';

			}
			if(layerIdString.length > 0)
				layerIdString = layerIdString.substr(0, layerIdString.length - 1);
			
			var routeIdString = new String();
			
			if(routeId)
				routeIdString = routeId.toString() + ',';
			if(routeArray)
			{
				for(i = 0; i < routeArray.length; i++)
					if(routeArray[i].routeVisible)
						routeIdString += routeArray[i].routeId + ',';
				
			}
			if(routeIdString.length > 0)
				routeIdString = routeIdString.substr(0, routeIdString.length - 1);
			
			var cmdString = 'cmd=loadinfobubbles';
			cmdString += '&mapid=' + mapId;
			cmdString += '&routeid=' + routeIdString;
			cmdString += '&layerid=' + layerIdString;
			cmdString += '&viewid=' + (viewId == null ? '' : viewId);
			cmdString += '&static=' + (staticInfoBubbleId == null ? '' : staticInfoBubbleId);
			cmdString += '&always=' + (alwaysVisibleList == null ? '' : alwaysVisibleList);
			
			cmdString += '&key=' + key;

			var response = tricket_sendPostRequest(mapCommandUrl, cmdString);

			if(!response) return;
			
			if(response.indexOf('NOT AUTH') >= 0)
			{
				if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				return false;
			}
			else if(response.indexOf('ERROR:') >= 0)
			{
				alert(response);
				return;
			}
			else if(response.length == 0)
				return;
			
			var itms = response.split('|');
			var parts = null;
			var iBubble = null;
			for(i = 0; i < itms.length; i++)
			{
				parts = itms[i].split('$');
				if(parts.length != 36)
				{
					alert('System error: could not load objects.');
					return;
				}
				
				iBubble = new s_InfoBubble();
				
				iBubble.infoBubbleId = parseInt(parts[0]);
				iBubble.mapId = parseInt(parts[1]);
				iBubble.routeId = (parts[3].length > 0 ? parseInt(parts[3]) : null);
				iBubble.mX = parseFloat(parts[4]);
				iBubble.mY = parseFloat(parts[5]);				
				iBubble.title = parts[6];
				iBubble.description = parts[7];

				iBubble.linkUrl = parts[18];
				iBubble.linkTitle = parts[19];

				iBubble.fileUrl = parts[20];
				iBubble.fileTitle = parts[21];
				
				iBubble.externalId = parts[22];
				iBubble.numbered = (parts[23] == 'true' ? true : false);
				iBubble.symbolId = parseInt(parts[24]);
				iBubble.categoryId = (parts[25].length == 0 ? null : parseInt(parts[25]))
				
				iBubble.shElemOffsX = parseInt(parts[15]);
				iBubble.shElemOffsY = parseInt(parts[16]);
				iBubble.elemOffsX = parseInt(parts[10]);
				iBubble.elemOffsY = parseInt(parts[11]);
				
				if(parts[17].length > 0)
					iBubble.shadowElem = createInfoBubbleShadowElement(symbols, m2pX(iBubble.mX), m2pY(iBubble.mY), baseSymbolPath + parts[17], parseInt(parts[13]), parseInt(parts[14]), parseInt(parts[15]), parseInt(parts[16]));

				var hasLink = false;

				if(iBubble.linkUrl != null && iBubble.linkUrl.length > 0) hasLink = true;
				if(iBubble.fileUrl != null && iBubble.fileUrl.length > 0) hasLink = true;

				iBubble.bubbleElem = createInfoBubbleElement(symbols, m2pX(iBubble.mX), m2pY(iBubble.mY), baseSymbolPath + parts[12], parseInt(parts[8]), parseInt(parts[9]), parseInt(parts[10]), parseInt(parts[11]), hasLink);

				iBubble.bubbleElem.bubbleId = iBubble.infoBubbleId;
				iBubble.bubbleElem.id = 'trobj' + iBubble.infoBubbleId.toString();
				if(iBubble.shadowElem) iBubble.shadowElem.id = 'trobjsh' + iBubble.infoBubbleId.toString();

/*
			var breadText = null;
			var img1Url = null;
			var img1Alt = null;
			var img1LinkUrl = null;
			var img2Url = null;
			var img2Alt = null;
			var img2LinkUrl = null;
			var templateId = null;
			var showExtended = null;
*/

				iBubble.breadText = parts[26];
				iBubble.img1Url = parts[27];
				iBubble.img1Alt = parts[28];
				iBubble.img1LinkUrl = parts[29];
				iBubble.img2Url = parts[30];
				iBubble.img2Alt = parts[31];
				iBubble.img2LinkUrl = parts[32];
				iBubble.templateId = (parts[33].length > 0 ? parseInt(parts[33]) : null);
				iBubble.showExtended = (parts[34] == 'true' ? true : false);
				
				iBubble.zoomLevel = (parts[35] == '' ? null : parseInt(parts[35]));

				infoBubbles.push(iBubble);
			}
		}

		function _lO(id, eid) { loadInfoBubble(id, eid); }
		function loadInfoBubble(id, eid)
		{
			if(disableObjects)
				return;
		
			for(i = 0; i < infoBubbles.length; i++)
				if(infoBubbles[i].infoBubbleId == id)
					return;
		
			var cmdString = 'cmd=loadinfobubble';
			cmdString += '&mapid=' + mapId;
			cmdString += '&id=' + (id == null ? '' : id);
			cmdString += '&eid=' + (eid == null ? '' : eid);
			cmdString += '&key=' + key;
			
			var response = tricket_sendPostRequest(mapCommandUrl, cmdString);

			if(!response) return;
			
			if(response.indexOf('NOT AUTH') >= 0)
			{
				if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				return false;
			}
			else if(response.indexOf('ERROR:') >= 0)
			{
				alert(response);
				return false;
			}
			else if(response.length == 0)
				return false;
			
			var parts = response.split('$');

			if(parts.length != 36)
			{
				alert('System error: could not load object.');
				return false;
			}
		
			
			iBubble = new s_InfoBubble();
			
			iBubble.infoBubbleId = parseInt(parts[0]);
			iBubble.mapId = parseInt(parts[1]);
			iBubble.routeId = (parts[3].length > 0 ? parseInt(parts[3]) : null);				
			iBubble.mX = parseFloat(parts[4]);
			iBubble.mY = parseFloat(parts[5]);				
			iBubble.title = parts[6];
			iBubble.description = parts[7];

			iBubble.linkUrl = parts[18];
			iBubble.linkTitle = parts[19];

			iBubble.fileUrl = parts[20];
			iBubble.fileTitle = parts[21];
			
			iBubble.externalId = parts[22];
			iBubble.numbered = (parts[23] == 'true' ? true : false);
			iBubble.symbolId = parseInt(parts[24]);
			iBubble.categoryId = (parts[25].length == 0 ? null : parseInt(parts[25]))

			iBubble.shElemOffsX = parseInt(parts[15]);
			iBubble.shElemOffsY = parseInt(parts[16]);
			iBubble.elemOffsX = parseInt(parts[10]);
			iBubble.elemOffsY = parseInt(parts[11]);
			if(parts[17].length > 0)
				iBubble.shadowElem = createInfoBubbleShadowElement(symbols, m2pX(iBubble.mX), m2pY(iBubble.mY), baseSymbolPath + parts[17], parseInt(parts[13]), parseInt(parts[14]), parseInt(parts[15]), parseInt(parts[16]));

// Has link!
			var hasLink = false;

			if(iBubble.linkUrl != null && iBubble.linkUrl.length > 0) hasLink = true;
			if(iBubble.fileUrl != null && iBubble.fileUrl.length > 0) hasLink = true;

			iBubble.bubbleElem = createInfoBubbleElement(symbols, m2pX(iBubble.mX), m2pY(iBubble.mY), baseSymbolPath + parts[12], parseInt(parts[8]), parseInt(parts[9]), parseInt(parts[10]), parseInt(parts[11]), hasLink);

			iBubble.bubbleElem.bubbleId = iBubble.infoBubbleId;
			iBubble.bubbleElem.id = 'trobj' + iBubble.infoBubbleId.toString();
			if(iBubble.shadowElem) iBubble.shadowElem.id = 'trobjsh' + iBubble.infoBubbleId.toString();
			
			iBubble.breadText = parts[26];
			iBubble.img1Url = parts[27];
			iBubble.img1Alt = parts[28];
			iBubble.img1LinkUrl = parts[29];
			iBubble.img2Url = parts[30];
			iBubble.img2Alt = parts[31];
			iBubble.img2LinkUrl = parts[32];
			iBubble.templateId = (parts[33].length > 0 ? parseInt(parts[33]) : null);
			iBubble.showExtended = (parts[34] == 'true' ? true : false);
			iBubble.zoomLevel = (parts[35] == '' ? null : parseInt(parts[35]));
			infoBubbles.push(iBubble);
			
			return true;
		}
		
		
		function _clearObjects() { clearAllInfoBubbles(); }
		function clearAllInfoBubbles()
		{
			for(i = infoBubbles.length - 1; i >= 0; i--)
			{
				if(infoBubbles[i].shadowElem)
					symbols.removeChild(infoBubbles[i].shadowElem);
				symbols.removeChild(infoBubbles[i].bubbleElem);
				infoBubbles.pop();
			}
			unSelectObject();
		}



		// saveLayer
		// CHARSAFE
		function _sL()
		{
			var titleElem = document.getElementById('LayerNameText');
			var descElem = document.getElementById('LayerDescriptionText');

			var overwrite = checkOverwrite();

			cmdString = 'cmd=savelayer';
			cmdString += '&mapid=' + mapId;
			cmdString += '&layerid=' + (overwrite ? layerId.toString() : '');
			cmdString += '&title=' + encode64(titleElem.value);
			cmdString += '&description=' + (descElem == null ? '' : encode64(descElem.value));
			cmdString += '&key=' + key;
			
			response = tricket_sendPostRequest(mapCommandUrl, cmdString);
			
			if(!response) return;

			if(response.indexOf('NOT AUTH') >= 0)
			{
				if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				return false;
			}
			if(response.indexOf('ERROR:') >= 0)
				alert(response);
			else
			{				
				_layerName = titleElem.value;
				_layerDescription = (descElem == null ? '' : descElem.value);

				setDelayedStatus(msgLayerSaved, 2000);
				populateLayerList(response);
				layerId = parseInt(response);
				
				if(onLayerSaved.length > 0) eval(onLayerSaved);
			
			}
			_cancel();
		}


		// saveView
		//CHARSAFE
		function _sV()
		{
			
			var nameElem = document.getElementById('ViewNameText');
			var descElem = document.getElementById('ViewDescriptionText');

			if(!nameElem || nameElem.value.length == 0)
			{
				alert(msgMissingViewName);
				return;
			}

			var vName = nameElem.value;
			var vDesc = '';
			if(descElem && descElem.value.length > 0)
				vDesc = descElem.value;

			var overwrite = checkOverwrite();

			_saveView(vName, vDesc, overwrite);

			_cancel();
		}
		
		function _saveView(name, desc, overwrite)
		{
			var objectIdString = new String();

			if(infoBubbles) 
			{
				for(i = 0; i < infoBubbles.length; i++)
					objectIdString += infoBubbles[i].infoBubbleId.toString() + ',';

				if(objectIdString.length > 0)
					objectIdString = objectIdString.substr(0, objectIdString.length - 1);
			}

			var routeIdString = new String();
			if(routeArray) 
			{
				for(i = 0; i < routeArray.length; i++)
					if(routeArray[i].routeVisible)
						routeIdString += routeArray[i].routeId + ',';
			}
			if(routeIdString.length > 0)
				routeIdString = routeIdString.substr(0, routeIdString.length - 1);


			cmdString = 'cmd=saveview';
			cmdString += '&viewid=' + (overwrite ? (viewId != null ? viewId.toString() : '') : '');
			cmdString += '&routeid=' + (routeIdString.length > 0 ? routeIdString : '');
			cmdString += '&mapid=' + mapId.toString();
			cmdString += '&zoom=' + _zoomLevel.toString();
			cmdString += '&mapvar=' + mapVariant;
			cmdString += '&xpos=' + Math.floor(p2mX(currentX + viewPortWidth / 2 + document.body.scrollLeft));
			cmdString += '&ypos=' + Math.floor(p2mY(currentY + viewPortHeight / 2 + document.body.scrollTop));
			cmdString += '&name=' + encode64(name);
			cmdString += '&description=' + encode64(desc);
			cmdString += '&objects=' + objectIdString;
			cmdString += '&key=' + key;
			
			response = tricket_sendPostRequest(mapCommandUrl, cmdString);
			
			if(!response) return;

			if(response.indexOf('NOT AUTH') >= 0)
			{
				if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				return false;
			}
			if(response.indexOf('ERROR:') >= 0)
				alert(response);
			else
			{
				setDelayedStatus(msgViewSaved, 2000);
				populateViewList(response);
				viewId = parseInt(response);
				
				_viewName = name;
				_viewDescription = desc;
				
				if(onViewSaved.length > 0) eval(onViewSaved);
			}
			return viewId;
		}


		function populateMapList()
		{
			if(!mapList)
				return;
			var response = tricket_sendGetRequest(mapCommandUrl, 'cmd=maplist&key=' + key);

			if(!response) return;
			
			if(response.indexOf('NOT AUTH') >= 0)
			{
				if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				return false;
			}
			if(response.indexOf('ERROR:') >= 0)
			{
				alert(response);
				return;
			}
			
			populateSelect(mapList, response, null, mapId);

		}
		
		
		
		function mapSelected()
		{
			if(mapList.value.length == 0) return;

			_clearView();

			startMeterX = startMeterY = null;
			currentX = currentY = null;

			loadMap(mapList.value);
		}


		function populateMapVariantList(selectedMapVariant)
		{
			if(!mapVariantList)
				return;
			
			if(!mapVariants)
				return;
				
			for(i = mapVariantList.length - 1; i >= 0; i--)
				mapVariantList.remove(i);
			
			
			for(i = 0; i < mapVariants.length; i++)
			{
				var o = document.createElement('option');
				if(isNS() || isSafari())
					mapVariantList.options[i + (selectedMapVariant ? 1 : 0)] = o;
				else
					mapVariantList.options.add(o);
				o.value = mapVariants[i]._mapVariant;
				o.innerHTML = mapVariants[i]._variantName;
			}
			
			if(mapVariant)
				mapVariantList.value = mapVariant;
		}		


		function populateRouteList(selectedRouteId)
		{
			var response = tricket_sendGetRequest(mapCommandUrl, 'cmd=routelist&mapId=' + mapId + '&key=' + key);

			routeArray = null;
			routeArray = new Array();

			if(response && response.length > 0)
			{
				if(response.indexOf('NOT AUTH') >= 0)
				{
					if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
					return false;
				}
				if(response.indexOf('ERROR:') >= 0)
				{
					alert(response);
					return;
				}
				if(routeList)
					populateSelect(routeList, response, optSelectRoute, selectedRouteId);
					
					
				var itms = response.split('|');

				for(i = 0; i < itms.length; i++)
				{
					var vals = itms[i].split('$');
					if(vals.length == 11) 
					{
						var v = new s_Route();
						v.routeId = parseInt(vals[0]);
						v.routeName = vals[1];						
						v.routeDescription = (vals[2].length == 0 ? null : vals[2]);
						v.routeCoordinates = (vals[3].length == 0 ? null : vals[3]);
						v.routeColor = (vals[4].length == 0 ? null : vals[4]);
						v.routeWeight = (vals[5].length == 0 ? null : parseInt(vals[5]));
						v.routeStyle = (vals[6].length == 0 ? null : vals[6]);
						v.routeDots = (vals[7].length == 0 || vals[7] == 'False' ? false : true);
						v.routePublic = (vals[8].length == 0 || vals[8] == '0' ? false : true);
						v.routeCreatedBy = vals[9];
						v.routeDistance = parseFloat(vals[10]);
						v.route = new Array();
						if(selectedRouteId != null && parseInt(selectedRouteId) == v.routeId) {
							v.routeVisible = true;
						}
						else v.routeVisible = false;

						routeArray.push(v);
					}
				}
			}
			else if(routeList)
				populateSelect(routeList, '', optSelectRoute, null);
				
				
		}
		
		function routeSelected()
		{
			_eR();

			if(routeList.value.length == 0)
				return;
			_loadRoute(routeList.value, true);
		}

		function viewSelected()
		{
			if(viewList.value.length == 0) 
			{
				_clearView();
				if(onViewLoaded.length > 0) eval(onViewLoaded);
				return;
			}
			_loadView(parseInt(viewList.value));
		}

		
		function mapVariantSelected()
		{
			if(mapVariantList.value.length == 0)
				return;
			_setMapVariant(mapVariantList.value);
		}
		
		function _loadRoute(id, scrollIntoView)
		{
			if(routeId != null) _eR();
			
			routeId = parseInt(id);

			for(var ai = 0; ai < routeArray.length; ai++)
				if(routeArray[ai].routeId == routeId)
					break;

			
			route = routeArray[ai].route;
			var c = routeArray[ai].routeCoordinates.split(',');
			for(var i = 0; i < c.length; i++)
				createMeterDot(routeArray[ai], parseFloat(c[i]), parseFloat(c[++i]));
			
			if(scrollIntoView && enableGlide) _smoothScrollTo(m2pX(parseFloat(c[0])), m2pY(parseFloat(c[1])));
			else if(scrollIntoView) _scrollToMeter(parseFloat(c[0]), parseFloat(c[1]));


			_routeName = routeArray[ai].routeName;
			_routeDescription = routeArray[ai].routeDescription;
			_routeCreatedBy = routeArray[ai].routeCreatedBy;
			_routePublic = routeArray[ai].routePublic;
			routeArray[ai].routeVisible = true;

			if(routeList && routeList.length > 0)
				routeList.value = routeId.toString();

			loadInfoBubbles();
			
//			if(enableRouteLines) { clrRouteLines(); redrawRouteLines(); }
		}

		function _uSR() // Unselect Route
		{
			if(routeList)
				routeList.value = '';
		}
		
		
		function _clearView()
		{
			viewId = null;
			_viewName = null;
			_viewDescription = null;
			_eR();
			_uSR();
			clearAllRoutes();
			loadInfoBubbles();
		}
		
		function _loadView(vId)
		{
			viewId = parseInt(vId);

			var response = tricket_sendGetRequest(mapCommandUrl, 'cmd=loadview&data=' + viewId.toString() + '&key=' + key);
			
			if(!response) return;
			
			if(response.indexOf('NOT AUTH') >= 0)
			{
				if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				return false;
			}
			if(response.indexOf('ERROR:') >= 0)
			{
				alert(response);
				return;
			}
			var parts = response.split('$');
// KundId$KartId$Kartvariant$StartMeterX$StartMeterY$Zoomnivå$RuttId$Namn$Beskrivning			
//   0      1         2           3           4         5       6      7      8

			var TmpMapId = parseInt(parts[1]);
			var TmpZoomLevel = parseInt(parts[5]);
			var TmpMapVar = parts[2];
			_viewName = parts[7];
			_viewDescription = parts[8];
			
			if(TmpMapId != mapId)
				loadMap(TmpMapId);
			if(TmpZoomLevel != _zoomLevel)
				loadZoomLevel(TmpZoomLevel);
			if(TmpMapVar != mapVariant)
				_setMapVariant(TmpMapVar);


			if(routeId)
			{
				_eR();
				_uSR();
			}

			clearAllRoutes();

			if(parts[6].length > 0)
			{
				//_loadRoute(parseInt(parts[6]), false);
				_setRoutes(true, parts[6]);
			}
			
			_scrollTo(m2pX(parseFloat(parts[3])), m2pY(parseFloat(parts[4])));
			
			loadInfoBubbles();

			if(onViewLoaded.length > 0) eval(onViewLoaded);		
		}
		


		function populateViewList(selectedViewId)
		{
			if(!viewList)
				return;
			var response = tricket_sendGetRequest(mapCommandUrl, 'cmd=viewlist&key=' + key);
		
			
			if(response.indexOf('NOT AUTH') >= 0)
			{
				if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				return false;
			}
			if(response.indexOf('ERROR:') >= 0)
			{
				alert(response);
				return;
			}
			
			populateSelect(viewList, response, optSelectView, selectedViewId);
		}


		
		function populateSelect(elem, dataString, nonSelection, selectedValue)
		{
			if(!elem) return;

			for(i = elem.length - 1; i >= 0; i--)
				elem.remove(i);

			var itms = dataString.split('|');

			if(nonSelection)
			{
				var o = document.createElement('option');
				if(isNS() || isSafari())
					elem.options[0] = o;
				else
					elem.options.add(o);
				o.value = '';
				o.innerHTML = nonSelection;
			}
			for(i = 0; i < itms.length; i++)
			{
				var vals = itms[i].split('$');
				if(vals.length >= 2) 
				{
					var o = document.createElement('option');
					if(isNS() || isSafari())
						elem.options[i + (nonSelection ? 1 : 0)] = o;
					else
						elem.options.add(o);
					o.value = vals[0];
					o.innerHTML = vals[1];
				}
			}
			
			if(selectedValue)
				elem.value = selectedValue;
		}



		function populateLayerList(selectedLayer)
		{
			var response = tricket_sendGetRequest(mapCommandUrl, 'cmd=layerlist&all=' + inactiveLayersInList.toString() + '&mapId=' + mapId + '&key=' + key);
			
			layerArray = null;
			layerArray = new Array();

			if(response && response.length > 0)
			{
				if(response.indexOf('NOT AUTH') >= 0)
				{
					if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
					return false;
				}
				if(response.indexOf('ERROR:') >= 0)
				{
					alert(response);
					return;
				}
				
				if(layerList)
					populateSelect(layerList, response, optSelectLayer, selectedLayer);
			
				var itms = response.split('|');

				for(i = 0; i < itms.length; i++)
				{
					var vals = itms[i].split('$');
					if(vals.length == 3) 
					{
						var v = new s_Layer();
						v.layerId = parseInt(vals[0]);
						v.layerName = vals[1];
						v.layerDescription = (vals[2].length == 0 ? null : vals[2]);
						v.layerVisible = false;
						layerArray.push(v);
					}
				}
			}
			else if(layerList)
				populateSelect(layerList, '', optSelectLayer, null);
		}



		function _renderLayerChecks(toElemId, rptCols, elemType, outerElemCssClass, columnElemCssClass, inputElemCssClass, labelElemCssClass)
		{
			if(!layerArray)
				return;

			var elem = document.getElementById(toElemId);
			if(!elem)
				return;
				
			var idx = 0;
			var htmlStr = '';
			
			if(elemType.toLowerCase() == 'table')
			{
				htmlStr = '<table class="' + (outerElemCssClass ? outerElemCssClass : '') + '">';
				while(idx < layerArray.length)
				{
					htmlStr += '<tr>';
					for(i = 0; i < rptCols; i++)
					{
						htmlStr += '<td class="' + (columnElemCssClass ? columnElemCssClass : '') + '"><input class="' + (inputElemCssClass ? inputElemCssClass : '') + '" id="layerCheck_' + layerArray[idx].layerId.toString() + '" type="checkbox" ' + (layerArray[idx].layerVisible ? 'checked="checked"' : '') + ' onclick="_setLayer(this.checked, ' + layerArray[idx].layerId + ');"><label class="' + (labelElemCssClass ? labelElemCssClass : '') + '" for="layerCheck_' + layerArray[idx].layerId + '">' + layerArray[idx].layerName + '</label></td>';
						if(++idx == layerArray.length)
							break;
					}
					htmlStr += '</tr>';
				}
				htmlStr += '</table>';
			}
			else if(elemType.toLowerCase() == 'div')
			{
				while(idx < layerArray.length)
				{
					htmlStr += '<div class="' + (outerElemCssClass ? outerElemCssClass : '') + '">';
					for(i = 0; i < rptCols; i++)
					{
						htmlStr += '<span class="' + (columnElemCssClass ? columnElemCssClass : '') + '">';
						htmlStr += '<input class="' + (inputElemCssClass ? inputElemCssClass : '') + '" id="layerCheck_' + layerArray[idx].layerId.toString() + '" type="checkbox" ' + (layerArray[idx].layerVisible ? 'checked="checked"' : '') + ' onclick="_setLayer(this.checked, ' + layerArray[idx].layerId + ');">';
						htmlStr += '<label class="' + (labelElemCssClass ? labelElemCssClass : '') + '" for="layerCheck_' + layerArray[idx].layerId + '">' + layerArray[idx].layerName + '</label>';
						htmlStr += '</span>';
						if(++idx == layerArray.length)
							break;
					}
					htmlStr += '</div>';
				}	
			}
			else {
				alert('Unknown elemType.');
				return;
			}

			elem.innerHTML = htmlStr;
		}


		function _syncRouteChecks()
		{
			var checkElem = null;
			for(var i = 0; i < routeArray.length; i++)
			{
				checkElem = document.getElementById('routeCheck_' + routeArray[i].routeId.toString());
				if(checkElem)
					checkElem.checked = routeArray[i].routeVisible;
			}
		}


		function _renderRouteChecks(toElemId, rptCols, elemType, outerElemCssClass, columnElemCssClass, inputElemCssClass, labelElemCssClass)
		{
			if(!routeArray)
				return;

			var elem = document.getElementById(toElemId);
			if(!elem)
				return;
				
			var idx = 0;
			var htmlStr = '';
			
			if(elemType.toLowerCase() == 'table')
			{
				htmlStr = '<table class="' + (outerElemCssClass ? outerElemCssClass : '') + '">';
				while(idx < routeArray.length)
				{
					htmlStr += '<tr>';
					for(i = 0; i < rptCols; i++)
					{
						htmlStr += '<td class="' + (columnElemCssClass ? columnElemCssClass : '') + '"><input class="' + (inputElemCssClass ? inputElemCssClass : '') + '" id="routeCheck_' + routeArray[idx].routeId.toString() + '" type="checkbox" onclick="_setRoute(this.checked, ' + routeArray[idx].routeId + ');"><label class="' + (labelElemCssClass ? labelElemCssClass : '') + '" for="layerCheck_' + routeArray[idx].routeId + '">' + routeArray[idx].routeName + '</label></td>';
						if(++idx == routeArray.length)
							break;
					}
					htmlStr += '</tr>';
				}
				htmlStr += '</table>';
			}
			else if(elemType.toLowerCase() == 'div')
			{
				while(idx < routeArray.length)
				{
					htmlStr += '<div class="' + (outerElemCssClass ? outerElemCssClass : '') + '">';
					for(i = 0; i < rptCols; i++)
					{
						htmlStr += '<span class="' + (columnElemCssClass ? columnElemCssClass : '') + '">';
						htmlStr += '<input class="' + (inputElemCssClass ? inputElemCssClass : '') + '" id="routeCheck_' + routeArray[idx].routeId.toString() + '" type="checkbox" onclick="_setRoute(this.checked, ' + routeArray[idx].routeId + ');">';
						htmlStr += '<label class="' + (labelElemCssClass ? labelElemCssClass : '') + '" for="routeCheck_' + routeArray[idx].routeId + '">' + routeArray[idx].routeName + '</label>';
						htmlStr += '</span>';
						if(++idx == routeArray.length)
							break;
					}
					htmlStr += '</div>';
				}	
			}
			else {
				alert('Unknown elemType.');
				return;
			}

			elem.innerHTML = htmlStr;
		}



		function _setLayer(visible, layerId)
		{
			if(!layerId)
				return;
			for(i = 0; i < layerArray.length; i++)
			{
				if(layerArray[i].layerId == layerId)
				{
					layerArray[i].layerVisible = visible;

					loadInfoBubbles();
					break;
				}
			}
		}
		
		function _setRoutes(visible, routeIdList)
		{
			var rArray = routeIdList.split(',');
			for(var j = 0; j < rArray.length; j++)
			{
				for(i = 0; i < routeArray.length; i++)
				{
					if(routeArray[i].routeId == parseInt(rArray[j]))
					{
						if(visible == true && routeArray[i].routeVisible == false) {
							routeArray[i].routeVisible = visible;
							var c = routeArray[i].routeCoordinates.split(',');
							for(var k = 0; k < c.length; k++)
								createMeterDot(routeArray[i], parseFloat(c[k]), parseFloat(c[++k]));
						}
						else if(routeArray[i].routeVisible == true)
						{
							routeArray[i].routeVisible = visible;
							clearRoute(routeArray[i].route);
						}
						break;
					}
				}
			}
			if(distanceOutput) distanceOutput.innerHTML = calculateRouteDistance();
			_syncRouteChecks();
		}
		
		function _setRoute(visible, routeId)
		{
			if(!routeId)
				return;
			for(i = 0; i < routeArray.length; i++)
			{
				if(routeArray[i].routeId == routeId)
				{
					routeArray[i].routeVisible = visible;

					if(visible == true) {
						var c = routeArray[i].routeCoordinates.split(',');
						for(var j = 0; j < c.length; j++)
							createMeterDot(routeArray[i], parseFloat(c[j]), parseFloat(c[++j]));
					}
					else
					{
						clearRoute(routeArray[i].route);
					}
					
					loadInfoBubbles();
					break;
				}
			}
			if(distanceOutput) distanceOutput.innerHTML = calculateRouteDistance();
			_syncRouteChecks();
		}



		function layerSelected()
		{
			for(i = 0; i < layerArray.length; i++)
			{
				if(layerId == layerArray[i].layerId)
				{
					layerArray[i].layerVisible = false;
					break;
				}
			}

			if(layerList.value.length == 0) 
			{
				layerId = null;
				_layerName = null;
				_layerDescription = null;
			}
			else layerId = parseInt(layerList.value);

			if(layerId)
			{
				for(i = 0; i < layerArray.length; i++)
				{
					if(layerId == layerArray[i].layerId)
					{
						layerArray[i].layerVisible = true;
						_layerName = layerArray[i].layerName;
						_layerDescription = layerArray[i].layerDescription;
						break;
					}
				}
			}
			loadInfoBubbles();
		}
				
		function _tricketMapSaveViewState()
		{
			var viewStateField = document.getElementsByName('_TricketMapViewState');
			if(viewStateField) 
				viewStateField[0].value = mapId.toString() + '$' + 
					_zoomLevel.toString() + '$' + 
					(routeId == null ? '' : routeId.toString()) + '$' + 
					(layerId == null ? '' : layerId.toString()) + '$' + 
					(mapVariant == null ? '' : mapVariant) + '$' + 
					currentX.toString() + '$' + 
					currentY.toString() + '$' +
					meterPerPixelX.toString() + '$' +
					meterPerPixelY.toString() + '$' +
					(viewId == null ? '' : viewId.toString()) + '$' +
					 _viewName + '$' +
					 (_viewDescription == null ? '' : _viewDescription);

			return true;
		}
		
		
		function loadViewState()
		{
			isPostBack = false;
			var viewStateField = document.getElementsByName('_TricketMapViewState');
			if(viewStateField.length > 0)
			{
				if(viewStateField[0].value.length > 0)
				{
					isPostBack = true;
					var parts = viewStateField[0].value.split('$');
					mapId = parseInt(parts[0]);
					_zoomLevel = parseInt(parts[1]);
					if(parts[2].length > 0) routeId = parseInt(parts[2]);
					if(parts[3].length > 0) layerId = parseInt(parts[3]);
					if(parts[4].length > 0) mapVariant = parts[4];
					if(parts[5].length > 0) currentX = parseInt(parts[5]);
					if(parts[6].length > 0) currentY = parseInt(parts[6]);
					meterPerPixelX = parseFloat(parts[7]);
					meterPerPixelY = parseFloat(parts[8]);
					if(parts[9].length > 0) viewId = parseInt(parts[9]);
					if(parts[10].length > 0) _viewName = parts[10];
					if(parts[11].length > 0) _viewDescription = parts[11];

				}
			}
		}
		
		function _bFb() // beginFeeback
		{
		    unRegAllEventHandlers();
			regEventHandler(placeholder, 'mousedown', doFeedback);
			setStatus(msgClickMap);
		}
		
		function doFeedback(e)
		{
			if(!e) e = window.event;
			_clrS();
			
			var cur = getPosition(e);
			
			showFeedbackDialog();
			
			var xposelem = document.getElementById('XPosText');
			var yposelem = document.getElementById('YPosText');

			xposelem.value = p2mX(currentX + cur.x);
			yposelem.value = p2mY(currentY + cur.y);
		}
		
		
		function showFeedbackDialog()
		{
			dialogElem = createDialog();
			dialogElem.innerHTML = feedbackDialogHtml;
		}
		
		//CHARSAFE
		function _sF()
		{
			var fbt = document.getElementById('FeedbackText');
			var xpt = document.getElementById('XPosText');
			var ypt = document.getElementById('YPosText');
			
			if(fbt.value.length == 0)
			{
				alert(msgMissingFeedbackDescription);
				return false;
			}

			cmdString = 'cmd=sendfeedback';
			cmdString += '&feedback=' + encode64(fbt.value);
			cmdString += '&xpos=' + xpt.value;
			cmdString += '&ypos=' + ypt.value;
			cmdString += '&mapid=' + mapId;
			cmdString += '&zoom=' + _zoomLevel;
			cmdString += '&key=' + key;
			
			response = tricket_sendPostRequest(mapCommandUrl, cmdString);

			if(response.indexOf('NOT AUTH') >= 0)
			{
				if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				return false;
			}
			if(response.indexOf('ERROR:') >= 0)
				alert(response);
			else
			{
				setDelayedStatus(msgFeedbackSaved, 2000);
				_cancel();
			}
		
		}

		
		function _showTempObject(mx, my, title, text, symbolId)
		{
			var object = createBubble(m2pX(mx), m2pY(my));

			// Get symbol graphics data
			var cmdString = 'cmd=symboldata&symbolid=' + symbolId;
			cmdString += '&key=' + key;
			var response = tricket_sendPostRequest(mapCommandUrl, cmdString);
			
			if(!response) return;
			
			if(response.indexOf('NOT AUTH') >= 0)
			{
				if(onNotAuthenticated.length > 0) eval(onNotAuthenticated);
				return false;
			}
			if(response.indexOf('ERROR:') >= 0)
				alert(response);
			else
			{
				var parts = response.split('$');
				if(parts[9].length > 0) 
					object.shadowElem = createInfoBubbleShadowElement(symbols, m2pX(object.mX), m2pY(object.mY), baseSymbolPath + parts[9], parseInt(parts[5]), parseInt(parts[6]), parseInt(parts[7]), parseInt(parts[8]));
				object.bubbleElem = createInfoBubbleElement(symbols, m2pX(object.mX), m2pY(object.mY), baseSymbolPath + parts[4], parseInt(parts[0]), parseInt(parts[1]), parseInt(parts[2]), parseInt(parts[3]), false);
			}

			object.infoBubbleId = tempBubbleId--;
			object.bubbleElem.bubbleId = object.infoBubbleId;
			object.title = title;
			object.description = text;

			object.shElemOffsX = parseInt(parts[7]);
			object.shElemOffsY = parseInt(parts[8]);
			object.elemOffsX = parseInt(parts[2]);
			object.elemOffsY = parseInt(parts[3]);
		}
		
		function colorSelected()
		{
			routeLineColor = colorList.value;
			reRenderRoute();
		}
		function lineStyleSelected()
		{
			routeLineStyle = lineStyleList.value;
			reRenderRoute();
		}
		function lineWeightSelected()
		{
			routeLineWeight = lineWeightList.value;
			reRenderRoute();
		}
		function dotSelected()
		{
			enableDots = dotCheck.checked;			
			reRenderRoute();
		}

		function _setGeoBoundaries(setGeoWest, setGeoNorth, setGeoEast, setGeoSouth)
		{
			if(boundGeoWest == geoWest && boundGeoNorth == geoNorth && boundGeoEast == geoEast && boundGeoSouth == geoSouth)
			{
				// Ok to change boundaries
				boundGeoWest = setGeoWest;
				boundGeoNorth = setGeoNorth;
				boundGeoEast = setGeoEast;
				boundGeoSouth = setGeoSouth;
				checkBoundaries();
			}
			else
				alert('ERROR: Boundaries already set.');
		}

		function _setGeoCenter(setX, setY)
		{
			var mtrX = 0, mtrY = 0;
			if(setX > geoNorth || setX < geoSouth || setY < geoWest || setY > geoEast)
			{
				return false;
			}
			mtrY = geoNorth - setX;
			mtrX = setY - geoWest;
			_scrollToMeter(mtrX, mtrY);
			
			return true;
		}
		
		function _createTextMarker(geoX, geoY, pixelOffsetX, pixelOffsetY, id, text, cssClass, onClickEvalString)
		{
		    for(i = 0; i < infoBubbles.length; i++)
		    {
			    if(infoBubbles[i].infoBubbleId == id.toString())
			    {
					_centerOnInfoBubble(id, true);
					return;
				}
			}

			var mtrX = 0, mtrY = 0;
			if(geoX > geoNorth || geoX < geoSouth || geoY < geoWest || geoY > geoEast)
				return false;

			mtrY = geoNorth - geoX;
			mtrX = geoY - geoWest;

			var object = createBubble(m2pX(mtrX), m2pY(mtrY));

			object.elemOffsX = pixelOffsetX;
			object.elemOffsY = pixelOffsetY;
			var divElm = document.createElement('div');
			divElm.style.position = 'absolute';
			divElm.innerHTML = text;
			divElm.className = cssClass;
			divElm.style.top = (m2pY(mtrY) + pixelOffsetY).toString() + 'px';
			divElm.style.left = (m2pX(mtrX) + pixelOffsetX).toString() + 'px';
			
			if(onClickEvalString != null && onClickEvalString.length > 0)
				divElm.onclick = new Function("eval('" + onClickEvalString + "');");
			symbols.appendChild(divElm);

			object.bubbleElem = divElm;

			object.infoBubbleId = id.toString();
			object.bubbleElem.bubbleId = object.infoBubbleId;
			object.title = '';
			object.description = '';
		}
		
		function _setAlwaysVisible(idList)
		{
			alwaysVisibleList = idList;
		}
		function _appendAlwaysVisible(objId)
		{
			if(alwaysVisibleList != null && alwaysVisibleList.length > 0)
				alwaysVisibleList += ','+objId.toString();
			else
				alwaysVisibleList = objId.toString();
		}
		
		
