﻿var gMap = null;	//Global Map Object
var gLocStartLocation = null; //Centers sweden on the map
var arPins = new Array;
var arDictionary = new Array(new Array,new Array);
var arZoomProximityLimit = new Array(null,600000,200000,160000,80000,45000,20000,10000,7000,4000,2000,500,0,0,0);
var intSearchResults = 20;
var gZoomLevel = 5;
var gShapeLayer = null;
var gDirectionOpen = false;
var objStartingPointPin = null;
var gSearchType = 'avancerad';
var gSearchInProgress = false;

//Initiate functions
Event.observe(window, 'load', 
	function()
	{
		createMap();
		if(gMap)
		{
			gMap.ClearInfoBoxStyles();	//Remove default info box styles
			attachCustomCss();	//Load custom info box styles
			gMap.HideDashboard();	//Remove original controls
			gMap.AttachEvent("onchangeview", onViewChange);	//Attach event function to handle clustering
			gMap.AttachEvent("onclick",onSingleMouseClick); //Attach mouse on even to handle clicking on pins
			//initiateDictionaryArray();	//Populate the translation array
			checkForSingleItem(); // Checks if the user has come from an item page to view the location on a map
		}
	}
); 

Event.observe(window, 'unload', 
	function()
	{
		gMap = null;
		gLocStartLocation = null;
		arPins = null;
		arDictionary = null;
		arZoomProximityLimit = null;
		gZoomLevel = null;
		gShapeLayer = null;
		gDirectionOpen = null;
		objStartingPointPin = null;
		gSearchInProgress = null;
		gSearchType = null;
	}
); 

//Dictionary
function initiateDictionaryArray()
{
	arDictionary[0].push('RIGHT');
	arDictionary[1].push('h&ouml;ger');
	arDictionary[0].push('LEFT');
	arDictionary[1].push('v&auml;nster');
	arDictionary[0].push('STRAIGHT');
	arDictionary[1].push('rakt fram');
	arDictionary[0].push('northwest');
	arDictionary[1].push('nordv&auml;st');
	arDictionary[0].push('northeast');
	arDictionary[1].push('nordost');
	arDictionary[0].push('southwest');
	arDictionary[1].push('sydv&auml;st');
	arDictionary[0].push('southeast');
	arDictionary[1].push('sydost');
	arDictionary[0].push('north');
	arDictionary[1].push('norr');
	arDictionary[0].push('west');
	arDictionary[1].push('v&auml;ster');
	arDictionary[0].push('south');
	arDictionary[1].push('s&ouml;der');
	arDictionary[0].push('east');
	arDictionary[1].push('&ouml;ster');
	arDictionary[0].push('Start at');
	arDictionary[1].push('Starta i');
	arDictionary[0].push('Pass through');
	arDictionary[1].push('K&ouml;r igenom');
	arDictionary[0].push('toward');
	arDictionary[1].push('mot');
	arDictionary[0].push('Take ramp');
	arDictionary[1].push('Ta avfarten ');
	arDictionary[0].push('Turn');
	arDictionary[1].push('Sv&auml;ng');
	arDictionary[0].push('roundabouts');
	arDictionary[1].push('rondeller');
	arDictionary[0].push('roundabout');
	arDictionary[1].push('rondell');
	arDictionary[0].push('Bear');
	arDictionary[1].push('H&aring;ll');
	arDictionary[0].push('Arrive at');
	arDictionary[1].push('Ankomst i');
    arDictionary[0].push('to stay on ');
	arDictionary[1].push('f&ouml;r att forts&auml;tta mot ');
	arDictionary[0].push('Take exit');
	arDictionary[1].push('Avfart');
	arDictionary[0].push('and take 2nd exit');
	arDictionary[1].push('och ta 2:a avfarten');
	arDictionary[0].push('and take 3rd exit');
	arDictionary[1].push('och ta 3:e avfarten');
	arDictionary[0].push('and take 1st exit');
	arDictionary[1].push('och ta 1:a avfarten');
	arDictionary[0].push('Entering');
	arDictionary[1].push('Ankomst');
	arDictionary[0].push('Enter');
	arDictionary[1].push('K&ouml;r in i');
	arDictionary[0].push('onto');
	arDictionary[1].push('mot');
	arDictionary[0].push('Depart');
	arDictionary[1].push('Avg&aring;ng');
	arDictionary[0].push('road');
	arDictionary[1].push('gata');
	arDictionary[0].push('Merge');
	arDictionary[1].push('Forts&auml;tt');
	arDictionary[0].push('Continue');
	arDictionary[1].push('Forts&auml;tt');
	arDictionary[0].push('Exit');
	arDictionary[1].push('L&auml;mna');
	arDictionary[0].push('and then immediately turn');
	arDictionary[1].push('och sv&auml;ng genast');
	arDictionary[0].push('at 2nd exit');
	arDictionary[1].push('vid 2:a avfarten');
	arDictionary[0].push('at 3rd exit');
	arDictionary[1].push('vid 3:e avfarten');
	arDictionary[0].push('Stay on');
	arDictionary[1].push('Forts&auml;tt p&aring;');
	arDictionary[0].push('Take');
	arDictionary[1].push('Ta');
	arDictionary[0].push('At exit 1');
	arDictionary[1].push('Vid avfart 1');
	arDictionary[0].push('take ramp ');
	arDictionary[1].push('ta ramp');
	arDictionary[0].push('and then bear RIGHT');
	arDictionary[1].push('och sv&auml;ng H&Ouml;GER');
	arDictionary[0].push('and then bear LEFT');
	arDictionary[1].push('och sv&auml;ng V&Auml;NSTER');
	arDictionary[0].push('Stop for toll booth');
	arDictionary[1].push('Stanna f&ouml;r v&auml;gtull');
	arDictionary[0].push('At exit 4');
	arDictionary[1].push('Vid avfart 4');
	arDictionary[0].push('Road name changes to');
	arDictionary[1].push('Namn p&aring; v&auml;gen byts till');
	arDictionary[0].push('on ');
	arDictionary[1].push('p&aring; ');
	arDictionary[0].push('and keep');
	arDictionary[1].push('och forts&auml;tt');
}

function checkForSingleItem()
{
	if($('ShowOne'))
	{
		doMapSearch('single');
	}
	return false;
}


function doMapSearch(strType)
{
	if(gSearchInProgress == false)
	{
		gSearchInProgress = true;
		if(strType != '') {gSearchType = strType;}
		$('MapSearchResultsList').update('Searching...');
		if($('MapSearchResultsContainer').visible() == false)
		{
			$('MapSearchResultsContainer').toggle();
		}
		
		RemoveDirections('');
		
		if(gShapeLayer)
		{
			gShapeLayer.DeleteAllShapes();
		}
		
		var strUrl = ''
		
		
		switch(gSearchType)
		{
			case 'avancerad':
				strUrl = 'e_search.asp?searchtype='+gSearchType+'&start='+$F('start')+'&region='+$F('region')+'&typ='+$F('typ')+'&ort='+$F('ort')+'&storlek='+$F('storlek')+'&kedja='+$F('kedja');
			break
			case 'single':
				strUrl = 'e_search.asp?searchtype=avancerad&id='+$('resultid').value;
			break
			default:
				strUrl = 'e_search.asp?searchtype='+gSearchType+'&start='+$F('start')+'&startDatum='+$F('startDatum')+'&stoppDatum='+$F('stoppDatum')+'&region='+$F('region')+'&antalRum='+$F('antalRum');
			break
		}
	
		gShapeLayer = new VEShapeLayer();
		gMap.AddShapeLayer(gShapeLayer);
	
		var objLayerSpec = new VEShapeSourceSpecification (VEDataType.GeoRSS, strUrl, gShapeLayer);
		gMap.ImportShapeLayerData(objLayerSpec, onFeedLoad, 1); // In the function onFeedLoad another function is called to fill the search result layer
		
		
		objLayerSpec = null;
		strUrl = null;
	}
	else
	{
		alert('Please wait until your search is complete');
	}
	return false;
}

function createMap()
{
	gMap = new VEMap('MapLyr');
	// Center sweden on the map
	gLocStartLocation = new VELatLong(60.13056361691419,17.644042968750004);
	gMap.LoadMap(gLocStartLocation, gZoomLevel, 'r', false);
}

function toggleForms(arForms)
{
	arForms.each(function(strLyr)
	{
		$(strLyr).toggle();
	 });
	arPins.clear();
	$F('start').value = 0;
	//if($('searchStatusBox').visible()) { $('searchStatusBox').toggle(); }
}

function attachCustomCss()
{
	var objCSS = document.createElement('link'); 
	objCSS.setAttribute('rel', 'stylesheet'); 
	objCSS.setAttribute('type', 'text/css'); 
	objCSS.setAttribute('href', '/_inc/customVE.css'); 
	document.getElementsByTagName('head')[0].appendChild(objCSS); 
	objCSS = null;
}

function infoBox(strType)
{
	if(strType == 'directions')
	{
		var strContent = '';
		strContent += '<strong>V&auml;gbeskrivning</strong><br><br>';
		strContent += 'F&ouml;r att f&aring; fram en v&auml;gbeskrivning m&aring;ste du f&ouml;rst s&ouml;ka efter anl&auml;ggningar och sedan klicka p&aring; v&auml;gbeskrivnings l&auml;nken f&ouml;r den anl&auml;ggningen du vill &aring;ka till.';
		strContent += '<br><br><a href="javascript:void(0);" onclick="infoBox(\'close\');" style="float:right">St&auml;ng</a>';
		$('InformationBox').update(strContent);
		if($('InformationBox').visible() == false) { $('InformationBox').toggle(); }
		var strContent = null;
	}
	if(strType == 'close' && $('InformationBox').visible() == true)
	{
		$('InformationBox').toggle();
	}
}

function onSingleMouseClick(e)
{
	//When the user click with the left mouse button on the map
	if(e.leftMouseButton)
	{
		if(e.ctrlKey)
		{
			if(gDirectionOpen)
			{
				var objLocation = gMap.PixelToLatLong(new VEPixel(e.mapX, e.mapY));

				if(confirm('Do you wish to specify this location as your start position?'))
				{
					if(objStartingPointPin)
					{
						gMap.DeleteShape(objStartingPointPin);
						objStartingPointPin = null;
					}
					objStartingPointPin = new VEShape(VEShapeType.Pushpin, objLocation);
					objStartingPointPin.SetCustomIcon('<img src="/_img/karta/start.gif" alt="" border=""/>');
					objStartingPointPin.SetTitle('Start position');
					
					gMap.AddShape(objStartingPointPin);
					$('strDirectionsFrom').value = '';
					$('DirectionFrom').value = objLocation.Latitude +' '+ objLocation.Longitude;
					GetDirections('');
				}
				else
				{
					if(objStartingPointPin)
					{
						gMap.DeleteShape(objStartingPointPin);
						objStartingPointPin = null;
					}
				}
				objLocation = null;
			}
		}
		if(e.elementID)
		{
			//document.location.href = gMap.GetShapeByID(e.elementID).GetMoreInfoURL()
			window.open(gMap.GetShapeByID(e.elementID).GetMoreInfoURL()) 
		}
	}
}

function OpenDirections(strLocation,strName,bolAdressFound)
{
	if($('DirectionsInstructions').innerHTML != '')
	{
		RemoveDirections('');
	}
	if($('MapSearchResultsContainer').visible() == true) { $('MapSearchResultsContainer').toggle(); }
	if($('MapDirectionsContainer').visible() == false) { $('MapDirectionsContainer').toggle(); }
	if($('DirectionSearch').visible() == false) { $('DirectionSearch').toggle(); }
	gDirectionOpen = true;
	$('DirectionTo').value = strLocation;
	
	$('DirectionSearchDestination').update(strName)
	$('DirectionTitle').value = strName;
	//$('DirectionsInstructions').update(strContent);
	strContent = null;
}

function SetFromAndGetDirections(strLocation)
{
	$('strDirectionsFrom').value = '';
	$('DirectionFrom').value = strLocation;
	GetDirections('');
}

function GetDirections(strSource)
{
	if($('strDirectionsFrom').value != '' || $('DirectionFrom') != '')
	{
		var arLocations = null;
		var objRouteOptions = new VERouteOptions();
		objRouteOptions.SetBestMapView = true;
		objRouteOptions.RouteCallback = onGotRoute;
		objRouteOptions.DistanceUnit = VERouteDistanceUnit.Kilometer;
		
		var objEnd = new VELatLong($('DirectionTo').value.split(' ')[0], $('DirectionTo').value.split(' ')[1]);
		
		if($('strDirectionsFrom').value != '')
		{
			$('DirectionFrom').value = '';
			if(objStartingPointPin)
			{
				gMap.DeleteShape(objStartingPointPin);
				objStartingPointPin = null;
			}
			arLocations = new Array($('strDirectionsFrom').value, objEnd);
		}
		if($('DirectionFrom').value != '')
		{
			$('strDirectionsFrom').value = '';
			var objStart = new VELatLong($('DirectionFrom').value.split(' ')[0], $('DirectionFrom').value.split(' ')[1]);
			arLocations = new Array(objStart, objEnd);
		}
		
		if(arLocations)
		{
			gMap.GetDirections(arLocations, objRouteOptions);
		}
		arLocations = null;
	}
	
	
	if(strSource == 'fromForm')
	{
		return false;
	}
}

/*
function GetDirections(strSource)
{
	var objFrom = null;
	var objTo = null;
	if($('strDirectionsFrom').value != '')
	{
		var strAddress = $('strDirectionsFrom').value;
		strAddress = strAddress.replace(/å/ig,'a');
		strAddress = strAddress.replace(/ä/ig,'a');
		strAddress = strAddress.replace(/ö/ig,'o');
		
		new Ajax.Request('getLocation.asp?address='+strAddress,
		{
			method: 'get',
			onSuccess: function(transport)
			{
				var strContent = '';
				
				var arResults = transport.responseText.split(',');
				if(arResults.length == 1 && arResults[0] == '')
				{
					strContent = 'No search results where found.<br>';
				}
				else
				{
					strContent = '<br><strong>Results:</strong><br>';
					arResults.each(function(objResultItem)
					{
						objResultItem = objResultItem.replace(/%%%/ig,',');
						objResultItem = objResultItem.split('|%|')
						objResultItem[1]
						arLocation = objResultItem[1].split(' ');
						strContent+='<a href="javascript:SetFromAndGetDirections(\''+ arLocation[1] +' '+ arLocation[0] +'\')" style="text-decoration:underline;">'+objResultItem[0]+'</a><br>';
					});
					arResults = null;
				}
				
				$('DirectionSearchResults').update(strContent +'<br>');
			}
		});

	}
	else
	{
		
		if($('DirectionSearch').visible() == true) { $('DirectionSearch').toggle(); }
		objFrom = new VELatLong($('DirectionFrom').value.split(' ')[0], $('DirectionFrom').value.split(' ')[1]);
		objTo = new VELatLong($('DirectionTo').value.split(' ')[0], $('DirectionTo').value.split(' ')[1]);
		$('DirectionsInstructions').update('Searching...');
		gMap.GetRoute(objFrom, objTo,VEDistanceUnit.Kilometers,null,onGotRoute);
	}
	objFrom = null;
	objTo = null;
	
	
	if(strSource == 'fromForm')
	{
		return false;
	}
}
*/
function RemoveDirections(strAction)
{
	if(strAction == 'opensearchresults')
	{
		if($('MapSearchResultsContainer').visible() == false) { $('MapSearchResultsContainer').toggle(); }
	}
	if($('MapDirectionsContainer').visible() == true ) { $('MapDirectionsContainer').toggle(); gDirectionOpen = false; }
	$('DirectionTo').value = '';
	$('DirectionSearchResults').update('');
	$('DirectionsInstructions').update('');
	try
	{
		gMap.DeleteRoute();
		gMap.HideDashboard();
		if(objStartingPointPin)
		{
			gMap.DeleteShape(objStartingPointPin);
			objStartingPointPin = null;
		}
		
	}
	catch (error)
	{
		alert(error.message);
	}
}

function onGotRoute(objRoute)
{
	if(objRoute)
	{
	
	   var arLegs			= objRoute.RouteLegs;
	   var strRouteInfo		= "<strong>Driving directions</strong><br/><br/>";
	   var objLeg			= null;
	   var intTurnNum		= 0;  // The turn #
	   var totalDistance	= 0;  // The sum of all leg distances
	
		// Get intermediate legs
		for(var i = 0; i < arLegs.length; i++)
		{
			// Get this leg so we don't have to derefernce multiple times
			objLeg = arLegs[i];  // Leg is a VERouteLeg object
			
			// Unroll each intermediate leg
			var turn        = null;  // The itinerary leg
			var legDistance = null;  // The distance for this leg
			
			for(var j = 0; j < objLeg.Itinerary.Items.length; j ++)
			{
				intTurnNum++;
				
				objTurn = objLeg.Itinerary.Items[j];  // turn is a VERouteItineraryItem object
				
				strRouteInfo+= "<b>" + intTurnNum+ "</b>\t" + translateDirection(objTurn.Text);
				
				strLegDistance = objTurn.Distance;
				totalDistance += strLegDistance;
				
				// Round distances to 1/10ths
				strRouteInfo+= " (" + strLegDistance.toFixed(1) + " km)<br/>";
			}
		}
		var strAddress = $('strDirectionsFrom').value;
		strAddress = strAddress.replace(/å/ig,'a');
		strAddress = strAddress.replace(/ä/ig,'a');
		strAddress = strAddress.replace(/ö/ig,'o');
		
		
		
		strRouteInfo += '<br><br><a href="javascript:void(0);" onclick="window.open(\'e_print_karta.asp?strDirectionsFrom='+ escape(strAddress) +'&DirectionTo='+escape($('DirectionTo').value)+'&DirectionFrom='+escape($('DirectionFrom').value)+'&DirectionTitle='+ escape($('DirectionTitle').value)+'\',\'printWindow\',\'location=0,status=0,scrollbars=1,width=600,height=650\');" style="float:left;">Printer friendly version</a>';
		strRouteInfo += '<br><br><a href="javascript:void(0);" onclick="RemoveDirections(\'\');" style="float:right;">Close</a>';
		$('DirectionsInstructions').update(strRouteInfo);
	}
}

/*
function onGotRoute(objRoute)
{
	if(objRoute)
	{
		var strRouteInfo = '<strong>Driving directions</strong><br><br>';
		strRouteInfo += '<b>Total distance:</b> ' + objRoute.Itinerary.Distance + objRoute.Itinerary.DistanceUnit +'<br/><br/>';
		var strSteps = '';
		var intLen = objRoute.Itinerary.Segments.length;
	
		for(var i = 0; i < intLen ;i++)
		{
			if(i == 0)
			{

}
			if((i+1) == intLen)
			{
				strSteps += '<div class="DirectionItem"> Arrival at '+ $('DirectionTitle').value+'<br><span class="grey">('+ objRoute.Itinerary.Segments[i].Distance +' '+ objRoute.Itinerary.DistanceUnit + ')</span></div>';
			}
			if(i != 0 && (i+1) != intLen)
			{
				strSteps += '<div class="DirectionItem">'+(i-1) +'. '+ objRoute.Itinerary.Segments[i].Instruction + '<br><span class="grey">('+ objRoute.Itinerary.Segments[i].Distance +' '+ objRoute.Itinerary.DistanceUnit + ')</span></div>';
			}
				
		}
		strRouteInfo += strSteps;
		strRouteInfo += '<br><br><a href="javascript:void(0);" onclick="window.open(\'e_print_karta.asp?DirectionFrom='+ escape($('DirectionFrom').value) +'&DirectionTo='+escape($('DirectionTo').value)+'&DirectionTitle='+ escape($('DirectionTitle').value)+'\',\'printWindow\',\'location=0,status=0,scrollbars=1,width=600,height=650\');" style="float:left;">Printer friendly version</a>';
		strRouteInfo += '<br><br><a href="javascript:void(0);" onclick="RemoveDirections(\'\');" style="float:right;">Close</a>';
		$('DirectionsInstructions').update(strRouteInfo);
		
		strSteps = null;
		intLen = null;
		strRouteInfo = null;
	}
	else
	{
		OpenDirections($('DirectionTo').value,$('DirectionTitle').value,true)
	}
}
*/

function translateDirection(strContent,i)
{
	/*arDictionary[0].each(function(strEngWord)
	{
		if(strContent.indexOf(strEngWord) != -1)
		{
			strContent = strContent.replace(strEngWord,arDictionary[1][arDictionary[0].indexOf(strEngWord)]);
		}
	});
	*/
	return strContent;
}

function onFeedLoad(objFeed)
{
	
	var strListContent = '';
	arPins.clear();
	if(objFeed.GetShapeCount() == 1 && objFeed.GetShapeByIndex(0).GetTitle() == 'No results')
	{
		gShapeLayer.DeleteAllShapes();
		$('MapSearchResultsList').update('Your search didn\'t give any results') //Fill the search result list
		//if($('searchStatusBox').visible() == true) { $('searchStatusBox').toggle(); }
		gMap.SetCenter(gLocStartLocation);
		gMap.SetZoomLevel(4);

	}
	else
	{
		searchSideInfo();
		for(var i = (objFeed.GetShapeCount() - 1); i >= 0; --i)
		{
			var objPin = objFeed.GetShapeByIndex(i);
			objPin.visible = true;
			objPin.OriginalTitle = objPin.GetTitle();
			objPin.OriginalDescription = objPin.GetDescription();
			objPin.ChildPins = new Array();
			objPin.SetCustomIcon('<img src="/_img/karta/pinIcon.gif" alt="" border=""/>');
			
			arPins.push(objPin);
			
			//Add list content
			var objLocation = objPin.GetPoints();
			strListContent += '<div class="ResultItem"><strong>'+ objPin.GetTitle() +'</strong><div>'+ objPin.GetDescription() +'</div>';
			if(objPin.GetMoreInfoURL())
			{
				strListContent += '<a href="'+ objPin.GetMoreInfoURL() +'" target="_blank"><img src="/_img/karta/btnMoreInfo.gif" alt="More information" border="0"><span>More information</span></a>';
			}
			strListContent += '<a href="javascript:OpenDirections(\''+ objLocation[0].Latitude +' '+ objLocation[0].Longitude +'\',\''+ objPin.GetTitle() +'\',false);"><img src="/_img/karta/btnDirections.gif" alt="Driving directions" border="0"><span>Driving directions</span></a>';
			strListContent += '</div>'
		}
		
		$('MapSearchResultsList').update(strListContent) //Fill the search result list
		if(arPins.length == 1)
		{
			gMap.SetZoomLevel(11);
		}
		onViewChange(null,true);	//Cluster when initiating pins
	}
	strListContent = null;
	gSearchInProgress = false;
}

function searchSideInfo()
{
	new Ajax.Request('searchTotalResult.asp?uniq='+new Date(),
	{
		method: 'get',
		onSuccess: function(transport)
		{
			var intTotalCount = parseInt(transport.responseText) + 1;
			var intStart = parseInt($F('start'));
			var strContent = '';
			strContent = 'Found '+ intTotalCount +' facilities, showing '+ (intStart+1) +'-';
			if((intStart+intSearchResults) > intTotalCount)
			{
				strContent += (intTotalCount) +'.';
			}
			else
			{
				strContent += (intStart + intSearchResults) +'.';
			}
			$('MapSearchStatus').update(strContent);
			
			strContent = '';
			if((intStart+intSearchResults) <= intTotalCount && intTotalCount > intSearchResults)
			{
				strContent += '<a href="javascript:void(0);" onclick="searchNextPage();" id="searchBtnNext"><img src="/_img/karta/e_btn_searchNext.gif" border="0" alt="Next"/></a>';
			}
			if(intStart > 1)
			{
				strContent += '<a href="javascript:void(0);" onclick="searchPreviousPage();" id="searchBtnPrevious"><img src="/_img/karta/e_btn_searchPrevious.gif" border="0" alt="Previous"/></a>';
			}
			$('MapSearchPageButtons').update(strContent);
			
			intTotalCount = null;
			intStart = null;
			strPageButtons = null;
			//	if($('searchStatusBox').visible() == false) { $('searchStatusBox').toggle(); }
		}
	});
}


function searchNextPage()
{
	if(gSearchInProgress == false)
	{
		$('start').value = parseInt($F('start')) + intSearchResults;
		doMapSearch('');
	}
	else
	{
		alert('Please wait until your search is complete');
	}
}

function searchPreviousPage()
{
	if(gSearchInProgress == false)
	{
		$('start').value = parseInt($F('start')) - intSearchResults;
		doMapSearch('');
	}
	else
	{
		alert('Please wait until your search is complete');
	}
}

function onViewChange(e,bolForcedRun)
{
	if(gZoomLevel != gMap.GetZoomLevel() || bolForcedRun == true)
	{
		gZoomLevel = gMap.GetZoomLevel();
		var intDistance = 0;
	
		var arHiddenPins = new Array();
		for(var i = (arPins.length - 1); i >= 0; --i)
		{
			var objPin1 = arPins[i];
			objPin1.ChildPins = new Array();
			objPin1.SetDescription(objPin1.OriginalDescription);
			objPin1.SetTitle(objPin1.OriginalTitle);
			
			var objPin1Loc = objPin1.GetIconAnchor();
			for(var j = (i-1); j >= 0; --j)
			{
				var objPin2 = arPins[j];
				
				if(arHiddenPins.indexOf(objPin2) == -1)
				{
					var objPin2Loc = objPin2.GetIconAnchor();
					
					intDistance = distVincenty(objPin1Loc.Latitude,objPin1Loc.Longitude,objPin2Loc.Latitude,objPin2Loc.Longitude);
	
					if(intDistance <= arZoomProximityLimit[gZoomLevel])
					{
						arHiddenPins.push(objPin2);
						objPin1.ChildPins.push(objPin2);

						if(objPin2.ChildPins.length > 0)
						{
							objPin2.ChildPins.each(function(objChildPin)
							{
								objPin1.ChildPins.push(objChildPin)
							});
						}
					}
				}
			}
		}
		
		intDistance = null;
		
		for(var i = (arPins.length - 1); i >= 0; --i)
		{
			var objPin = arPins[i];
			if(arHiddenPins.indexOf(objPin) == -1)
			{
				var arDescriptions = getTitlesFromPins(objPin.ChildPins.uniq());
				if(arDescriptions.length > 0)
				{
					strDescription = '<div style="padding-top:5px;">'+objPin.OriginalTitle + '</div><div style="padding-top:3px;">' + arDescriptions.toString().replace(/,/,'</div><div style="padding-top:3px;">')
					objPin.SetTitle('');
					objPin.SetDescription('<strong>Nearby facilities</strong><br>'+strDescription+'</div>');
					objPin.ChildPins.clear();
					arDescriptions = null;
				}
				
				if(!objPin.visible)
				{
					objPin.Show();
					objPin.visible = true;
				}
				
			}
			else
			{
				if(objPin.visible)
				{
					objPin.Hide();
					objPin.visible = false;
				}
			}
		}
				
	}
}

function getTitlesFromPins(arPinChilds)
{
	var arDesc = new Array();
	if(arPinChilds.length > 0)
	{
		arPinChilds.each(function(objChildPin)
		{
			//Add description (as string) into the arDesc array
			arDesc.push(objChildPin.OriginalTitle);
			//Check if the current pin has any childs
			if(objChildPin.ChildPins.length > 0)
			{
				//Send the childpin array to the same function (but as an unique array)
				var arChildDesc = getTitlesFromPins(objChildPin.ChildPins.uniq());
				arChildDesc.each(function(objChildDesc)
				{
					//Add each result from the return array into the main description array
					arDesc.push(objChildDesc);
				});
				arChildDesc = null;
			}
		});
		
	}
	return arDesc.uniq();
}

function safeMailChars(objLink)
{
	//window.open(escape(objLink.href));
	strHref = objLink.href;
	objLink.href = strHref.substring(0,strHref.indexOf('=')) + '=' +escape(strHref.substring(strHref.indexOf('=')+1,strHref.length));
	return true;
}


/* ### MoveControl class ###*/
function MoveControl(){}

MoveControl.Panning = false;

MoveControl.MouseDown = function(sender, args)
{    
    MoveControl.Panning = true;
    MoveControl.Pan(sender, args);
}

MoveControl.MouseMove = function(sender, args)
{    
    if(MoveControl.Panning) MoveControl.Pan(sender, args);
}

MoveControl.MouseUp = function(sender, args)
{
    MoveControl.Panning = false;
    gMap.vemapcontrol.StopContinuousPan();
}

MoveControl.Pan = function(element, e)
{    
	if(!e) var e = window.event;
	
	var dx = GetMousePosX(e) - GetElementLeftPosition(element) - (element.offsetWidth / 2);
	var dy = GetMousePosY(e) - GetElementTopPosition(element) - (element.offsetHeight / 2);
	
	dx = Math.min(Math.max(dx, -25), 25);
	dy = Math.min(Math.max(dy, -25), 25);
	
	gMap.vemapcontrol.ContinuousPan(dx, dy);
}


/* COPYRIGHT NOTICE */
/* © 2002-2006 Chris Veness  */
/*
 * Calculate geodesic distance (in m) between two points specified by latitude/longitude (in numeric degrees)
 * using Vincenty inverse formula for ellipsoids
 */
function distVincenty(lat1, lon1, lat2, lon2)
{
	if(lat1 != null && lon1 != null && lat2 != null && lon2 != null)
	{
		var a = 6378137, b = 6356752.3142,  f = 1/298.257223563;  // WGS-84 ellipsiod
		var L = (lon2-lon1).toRad();
		
		var U1 = Math.atan((1-f) * Math.tan(lat1.toRad()));
		var U2 = Math.atan((1-f) * Math.tan(lat2.toRad()));
		var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1);
		var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2);
		
		var lambda = L, lambdaP = 2*Math.PI;
		var iterLimit = 20;
		while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0)
		{
		var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda);
		var sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) + (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda));
		if (sinSigma==0) return 0;  // co-incident points
		var cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda;
		var sigma = Math.atan2(sinSigma, cosSigma);
		var sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
		var cosSqAlpha = 1 - sinAlpha*sinAlpha;
		var cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha;
		if (isNaN(cos2SigmaM)) cos2SigmaM = 0;  // equatorial line: cosSqAlpha=0 (§6)
		var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
		lambdaP = lambda;
		lambda = L + (1-C) * f * sinAlpha * (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
		}
		if (iterLimit==0) return NaN  // formula failed to converge
		
		var uSq = cosSqAlpha * (a*a - b*b) / (b*b);
		var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
		var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
		var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM) - B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
		var s = b*A*(sigma-deltaSigma);
		
		s = s.toFixed(3); // round to 1mm precision
		
		return s;
	}
	else
	{
		return 0;
	}
	
}


// extend String object with method for parsing degrees or lat/long values to numeric degrees
//
// this is very flexible on formats, allowing signed decimal degrees, or deg-min-sec suffixed by 
// compass direction (NSEW). A variety of separators are accepted (eg 3º 37' 09"W) or fixed-width 
// format without separators (eg 0033709W). Seconds and minutes may be omitted. (Minimal validation 
// is done).

String.prototype.parseDeg = function() {
  if (!isNaN(this)) return Number(this);                 // signed decimal degrees without NSEW

  var degLL = this.replace(/^-/,'').replace(/[NSEW]/i,'');  // strip off any sign or compass dir'n
  var dms = degLL.split(/[^0-9.]+/);                     // split out separate d/m/s
  for (var i in dms) if (dms[i]=='') dms.splice(i,1);    // remove empty elements (see note below)
  switch (dms.length) {                                  // convert to decimal degrees...
    case 3:                                              // interpret 3-part result as d/m/s
      var deg = dms[0]/1 + dms[1]/60 + dms[2]/3600; break;
    case 2:                                              // interpret 2-part result as d/m
      var deg = dms[0]/1 + dms[1]/60; break;
    case 1:                                              // decimal or non-separated dddmmss
      if (/[NS]/i.test(this)) degLL = '0' + degLL;       // - normalise N/S to 3-digit degrees
      var deg = dms[0].slice(0,3)/1 + dms[0].slice(3,5)/60 + dms[0].slice(5)/3600; break;
    default: return NaN;
  }
  if (/^-/.test(this) || /[WS]/i.test(this)) deg = -deg; // take '-', west and south as -ve
  return deg;
}
// note: whitespace at start/end will split() into empty elements (except in IE)

// extend Number object with methods for converting degrees/radians

Number.prototype.toRad = function() {  // convert degrees to radians
  return this * Math.PI / 180;
}