/**
 * Color settings, enter colors as RRGGBB
 */
function mapConfig()
 { 	return  { 		maxResults			: 1000,
		addCurtain			: true,		// Color overlay to make markers stand out more
		curtainOpacity		: .4,		// 0-1
		curtainColor		: 'ffffff',
		markerCircleColor	: 'ff0000',
		clusterLabelColor	: 'ffffff',
		clusterCircleColor	: 'ff0000',
		zoomlevelSearch		: 5,
		zoomlevelMini		: 13,
		maxDistanceNeighbors: 20000,
		maxNeighbors		: 30,
		editMapDefaultLat	: 52.36314,
		editMapDefaultLong	: 4.89193,
		editMapDefaultZoom	: 3,
		popupOffset			: 190
	};
}
// 
/**
 * Loads Google Map, adds curtain, 
 *  loads clustermarker and mapiconmaker, 
 *  creates infowindow content.
 * Blaise - March 2009
 */

// Global variables
var activeMarker, activeMarkerIndex, mapData, mapCenter, map, $map, cluster, mapThgCache = [], mapConfig = mapConfig(), mapPan, windowIds = [];

// Initialize map without any markers / location
function initMap(lat, long, zoom)
{
	lat	 = lat  || 0;
	long = long || 0;
	zoom = zoom || mapConfig.zoomlevelSearch || 2;

	map = new GMap2(document.getElementById('map'));
	map.setCenter(new GLatLng(lat, long), zoom, G_NORMAL_MAP);

	$map = $('#map');
	if ($map.hasClass('nodrag'))
	{
		map.disableDragging();
	}
	if (!$map.hasClass('nocontrol'))
	{
		if ($map.hasClass('mini'))
		{
			map.addControl(new GSmallMapControl());
		} else
		{
		    map.enableContinuousZoom();
			map.addControl(new GLargeMapControl());
			map.addControl(new GMapTypeControl());
		}
	}

	// Info window init
	makeInfoWindowOverlay(map);
	window.gmaps_georepeats	= new Object();
	window.gmaps_geopoints	= new Object();
	InfoWindow.prototype	= new GOverlay();

	// Curtain init
	if (!$map.hasClass('edit') && mapConfig.addCurtain)
	{
		new CurtainOverlay().initialize();
		CurtainOverlay.prototype = new GOverlay();
	}
}

// Load the map into the div
// Insert markers which should be already loaded into mapData var
function addMarkersToMap() {

	var marker, markersArray=[];

	for (var i=0, m=mapData.length; i<m; i++) {
		marker = newMarker(new GLatLng(mapData[i].lat, mapData[i].long), i);
		markersArray.push(marker);
		if (mapData[i].id == activeMarker)
		{
			activeMarkerIndex = i;
		}
	}
	
	cluster = new ClusterMarker(map, {
		markers				: markersArray, 
		intersectPadding	: 5,
		clusterMarkerClick	: myClusterClick
	});
	
	if (mapData.length) cluster.fitMapToMarkers();
	
	// Center if we have an active marker
	if (activeMarker) 
	{
		var activeMarkerObj = mapData[activeMarkerIndex];
		if (activeMarkerObj.lat && activeMarkerObj.long)
		{
			mapPan = new GLatLng(activeMarkerObj.lat, activeMarkerObj.long);
			map.setCenter(mapPan, cluster.fitMapToMarkers(1));
			map.savePosition();
		}
	}
}

// Update # things and # locations
function uiUpdate(nThings, nLocations)
{
	if (typeof nThings != 'undefined')    $('#gmap-things').html(nThings);
	if (typeof nLocations != 'undefined') $('#gmap-locations').html(nLocations);
}

// Icon colors + size
function createIconOptions(clusterSize, containsActiveMarker)
{
	clusterSize = parseInt(clusterSize) || 1;
	containsActiveMarker = containsActiveMarker || false;

	// Unclustered
	if (clusterSize <= 1)
	{
		var iconOptions =
		{
			width:			15,
			height:			15,
			label:			'',
			labelSize:		0,
			primaryColor:	mapConfig.markerCircleColor + 'ff',	// RRGGBBAA color of circle, AA=alpha, trans=00 to solid=ff
			labelColor:		'00000000',							// Ignored
			shadowColor:	'88888800'							// RRGGBBAA color + alpha of shadow
		};
	} 
	
	// Clustered
	else {
		var size, labelSize;
		switch(String(clusterSize).length)
		{
			case 1:
			case 2:
			case 3:
				size		= (Math.log(clusterSize) * 6) + 13;
				size		= Math.max(20, size);
				labelSize	= (size / 4) + 10;
				labelSize	= Math.max(labelSize, 9);
				break;
			default:
				size		= 100;
				labelSize	= 35;
				break;
		}
		var iconOptions =
		{
			width:			Math.round(size),
			height:			Math.round(size),
			labelSize:		Math.round(labelSize),
			label:			clusterSize,
			primaryColor:	mapConfig.clusterCircleColor + 'ff',	// RRGGBBAA color of circle
			labelColor:		mapConfig.clusterLabelColor + 'ff',		// RRGGBBAA color of number
			shadowColor:	'88888800'								// RRGGBBAA color + alpha of shadow
		};
	}
	
	// Conatins active marker
	if (containsActiveMarker)
	{
		iconOptions.width	*= 1.2;
		iconOptions.height	*= 1.2;
		if (clusterSize <= 1)
		{
			iconOptions.i2profile = 'marker';	
		} else
		{
			iconOptions.i2profile = 'markercluster';
			iconOptions.labelSize = Math.round(iconOptions.labelSize * 0.6); 
		}
	}
	
	return iconOptions;
}

// Click handler for clusters
function myClusterClick(args)
{

	// Is this an unclusterable cluster?
	var unclusterable = true, items = [];
	if (true || !$map.hasClass('nodrag')) // has a weird bug with popup position
	{
		for (i=0, m=args.clusteredMarkers.length; i<m; i++)
		{
			items.push(mapData[args.clusteredMarkers[i].id].title);
			if (!args.clusterMarker.getLatLng().equals(args.clusteredMarkers[i].getLatLng()))
			{
				unclusterable = false;
				break;
			}
		}
	}
	
	// Unclusterable
	if  (!unclusterable && map.getZoom() != 17)
	{
		var zoom = map.getBoundsZoomLevel(args.clusterMarker.clusterGroupBounds);
		map.setCenter(args.clusterMarker.getLatLng(), zoom)
		delete cluster.defaultClickAction;
	} 
	
	// Not unclusterable, show items
	else
	{
		var ids = [];
		for (i=0; i<args.clusteredMarkers.length; i++) {
			ids.push(mapData[args.clusteredMarkers[i].id].id);
		}
		showInfoWindow(args.clusteredMarkers[0], ids);
	}
}

// Single markers
function newMarker(markerLocation, mapDataIndex)
{
	var opts = createIconOptions(1, mapData[mapDataIndex].id == activeMarker);
	var defaultIcon = MapIconMaker.createFlatIcon(opts);

	// Create marker
	var marker = new GMarker(markerLocation, {
		title:	mapData[mapDataIndex].title,
		id:		mapDataIndex,
		icon:	defaultIcon
	});

	// Onclick action
	if (!$map.hasClass('noclick'))
	{
		GEvent.addListener(marker, 'click', function() {
			showInfoWindow(marker, [mapData[mapDataIndex].id]);
		});
	}

	return marker;
}

// Remove maps from memory at unload
$(window).unload(function()
{
	GUnload();
});


/* INFO WINDOW
------------------------------------------------------------- */
function makeInfoWindowOverlay(map)
{
	window.gmaps_infowindow	= new InfoWindow(map);
	window.gmaps_map		= map;
	map.addOverlay( window.gmaps_infowindow );
}

// Show information
function showInfoWindow(marker, ids)
{
	// Reclick when still open = close
	if (windowIds.join('.') == ids.join('.')) 
	{
		window.gmaps_infowindow.hide();	
		return;
	}
	
	windowIds = ids;

	// Build HTML
	var html = '';
	html += '<div id="infowindow-close" onclick="window.gmaps_infowindow.hide()">x</div>';
	if (ids.length > 1) { html += '<div id="infowindow-title">' + ids.length + ' things with the same location</div>'; } 
	else { html += '<div id="infowindow-title">&nbsp;</div>'; }
	html += '<div id="infowindow-content" class="wait"></div>';
	
	// Append HTML to popup
	window.gmaps_infowindow.openOnMarker(marker, html);

	$('#infowindow-wrapper a').bind('mousedown', function(e){ return true;  });
	$('#infowindow-wrapper  ').bind('mousedown', function(e){ return false; });
	if (ids.length > 1) { $('#infowindow-content').addClass('multiple'); }

	// Load things
	infoWindowLoadAllThg(ids);
	
	// Pan
	var pnt = marker.getPoint();
	pnt = map.fromLatLngToDivPixel(pnt);

	if ($map.hasClass('mini'))
	{
		pnt.y -= ($('#map').height() / 2) - 25;
		if (!$map.hasClass('nocontrol')) pnt.x -= 20;
	} else
	{
		pnt.y -= mapConfig.popupOffset;
	}

	pnt = map.fromDivPixelToLatLng(pnt);
	map.panTo(pnt);
}

// Set new info
function infoWindowSetContent(html)
{
	$('#infowindow-content').html(html);
	$('#infowindow-content div.listbox li:last-child').addClass('last-child');
	
	// Calculate max height for content
	if ($map.hasClass('mini')) var mh = $map.height() - 85;
	else var mh = mapConfig.maxPopupHeight || 145;
	var ch = $('#infowindow-content div.listbox').height();
	$('#infowindow-content').animate({height: Math.min(mh, ch)}).removeClass('wait');
}

// Ajax load things
function infoWindowLoadAllThg(ids)
{
	// No cache, get data from server
	var cacheKey = ids.join('_');
	if (typeof mapThgCache[cacheKey] == 'undefined')
	{
		var tpl = ($map.hasClass('mini')) ? 'gmaps_mini_listitem' : 'listsection';
		try
		{
			anyRest.html.scomp({name: tpl, query_list: ids, start:0, step:1}, 
				function(xml) 
				{
					if (anyRest.aux.error(xml)) { jQuery.log(anyRest.aux.errorMsg(xml)); }
					else
					{
						var htmlNode = xml.getElementsByTagName('html')[0];
						var html = anyRest.aux.concatChildNodes(htmlNode);
						infoWindowSetContent(html);
						mapThgCache[cacheKey] = html;
					}
				}
			);
		} catch(e)
		{
			window.gmaps_infowindow.hide();
		}
	}
	// Awesome! already loaded
	else
	{
		infoWindowSetContent(mapThgCache[cacheKey]);
	}
}

// 
// 
/*
	ClusterMarker Version 1.3.2
	
	A marker manager for the Google Maps API
	http://googlemapsapi.martinpearman.co.uk/clustermarker
	
	-----
	
	Modified by Blaise, march 2009
*/

function ClusterMarker($map, $options){
	this._map=$map;
	this._mapMarkers=[];
	this._iconBounds=[];
	this._clusterMarkers=[];
	this._eventListeners=[];
	if(typeof($options)==='undefined'){
		$options={};
	}
	this.borderPadding=50;
	this.clusteringEnabled=($options.clusteringEnabled===false)?false:true;
	if($options.clusterMarkerClick){
		this.clusterMarkerClick=$options.clusterMarkerClick;
	}
	
	//	create an array with which to cache all cluster marker icons as they are created
	//	avoiding repeated requests using MapIconMaker for the same marker
	this.clusterMarkerIconCache=[];
	
	if($options.fitMapMaxZoom){
		this.fitMapMaxZoom=$options.fitMapMaxZoom;
	}
	this.intersectPadding=($options.intersectPadding) ? $options.intersectPadding:0;
	if($options.markers){
		this.addMarkers($options.markers);
	}
	GEvent.bind(this._map, 'moveend', this, this._moveEnd);
	GEvent.bind(this._map, 'zoomend', this, this._zoomEnd);
	GEvent.bind(this._map, 'maptypechanged', this, this._mapTypeChanged);
}

ClusterMarker.prototype.addMarkers=function($markers){
	var i;
	if(!$markers[0]){
		//	assume $markers is an associative array and convert to a numerically indexed array
		var $numArray=[];
		for(i in $markers){
			$numArray.push($markers[i]);
		}
		$markers=$numArray;
	}
	for(i=$markers.length-1; i>=0; i--){
		$markers[i]._isVisible=false;
		$markers[i]._isActive=false;
		$markers[i]._makeVisible=false;
	}
	this._mapMarkers=this._mapMarkers.concat($markers);
};

ClusterMarker.prototype._clusterMarker=function($clusterGroupIndexes)
{
	function $newClusterMarker($location, $icon, $title)
	{
		return new GMarker($location, {icon:$icon, title:$title});
	}
	
	var $clusterGroupBounds=new GLatLngBounds(), i, $maxTitles=25, $clusterMarker, $clusteredMarkers=[], $clusterMarkerTitles=[], $marker, $this=this, $mapMarkers=this._mapMarkers;
	
	for (i=$clusterGroupIndexes.length-1; i>=0; i--)
	{
		$marker=$mapMarkers[$clusterGroupIndexes[i]];
		$marker.index=$clusterGroupIndexes[i];
		$clusterGroupBounds.extend($marker.getLatLng());
		$clusteredMarkers.push($marker);
		
		if ($clusterMarkerTitles.length <= $maxTitles)
		{
			var markerTitle = mapData[$marker.id].title;
			if (markerTitle) { $clusterMarkerTitles.push(markerTitle); }
		}
	}
	
	// No more than $maxTitles titles
	if ($clusterMarkerTitles.length >= $maxTitles)
	{
		$clusterMarkerTitles.length = $maxTitles;
		$clusterMarkerTitles.push('...');
	}
	
	$clusterMarker = $newClusterMarker($clusterGroupBounds.getCenter(), this.clusterMarkerIcon($clusterGroupIndexes), $clusterMarkerTitles.join(', '));
	
	$clusterMarker.clusterGroupBounds = $clusterGroupBounds;	//	only req'd for default cluster marker click action
	this._eventListeners.push(GEvent.addListener($clusterMarker, 'click', function(){
		$this.clusterMarkerClick({clusterMarker:$clusterMarker, clusteredMarkers:$clusteredMarkers });
	}));
	$clusterMarker._childIndexes=$clusterGroupIndexes;
	for(i=$clusterGroupIndexes.length-1; i>=0; i--){
		$mapMarkers[$clusterGroupIndexes[i]]._parentCluster=$clusterMarker;
	}
	return $clusterMarker;
};

ClusterMarker.prototype.clusterMarkerClick=function($args){
	this._map.setCenter($args.clusterMarker.getLatLng(), this._map.getBoundsZoomLevel($args.clusterMarker.clusterGroupBounds));
};

ClusterMarker.prototype.clusterMarkerIcon=function($clusterGroupIndexes){
	//	a new method to return a dynamically created icon showing $count as text on the icon
	//	first check to see if the required icon has already been created
	var $count = $clusterGroupIndexes.length;
	if (this.clusterMarkerIconCache[$count] && !activeMarker)
	{
		return this.clusterMarkerIconCache[$count];
	}
	else
	{
		//	create the required icon, cache it and return it from this method
		var containsActiveMarker = false;
		if (activeMarker)
		{
			for (var i=0; i<$clusterGroupIndexes.length; i++)
			{
				if (mapData[$clusterGroupIndexes[i]].id == activeMarker)
				{
					containsActiveMarker = true; break;
				}
			}
		}

		var $count = $count.toString();
		var $iconOptions = createIconOptions($count, containsActiveMarker);
		var $icon = MapIconMaker.createFlatIcon($iconOptions);
		this.clusterMarkerIconCache[$count]=$icon;
		return $icon;
	}
};

ClusterMarker.prototype._filterActiveMapMarkers=function(){
	var $borderPadding=this.borderPadding, $mapZoomLevel=this._map.getZoom(), $mapProjection=this._map.getCurrentMapType().getProjection(), $mapPointSw, $activeAreaPointSw, $activeAreaLatLngSw, $mapPointNe, $activeAreaPointNe, $activeAreaLatLngNe, $activeAreaBounds=this._map.getBounds(), i, $marker, $uncachedIconBoundsIndexes=[], $oldState, $mapMarkers=this._mapMarkers, $iconBounds=this._iconBounds;
	if($borderPadding){
		$mapPointSw=$mapProjection.fromLatLngToPixel($activeAreaBounds.getSouthWest(), $mapZoomLevel);
		$activeAreaPointSw=new GPoint($mapPointSw.x-$borderPadding, $mapPointSw.y+$borderPadding);
		$activeAreaLatLngSw=$mapProjection.fromPixelToLatLng($activeAreaPointSw, $mapZoomLevel);
		$mapPointNe=$mapProjection.fromLatLngToPixel($activeAreaBounds.getNorthEast(), $mapZoomLevel);
		$activeAreaPointNe=new GPoint($mapPointNe.x+$borderPadding, $mapPointNe.y-$borderPadding);
		$activeAreaLatLngNe=$mapProjection.fromPixelToLatLng($activeAreaPointNe, $mapZoomLevel);
		$activeAreaBounds.extend($activeAreaLatLngSw);
		$activeAreaBounds.extend($activeAreaLatLngNe);
	}
	this._activeMarkersChanged=false;
	if(typeof($iconBounds[$mapZoomLevel])==='undefined'){
		//	no iconBounds cached for this zoom level
		//	no need to check for existence of individual iconBounds elements
		this._iconBounds[$mapZoomLevel]=[];
		this._activeMarkersChanged=true;	//	force refresh(true) as zoomed to uncached zoom level
		for(i=$mapMarkers.length-1; i>=0; i--){
			$marker=$mapMarkers[i];
			$marker._isActive=$activeAreaBounds.containsLatLng($marker.getLatLng())?true:false;
			$marker._makeVisible=$marker._isActive;
			if($marker._isActive){
				$uncachedIconBoundsIndexes.push(i);
			}
		}
	}else{
		//	icondBounds array exists for this zoom level
		//	check for existence of individual iconBounds elements
		for(i=$mapMarkers.length-1; i>=0; i--){
			$marker=$mapMarkers[i];
			$oldState=$marker._isActive;
			$marker._isActive=$activeAreaBounds.containsLatLng($marker.getLatLng())?true:false;
			$marker._makeVisible=$marker._isActive;
			if(!this._activeMarkersChanged && $oldState!==$marker._isActive){
				this._activeMarkersChanged=true;
			}
			if($marker._isActive && typeof($iconBounds[$mapZoomLevel][i])==='undefined'){
				$uncachedIconBoundsIndexes.push(i);
			}
		}
	}
	return $uncachedIconBoundsIndexes;
};

ClusterMarker.prototype._filterIntersectingMapMarkers=function(){
	var $clusterGroup, i, j, $mapZoomLevel=this._map.getZoom(), $mapMarkers=this._mapMarkers, $iconBounds=this._iconBounds;
	for(i=$mapMarkers.length-1; i>0; i--)
	{
		if($mapMarkers[i]._makeVisible){
			$clusterGroup=[];
			for(j=i-1; j>=0; j--){
				if($mapMarkers[j]._makeVisible && $iconBounds[$mapZoomLevel][i].intersects($iconBounds[$mapZoomLevel][j])){
					$clusterGroup.push(j);
				}
			}
			if($clusterGroup.length!==0){
				$clusterGroup.push(i);
				for(j=$clusterGroup.length-1; j>=0; j--){
					$mapMarkers[$clusterGroup[j]]._makeVisible=false;
				}
				this._clusterMarkers.push(this._clusterMarker($clusterGroup));
			}
		}
	}
};

ClusterMarker.prototype.fitMapToMarkers=function(getZoom){
	var $mapMarkers=this._mapMarkers, $markersBounds=new GLatLngBounds(), i;
	for(i=$mapMarkers.length-1; i>=0; i--){
		$markersBounds.extend($mapMarkers[i].getLatLng());
	}
	var $fitMapToMarkersZoom=this._map.getBoundsZoomLevel($markersBounds);
	
	if(this.fitMapMaxZoom && $fitMapToMarkersZoom>this.fitMapMaxZoom){
		$fitMapToMarkersZoom=this.fitMapMaxZoom;
	}

	if ($mapMarkers.length < 2) { $fitMapToMarkersZoom = this._map.getZoom(); }
	
	if (getZoom)
	{
		return $fitMapToMarkersZoom;
	}
	else
	{
		this._map.setCenter($markersBounds.getCenter(), $fitMapToMarkersZoom);
		mapCenter = $markersBounds.getCenter();
		this.refresh();
	}
};

ClusterMarker.prototype._mapTypeChanged=function(){
	this.refresh(true);
};

ClusterMarker.prototype._moveEnd=function(){
	if(!this._cancelMoveEnd){
		this.refresh();
	}else{
		this._cancelMoveEnd=false;
	}
};

ClusterMarker.prototype._preCacheIconBounds=function($indexes, $mapZoomLevel){
	var $mapProjection=this._map.getCurrentMapType().getProjection(), i, $marker, $iconSize, $iconAnchorPoint, $iconAnchorPointOffset, $iconBoundsPointSw, $iconBoundsPointNe, $iconBoundsLatLngSw, $iconBoundsLatLngNe, $intersectPadding=this.intersectPadding, $mapMarkers=this._mapMarkers;
	
	// Trim some intersection padding
	if (this._map.getZoom() > 16) $intersectPadding = 3;
	
	for(i=$indexes.length-1; i>=0; i--){
		$marker=$mapMarkers[$indexes[i]];
		$iconSize=$marker.getIcon().iconSize;
		$iconAnchorPoint=$mapProjection.fromLatLngToPixel($marker.getLatLng(), $mapZoomLevel);
		$iconAnchorPointOffset=$marker.getIcon().iconAnchor;
		$iconBoundsPointSw=new GPoint($iconAnchorPoint.x-$iconAnchorPointOffset.x-$intersectPadding, $iconAnchorPoint.y-$iconAnchorPointOffset.y+$iconSize.height+$intersectPadding);
		$iconBoundsPointNe=new GPoint($iconAnchorPoint.x-$iconAnchorPointOffset.x+$iconSize.width+$intersectPadding, $iconAnchorPoint.y-$iconAnchorPointOffset.y-$intersectPadding);
		$iconBoundsLatLngSw=$mapProjection.fromPixelToLatLng($iconBoundsPointSw, $mapZoomLevel);
		$iconBoundsLatLngNe=$mapProjection.fromPixelToLatLng($iconBoundsPointNe, $mapZoomLevel);
		this._iconBounds[$mapZoomLevel][$indexes[i]]=new GLatLngBounds($iconBoundsLatLngSw, $iconBoundsLatLngNe);
	}
};

ClusterMarker.prototype.refresh=function($forceFullRefresh){
	var i, j, $marker, $visibleMarkers = [], $zoomLevel=this._map.getZoom(), $uncachedIconBoundsIndexes=this._filterActiveMapMarkers();
	
	if (this._activeMarkersChanged || $forceFullRefresh)
	{
		this._removeClusterMarkers();

		// if(this.clusteringEnabled && $zoomLevel<this._map.getCurrentMapType().getMaximumResolution()){

		if (this.clusteringEnabled)
		{
			if ($uncachedIconBoundsIndexes.length > 0)
			{
				this._preCacheIconBounds($uncachedIconBoundsIndexes, $zoomLevel);
			}
			this._filterIntersectingMapMarkers();
		} else
		{
			// zooming in any further will not uncluster
		}
		
		// Add clusters to map
		for (i=this._clusterMarkers.length-1; i>=0; i--)
		{
			this._map.addOverlay(this._clusterMarkers[i]);
		}
		
		// Add/remove markers to/from map
		for (i=this._mapMarkers.length-1; i>=0; i--)
		{
			$marker=this._mapMarkers[i];
			if (!$marker._isVisible && $marker._makeVisible)
			{
				this._map.addOverlay($marker);
				$marker._isVisible = true;
			}
			if ($marker._isVisible)
			{
				if (!$marker._makeVisible)
				{
					this._map.removeOverlay($marker);
					$marker._isVisible=false;
				}
			}
		}
/*
		// Create unique arrays for location and thing ids
		var uId	 = [];
		var uLoc = [];
		var $visibleMarkers = this.getMarkersStatus();
		for (var i=0, m=$visibleMarkers.length; i<m; i++)
		{

			// Unique locations 
			var locExists = false
			for (var j=0, x=uLoc.length; j<x; j++)
			{
				var difLat	= Math.abs(uLoc[j][0] - $visibleMarkers[i].aa.y);
				var difLong	= Math.abs(uLoc[j][1] - $visibleMarkers[i].aa.x);
				if (Math.max(difLat, difLong) < 0.0005)
				{
					locExists = true;
					break;
				}
			}
			if (!locExists)
			{
				uLoc.push([$visibleMarkers[i].getLatLng().lat(), $visibleMarkers[i].getLatLng().lng()]);
			}
		
			// Unique ID
			var idExists = false
			for (var j=0, x=uId.length; j<x; j++)
			{
				if (uId[j] == mapData[i].id)
				{
					idExists = true;
					break;
				}
			}
			if (!idExists)
			{
				uId.push(mapData[i].id);
			}
		
		}
		uiUpdate(uId.length.toString(), uLoc.length.toString());
*/		
	}
};


// Get visible markers
ClusterMarker.prototype.getMarkersStatus=function()
{
	var markers = this._mapMarkers, length=markers.length, visible=[];
	for (var i=0; i<length; i++)
	{
		if (markers[i]._isVisible || markers[i]._isActive)
		{
			visible.push(markers[i]);
		}
	}
	return visible;
};



ClusterMarker.prototype._removeClusterMarkers=function(){
	var i, j, $map=this._map, $eventListeners=this._eventListeners, $clusterMarkers=this._clusterMarkers, $childIndexes, $mapMarkers=this._mapMarkers;
	for(i=$clusterMarkers.length-1; i>=0; i--){
		$childIndexes=$clusterMarkers[i]._childIndexes;
		for(j=$childIndexes.length-1; j>=0; j--){
			delete $mapMarkers[$childIndexes[j]]._parentCluster;
		}
		$map.removeOverlay($clusterMarkers[i]);
	}
	for(i=$eventListeners.length-1; i>=0; i--){
		GEvent.removeListener($eventListeners[i]);
	}
	this._clusterMarkers=[];
	this._eventListeners=[];
};

ClusterMarker.prototype.removeMarkers=function(){
	var i, $mapMarkers=this._mapMarkers, $map=this._map;
	for(i=$mapMarkers.length-1; i>=0; i--){
		if($mapMarkers[i]._isVisible){
			$map.removeOverlay($mapMarkers[i]);
		}
		delete $mapMarkers[i]._isVisible;
		delete $mapMarkers[i]._isActive;
		delete $mapMarkers[i]._makeVisible;
	}
	this._removeClusterMarkers();
	this._mapMarkers=[];
	this._iconBounds=[];
};

ClusterMarker.prototype.triggerClick=function($index){
	var $marker=this._mapMarkers[$index];
	if($marker._isVisible){
		//	$marker is visible
		GEvent.trigger($marker, 'click');
	}
	else if($marker._isActive){
		//	$marker is clustered
		var $clusteredMarkersIndexes=$marker._parentCluster._childIndexes, $intersectDetected=true, $uncachedIconBoundsIndexes, i, $mapZoomLevel=this._map.getZoom(), $clusteredMarkerIndex, $iconBounds=this._iconBounds, $mapMaxZoomLevel=this._map.getCurrentMapType().getMaximumResolution();
		while($intersectDetected && $mapZoomLevel<$mapMaxZoomLevel){
			$intersectDetected=false;
			$mapZoomLevel++;
			if(typeof($iconBounds[$mapZoomLevel])==='undefined'){
				//	no iconBounds cached for this zoom level
				//	no need to check for existence of individual iconBounds elements
				$iconBounds[$mapZoomLevel]=[];
				// need to create cache for all clustered markers at $mapZoomLevel
				this._preCacheIconBounds($clusteredMarkersIndexes, $mapZoomLevel);
			}else{
				//	iconBounds array exists for this zoom level
				//	check for existence of individual iconBounds elements
				$uncachedIconBoundsIndexes=[];
				for(i=$clusteredMarkersIndexes.length-1; i>=0; i--){
					if(typeof($iconBounds[$mapZoomLevel][$clusteredMarkersIndexes[i]])==='undefined'){
						$uncachedIconBoundsIndexes.push($clusteredMarkersIndexes[i]);
					}
				}
				if($uncachedIconBoundsIndexes.length>=1){
					this._preCacheIconBounds($uncachedIconBoundsIndexes, $mapZoomLevel);
				}
			}
			for(i=$clusteredMarkersIndexes.length-1; i>=0; i--){
				$clusteredMarkerIndex=$clusteredMarkersIndexes[i];
				if($clusteredMarkerIndex!==$index && $iconBounds[$mapZoomLevel][$clusteredMarkerIndex].intersects($iconBounds[$mapZoomLevel][$index])){	
					$intersectDetected=true;
					break;
				}
			}
			
		};
		this._map.setCenter($marker.getLatLng(), $mapZoomLevel);
		this.triggerClick($index);
	}else{
		// $marker is not within active area (map bounds + border padding)
		this._map.setCenter($marker.getLatLng());
		this.triggerClick($index);
	}
};

ClusterMarker.prototype._zoomEnd=function(){
	this._cancelMoveEnd=true;
	this.refresh(true);
};
// 
// 
var MapIconMaker = {};

MapIconMaker.createFlatIcon = function(opts) {

	var fileExt = 'png';
	if ($.browser.msie && $.browser.version < 7) fileExt = 'gif';
		
	// Google hosted icons
	if (!opts.i2profile)
	{
		var shapeCode = 'it';
		var baseUrl = 'http://chart.apis.google.com/chart?cht=' + shapeCode;
		var iconUrl = baseUrl
			+ '&chs=' + opts.width + 'x' + opts.height 
			+ '&chco='+ opts.primaryColor + ',000000,' + opts.shadowColor
			+ '&chl=' + opts.label
			+ '&chx=' + opts.labelColor + ',' + opts.labelSize
			+ '&chf=bg,s,00000000'
			+ '&chof=' + fileExt;
	}

	// Own icons
	else
	{
		iconUrl = 'http://static.mediamatic.nl/f/cgcz/i2/gmaps+'+opts.i2profile+'+'+opts.width+'+'+opts.label+'+'+opts.labelSize+'.'+fileExt+'';
	}

	var icon				= new GIcon(G_DEFAULT_ICON);
	icon.image		 		= iconUrl;
	icon.transparent		= iconUrl;

	icon.iconSize			= new GSize(opts.width, opts.height);
	icon.shadowSize			= new GSize(0, 0);
	icon.iconAnchor			= new GPoint(opts.width / 2, opts.height / 2);
	icon.infoWindowAnchor	= new GPoint(opts.width / 2, opts.height / 2);

	icon.imageMap = [];
	if (shapeCode === 'itr') {
		icon.imageMap = [0, 0, opts.width, 0, opts.width, opts.height, 0, opts.height];
	} else {
		var polyNumSides = 8;
		var polySideLength = 360 / polyNumSides;
		var polyRadius = Math.min(opts.width, opts.height) / 2;
		for (var a = 0; a < (polyNumSides + 1); a++) {
			var aRad = polySideLength * a * (Math.PI / 180);
			var pixelX = polyRadius + polyRadius * Math.cos(aRad);
			var pixelY = polyRadius + polyRadius * Math.sin(aRad);
			icon.imageMap.push(parseInt(pixelX), parseInt(pixelY));
		}
	}

	return icon;
};

/**
 * Utility function for doing special chart API escaping first,
 *	and then typical URL escaping. Must be applied to user-supplied text.
 * @private
 */
MapIconMaker.escapeUserText_ = function (text) {
	if (text === undefined) {
		return null;
	}
	text = text.replace(/@/, "@@");
	text = text.replace(/\\/, "@\\");
	text = text.replace(/'/, "@'");
	text = text.replace(/\[/, "@[");
	text = text.replace(/\]/, "@]");
	return encodeURIComponent(text);
};
// 
// 
/**
 * Infowindow. Styles are in gmaps.css
 * Blaise - March 2009
 */

function InfoWindow( map )
{
	this.visible = false;
	this.curxy = {x: -1, y: -1};
	
	var scope = this;

	GEvent.bind(map, 'zoomend', this, this.hide);
	GEvent.addListener(map, "dblclick", function(overlay, latlng) {     
		$('#infowindow-wrapper').css({display:'none'});
	});
} 

InfoWindow.prototype.initialize = function(map)
{
	var wrapperDiv = map.getPane(G_MAP_FLOAT_PANE);
	wrapperDiv.id = 'infowindow-wrapper';
	this.wrapperDiv = wrapperDiv;
}

InfoWindow.prototype.openOnMap = function(point, html)
{

	this.xy = map.fromLatLngToDivPixel(point);

	this.wrapperDiv.innerHTML = '<div id="infowindow-top"></div>'
		+ '<div id="infowindow-bottom">' + html + '</div>';

	this.show();
	this.redraw(true);
}

InfoWindow.prototype.openOnMarker = function(marker, html) 
{
	html = html || '';
	var vx = marker.getIcon().iconAnchor.x - marker.getIcon().infoWindowAnchor.x;
	var vy = marker.getIcon().iconAnchor.y - marker.getIcon().infoWindowAnchor.y;
	this.openOnMap(marker.getPoint(), html, new GPoint(vx, vy));
}


InfoWindow.prototype.redraw = function () 
{
	if (!this.visible) { return; }

	$(this.wrapperDiv).css({
		left	:  this.xy.x,
		bottom	: -this.xy.y
	});
}

InfoWindow.prototype.show = function()
{
	if ($.browser.msie) { this.wrapperDiv.style.display='block'; }
	else { $(this.wrapperDiv).stop().fadeIn(200); }
	this.visible = true;
	this.curxy = this.xy;
}

InfoWindow.prototype.hide = function() 
{
	if (!this.visible) return;

	if ($.browser.msie) { this.wrapperDiv.style.display='none'; }
	else { $(this.wrapperDiv).stop().fadeOut(200); }
	this.visible = false;
	this.curxy = {x: -1, y: -1};
	windowIds = [];
	
	if (mapPan && $('#map').hasClass('panback')) map.returnToSavedPosition();
}

// 
// 

/**
 * Adds a semi-transparent layer over the map 
 * to make markers stand out more
 * Blaise - March 2009
 */

function CurtainOverlay(){}

// Create curtain
CurtainOverlay.prototype.initialize = function()
{
	this.div = document.createElement('div');
	map.getPane(G_MAP_MAP_PANE).appendChild( this.div );
	$(this.div).attr('id', 'map-curtain')
}

// 