/* DOCUMENTATION

Initialization
Include the following lines in the <head> section:
	<script type="text/javascript" src="http://www.google.com/jsapi?key=GOOGLE_MAPS_API_KEY"></script>
	<script type="text/javascript" src="google_maps.js"></script>
	<link media="all" rel="stylesheet" href="google_maps.css" type="text/css" />

Make sure the html element includes an XML namespace declaration for the prefix 'map':
	<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:map="http://creuna.dk/google_maps">

(Replace the Google Maps API key with a key matching the server's domain.)

Maps
To add a Google map, add a div element and add the class "google_map":
	<div id="first_map" class="google_map"></div>

Specifying starting position
You must speficy the size of the map using css (either inline as style="width: 200px; height: 200px" or be specifying one or more additional styles) as the default size is 0,0 (i.e. invisible).
To specify the center of the map (default is the Eiffel Tower in Paris) use either coordinates or an address as attributes on the div. (Note that all map-specific attributes are prefixed with "map:").

Latitude and longitude coordinates
	mat:lat="[latitude (float)]" map:lng="[longitude (float)]"
	<div id="first_map" class="google_map" style="width: 600px; height: 400px" map:lat="55.6882" map:lng="12.5905"></div>

Address
	map:address="[street, city, country]"
	<div id="first_map" class="google_map" style="width: 600px; height: 400px" map:address="hammerensgade 4, kÃ¸benhavn, dk"></div>
 
Zoom level can be specified with the map:zoom attribute (default is 15)
	map:zoom="[zoom level (integer)]"
	<div id="first_map" class="google_map" style="width: 600px; height: 400px" map:lat="55.6882" map:lng="12.5905" map:zoom="17"></div>

Controls can be added to the map by specifying a comma- (or space-) separated string in the map:controls attribute with the names (from the Google Maps API) of the controls.
The possible controls are:
- GLargeMapControl - a large pan/zoom control used on Google Maps. Appears in the top left corner of the map by default.
- GSmallMapControl - a smaller pan/zoom control used on Google Maps. Appears in the top left corner of the map by default.
- GSmallZoomControl - a small zoom control (no panning controls) used in the small map blowup windows used to display driving directions steps on Google Maps.
- GScaleControl - a map scale
- GMapTypeControl - buttons that let the user toggle between map types (such as Map and Satellite)
- GOverviewMapControl- a collapsible overview map in the corner of the screen
	map:controls="GLargeMapControl|GSmallMapControl|GSmallZoomControl|GScaleControl|GMapTypeControl|GOverviewMapControl"
	<div id="other_map" class="google_map medium_map" map:type="hybrid" map:address="times square, ny" map:zoom="17" map:controls="GMapTypeControl, GLargeMapControl, GScaleControl"></div>


<div class="google_map"
	map:address=""
	map:lat=""
	map:lng=""
	map:zoom=""
	map:controls="">
	
	<div class="google_marker"
		map:parent=""
		map:lat=""
		map:lng=""
		map:googleIcon=""
		map:icon="image.png"
		map:iconSize="10,30"
		map:shadow="image.png"
		map:shadowSize="28,31"
		map:iconAnchor="5,28"
		map:infoWindowAnchor="3,0" >
	
			info window html
		
			<div map:tabTitle="">
				info window tab html
			</div>

	</div>

</div>

markers JSON file format:
[
    {"lat":"55.687897356076505", "lng":"12.589666843414307", "icon":"google_maps_icons/blue_marker.png"},
    {"lat":"55.688272321016775", "lng":"12.589570283889770", "icon":"google_maps_icons/green_markerX.png", "infoWindowTabs":
    [
       {"title":"Adresse", "html":"Who knows?..."},
       {"title":"Aktiviteter", "html":"Who cares?..."}
    ]},
    {"lat":"55.688683568752310", "lng":"12.589634656906128", "icon":"google_maps_icons/green_markerY.png", "infoWindowHtml":"Her <b>er</b> faktisk noget."},
    {"lat":"55.687383285395040", "lng":"12.590214014053345", "icon":"google_maps_icons/blue_marker.png"},
    {"lat":"55.687915499624150", "lng":"12.590578794479370", "icon":"google_maps_icons/blue_marker.png"}
]
*/


// global vars
// load api
google.load("maps", "2.x", {"language" : "da"});


var Creuna = {};
Creuna.GoogleMaps = 
{
	// "global" vars
	maps: {},
	geocoder: {loaded: false},

// Call this function when the page has been loaded
	initialize: function( baseCountryCode ) 
	{
	// find all <div class="google_map"> elements
	// we need to copy all existing divs into a new array since document.getElementsByTagName() will change as new dics are added to the document (tiles and markers)
	var origDivs = document.getElementsByTagName('DIV');
	var divs = [];
	for( var i = 0; i<origDivs.length; i++ )
		divs.push( origDivs[ i ] );
		
	for( i=0; i<divs.length; i++ )
	{
		if( this.arrayContains( divs[ i ].className.split(' '), 'google_map' ))
		{
			var map_div = divs[ i ];
			var map_id = map_div.id;
			this.maps[ map_id ] = new google.maps.Map2( map_div );
			this.maps[ map_id ][ "addDraggableMarker" ] = this._addDraggableMarker;
			this.maps[ map_id ][ "addStaticMarker" ] = this._addStaticMarker;
			this.maps[ map_id ][ "loadMarkersFromJson" ] = this._loadMarkersFromJson;
			this.maps[ map_id ][ "goToAddress" ] = this._goToAddress;

			// extract properties
			// map:zoom -> zoom level
			var zoom = map_div.getAttribute( 'map:zoom' );
			if( zoom )
			{
				zoomLevel = Number( zoom );
			}
			else
				zoomLevel = 15;

			// c:lat and c:lng -> center coordinates
			var lat = map_div.getAttribute( 'map:lat' );
			var lng = map_div.getAttribute( 'map:lng' );
			if( lat && lng )
				center  = new google.maps.LatLng( lat, lng );
			else
			{
				// there is no coordinates specified. see if an address has been specified
				var address = map_div.getAttribute( 'map:address' );
				if( address )
				{
					// yes, we have an address. let's try and geocode it
					if( Creuna.GoogleMaps.geocoder.loaded == false )
					{
						Creuna.GoogleMaps.geocoder = new GClientGeocoder();
						if( baseCountryCode != null )
						{
							Creuna.GoogleMaps.geocoder.setBaseCountryCode( baseCountryCode );
						}
					}
										
					Creuna.GoogleMaps.geocoder.getLatLng( address, this.createGeocoderReturnFunction( map_id, zoomLevel ));
				}
				center = new google.maps.LatLng( 48.85850346934554, 2.2945117950439453 );
			}
			
			this.maps[ map_id ].setCenter( center, zoomLevel );

			// map:view = "map" | "satellite" | "hybrid" -> default view
			var view = map_div.getAttribute( 'map:type' );
			switch( view )
			{
				case 'satellite':
					type = G_SATELLITE_MAP;
					break;
					
				case 'hybrid':
					type = G_HYBRID_MAP;
					break;
					
				case 'map':
				default:
					type = G_NORMAL_MAP;
					break;
			}
			this.maps[ map_id ].setMapType( type );

				
			// map:controls -> add map controls
			var controls = map_div.getAttribute( 'map:controls' );
			if( controls )
			{
				var controlsListArr = controls.split( /[,\s]/ );
				for( r in controlsListArr )
				{
					if( typeof( controlsListArr[ r ] ) == "string" )
						switch( controlsListArr[ r ].toLowerCase() )
						{
							case 'glargemapcontrol':
								this.maps[ map_id ].addControl( new GLargeMapControl() );
								break;
							
							case 'gsmallmapcontrol':
								this.maps[ map_id ].addControl( new GSmallMapControl() );
								break;

							case 'gsmallzoomcontrol':
								this.maps[ map_id ].addControl( new GSmallZoomControl() );
								break;

							case 'gscalecontrol':
								this.maps[ map_id ].addControl( new GScaleControl() );
								break;

							case 'gmaptypecontrol':
								this.maps[ map_id ].addControl( new GMapTypeControl() );
								break;

							case 'goverviewmapcontrol':
								this.maps[ map_id ].addControl( new GOverviewMapControl() );
								break;
							
							case 'googlebar':
								this.maps[ map_id ].enableGoogleBar();
								break;
						}	// end-switch
				} 		// end-for
			}			// end-if (controls)
			
		}		// end-if (className contains google_maps)
		
		// <div class="google_marker"> -> markers
		else if( divs[ i ].className == 'google_marker' )
		{
			// div has correct class. does it have a map:parent attr?
			var marker_div = divs[ i ];
			var parent_map_id = marker_div.getAttribute( 'map:parent' );
			if( parent_map_id )
			{
				// yes: map:parent is present. does it have map:lat and map:lng?
				marker_lat = marker_div.getAttribute( 'map:lat' );
				marker_lng = marker_div.getAttribute( 'map:lng' );
				
				// get address for geocoding if it exists
				marker_address = marker_div.getAttribute( 'map:address' );

				if( (marker_lat && marker_lng) || marker_address )
				{
					// yes: coordinates are present. do we have custom map:icon specification?
					if( marker_div.getAttribute( 'map:icon' ))
					{
						// yes: extract all custom marker attributes
						iconUrl			= marker_div.getAttribute( 'map:icon');
						iconSize		= marker_div.getAttribute( 'map:iconSize');
						iconShadowUrl	= marker_div.getAttribute( 'map:shadow');
						iconShadowSize	= marker_div.getAttribute( 'map:shadowSize');
						iconAnchor		= marker_div.getAttribute( 'map:iconAnchor');
						iconInfoAnchor	= marker_div.getAttribute( 'map:infoWindowAnchor');

						// create custom icon and set attrs
						customIcon = new GIcon();
						customIcon.image = iconUrl;
						customIcon.shadow = iconShadowUrl;
						customIcon.iconSize = new GSize( Number( iconSize.split(',')[0] ), Number( iconSize.split(',')[1] ));
						customIcon.shadowSize = new GSize( Number( iconShadowSize.split(',')[0] ), Number( iconShadowSize.split(',')[1] ));
						customIcon.iconAnchor = new GPoint( Number( iconAnchor.split(',')[0] ), Number( iconAnchor.split(',')[1] ));
						customIcon.infoWindowAnchor = new GPoint( Number( iconInfoAnchor.split(',')[0] ), Number( iconInfoAnchor.split(',')[1] ));

						// Set up our GMarkerOptions object literal
						markerOptions = { icon:customIcon };
					}	// end-if (has map:icon attr)
					else if( marker_div.getAttribute( 'map:googleIcon' ))
					{
						// no, but we have google style icon
						customIcon = new GIcon( G_DEFAULT_ICON );
						customIcon.image = marker_div.getAttribute( 'map:googleIcon' );
						markerOptions = { icon: customIcon };
					}
					else
						// no custom icon
						markerOptions = null;
					
					// does the marker div contain html for info window?
					if( marker_div.innerHTML != '' )
					{
						// iterate innerHTML and add key/value from <div map:tabTitle="key">value</div>
						var tabs = {};
						var hasTabs = false;
						for( r in marker_div.childNodes )
						{
							if( marker_div.childNodes[ r ].tagName == 'DIV' )
							{
								// found <div>: use tabs in info window
								hasTabs = true;
								tabs[ marker_div.childNodes[ r ].getAttribute( 'map:tabTitle' ) ] = marker_div.childNodes[ r ].innerHTML;
							}
						}

						// add tabs or simple info window
						var markerOverlay;
						if( hasTabs )
						{
							if( marker_address )
								this.createMarkerTabsAddress( parent_map_id, marker_address, markerOptions, tabs );
							else
							{
								markerOverlay = this.createMarkerTabs( marker_lat, marker_lng, markerOptions, tabs);
								this.maps[ parent_map_id ].addOverlay( markerOverlay );
							}
						}
						else
						{
							if( marker_address )
								this.createMarkerSimpleAddress( parent_map_id, marker_address, markerOptions, marker_div.innerHTML );
							else
							{
								markerOverlay = this.createMarkerSimple( marker_lat, marker_lng, markerOptions, marker_div.innerHTML);
								this.maps[ parent_map_id ].addOverlay( markerOverlay );
							}
						}
						
						if( marker_div.id )
						{
							if( !this.maps[ parent_map_id ].markers )
								this.maps[ parent_map_id ].markers = {};
							
								this.maps[ parent_map_id ].markers[ marker_div.id ] = markerOverlay;
						}	// end-if (marker_div.id)
					}		// end-if (marker_div has innerHTML)
					else
					{
						if( marker_address )
							// simple marker from address
							this.createMarkerSimpleAddress( parent_map_id, marker_address, markerOptions, null );	
						else
							// simple marker with coords
							this.maps[ parent_map_id ].addOverlay( this.createMarkerSimple( marker_lat, marker_lng, markerOptions, null ));
					}
				}	// end-if (has lat and lng)
			}		// end-if (har map:parent)
		}			// end-if (class is google_marker)
	}				// end-for (all divs)
},					// end-function (initialize)

// closure function for adding a marker from geocoding
createMarkerSimpleAddress: function( map_name, address, markerOptions, infoWindowHtml )
{
	if( Creuna.GoogleMaps.geocoder.loaded == false )
		Creuna.GoogleMaps.geocoder = new GClientGeocoder();
		
	Creuna.GoogleMaps.geocoder.getLatLng( address,  function( point )
													{
														if( point )
														{
															Creuna.GoogleMaps.maps[ map_name ].addOverlay( Creuna.GoogleMaps.createMarkerSimple( point.lat(), point.lng(), markerOptions, infoWindowHtml ));
														}
													} );
},

// closure funtion for adding a marker from geocoding with tabs
createMarkerTabsAddress: function( map_name, address, markerOptions, tabs )
{
	if( Creuna.GoogleMaps.geocoder.loaded == false )
		Creuna.GoogleMaps.geocoder = new GClientGeocoder();
		
	Creuna.GoogleMaps.geocoder.getLatLng( address,  function( point )
													{
														if( point )
														{
															Creuna.GoogleMaps.maps[ map_name ].addOverlay( Creuna.GoogleMaps.createMarkerTabs( point.lat(), point.lng(), markerOptions, tabs ));
														}
													} );
},

// closure function for adding an onClick handler to a marker with a simple html info window
createMarkerSimple: function( lat, lng, markerOptions, infoWindowHtml )
{
	// initialize marker with position and options if specified
	var marker;
	if( markerOptions != null )
	 	marker = new GMarker( new GLatLng( lat, lng ), markerOptions );
	else
		marker = new GMarker( new GLatLng( lat, lng ));
	
	// add event listener and return marker
	if( infoWindowHtml )
	{
		var tabArray = [];
		tabArray.push( new GInfoWindowTab( 'Info', infoWindowHtml ));
		tabArray.push( new GInfoWindowTab( 'Directions', '<strong id="from_header">Get directions to here from:</strong><br /><form id="from_address" class="menu_form" onsubmit="return false"><dl class="pane"><dt>Address</dt><dd><input type="text" name="from_street" id="from_street" class="textfield" /></dd><dt>City</dt><dd><input type="text" name="from_city" id="from_city" class="textfield" value="kÃ¸benhavn"/></dd><dt></dt><dd><input type="submit" onclick="getDirectionsFromCoords( ' + lat + ',' + lng + ' )" value="Get directions" class="formbutton" /></dd></dl></form>' ));
		GEvent.addListener( marker, "click", function() { marker.openInfoWindowHtml( infoWindowHtml ) } );		// comment out this line to include "Directions" tab 
//		GEvent.addListener( marker, "click", function() { marker.openInfoWindowTabsHtml( tabArray ) } );		// comment in this line to include "Directions" tab
//		GEvent.addListener( marker, "mouseover", function() { marker.openInfoWindowHtml( infoWindowHtml ) } );	// comment out this line to disable window popup on mouseover
	}
	return marker;
},

// closure function for adding an onClick handler to a marker with a html tabs info window
createMarkerTabs: function( lat, lng, markerOptions, tabs )
{
	// initialize marker with position and options if specified
	var marker;
	if( markerOptions != null )
	 	marker = new GMarker( new GLatLng( lat, lng ), markerOptions );
	else
		marker = new GMarker( new GLatLng( lat, lng ));
	
	// iterate all objects and add as tabs
	var tabArray = [];
	for( tabTitle in tabs)
	{
		var tab = new GInfoWindowTab( tabTitle, tabs[ tabTitle ] );
		tabArray.push( tab );
	}

	// add event listener and return marker
	GEvent.addListener( marker, "click", function() {marker.openInfoWindowTabsHtml( tabArray )} );
//	GEvent.addListener( marker, "mouseover", function() {marker.openInfoWindowTabsHtml( tabArray )} );		// comment out this line to disable window popup in mouseover
	return marker;
},

// closure function to create a geocoding callback function
createGeocoderReturnFunction: function( map_id, zoomLevel )
{
	func =	function( point )
			{
				if( !point ) 
				{
				//	alert(address + " not found");
				}
				else
				{
					Creuna.GoogleMaps.maps[ map_id ].setCenter( point, zoomLevel );
				}
			}
			
	return func;
},

// set onLoad handler
// google.setOnLoadCallback( initialize );

// an instance of this function is attached to all maps and is invoked with
// Creuna.GoogleMaps.maps.map_name.panToAddress( 'address', true )
// 
// address		complete address to geocode
// pan			(Boolean) if true, use panTo, otherwise use setCenter
_goToAddress: function( address, pan )
{
	// return immediately if no address is given
	if( !address || address == '' )
		return;
		
	// create geocoder instance if not already done
	if( Creuna.GoogleMaps.geocoder.loaded == false )
	{
		Creuna.GoogleMaps.geocoder = new GClientGeocoder();
	}

	var targetMap = this;
	
	// geocode and pan
	Creuna.GoogleMaps.geocoder.getLatLng( address, function( point )
			{
				if( !point ) 
				{
				//	alert(address + " not found");
				}
				else
				{
					if( pan )
						targetMap.panTo( point );
					else
						targetMap.setCenter( point );
				}
			});
},

// an instance of this function is attached to all maps
// it can be activated with
//	maps.map_name.addDraggableMarker( input_field_id )
//
// the ID of a an input field can be passed as a parameter to the function. The value property of this element will be updated with the marker's position on every dragEnd event.
_addDraggableMarker: function( coordDivId, customIconUrl )
{
	var marker;
	
	if( customIconUrl && customIconUrl != '' )
	{
		customIcon = new GIcon( G_DEFAULT_ICON );
		customIcon.image = customIconUrl;
		markerOptions = { icon: customIcon, draggable: true };
		
		marker = new GMarker( this.getCenter(), markerOptions );
		
	}
	else
		marker = new GMarker( this.getCenter(), {draggable: true});

	if( coordDivId && coordDivId != '' )
	{
		document.getElementById( coordDivId ).value = marker.getLatLng().toString();
		GEvent.addListener(marker, "dragend", function() 
											  {
												document.getElementById( coordDivId ).value = marker.getLatLng().toString();
		  									  } );
	}
	this.addOverlay(marker);
},

// adds a simple (non-draggable) marker at the specified coordinates
// a custom (Google style) icon can be used by specifying the url to the icon image file
// the function is attached to the maps and can be called with
//		maps.map_name.addStaticMarker( 52.123, 12.23434, 'http://site.com/images/google_Purple.png' )
_addStaticMarker: function( lat, lng, customIconUrl )
{
	if( customIconUrl && customIconUrl != '' )
	{
		customIcon = new GIcon( G_DEFAULT_ICON );
		customIcon.image = customIconUrl;
		markerOptions = { icon: customIcon };
		
		this.addOverlay( new GMarker( new GLatLng( lat, lng ), markerOptions ));
	}
	else
		this.addOverlay( new GMarker( new GLatLng( lat, lng )));
},

// Creuna.GoogleMaps.addMarker( 'map2', 55.6472528, 12.5500452, {image: 'http://dev.metro/Metro/google-maps/arrow.png',shadow: 'http://dev.metro/Metro/google-maps/arrowshadow.png', iconSize: new GSize( 23, 23 ), shadowSize: new GSize( 23, 23 ), iconAnchor: new GPoint( 8,23 )} )
// 
addMarker: function( mapName, lat, lng, customIconParameters )
{
	if( customIconParameters )
	{
		var customIcon = new GIcon( G_DEFAULT_ICON );
		for( property in customIconParameters )
		{
			customIcon[ property ] = customIconParameters[ property ];
		}
		var markerOptions = { icon: customIcon };
		var marker = new GMarker( new GLatLng( lat, lng ), markerOptions);
		this.maps[ mapName ].addOverlay( marker );
		
		return marker;
	}
	else
		this.maps[ mapName ].addOverlay( new GMarker( new GLatLng( lat, lng )));
},

// loads and shows markers from a JSON formatted file
// the function can be called with
//		maps.name_name.loadMarkersFromJson( '/file_path/file.json' );
//
// the format of the JSON file is as follows:
//		[
//		    {"lat":"55.687897356076505", "lng":"12.589666843414307", "icon":"google_maps_icons/blue_marker.png"},
//		    {"lat":"55.688272321016775", "lng":"12.589570283889770", "icon":"google_maps_icons/green_markerX.png", "infoWindowTabs":
//		    [
//		       {"title":"Adresse", "html":"Who knows?..."},
//		       {"title":"Aktiviteter", "html":"Who cares?..."}
//		    ]},
//		    {"lat":"55.688683568752310", "lng":"12.589634656906128", "icon":"google_maps_icons/green_markerY.png", "infoWindowHtml":"Her <b>er</b> faktisk noget."},
//		    {"lat":"55.687383285395040", "lng":"12.590214014053345", "icon":"google_maps_icons/blue_marker.png"},
//		    {"lat":"55.687915499624150", "lng":"12.590578794479370", "icon":"google_maps_icons/blue_marker.png"}
//		]
//
// i.e. it must contain an array of objects with "lat" and "lng" properties and optional "icon" and either "infoWindowHtml" or "infoWindowTabs" objects.
// the "infoWindowTabs" object must be an array of objects with "title" and "html" properties
//
// if the second parameter is true, markers are only added if no marker is currently present in the jsonMarkers array with the same coords (even if the rest of the info is different)
_loadMarkersFromJson: function( url, onlyNewMarkers )
{
	var parentMap = this;
	
	// create XmlHttp request and load
	var request = GXmlHttp.create();
	request.open( "GET", url, true );
	
	// set "complete" event handler
	request.onreadystatechange = function() 
	{
  		if( request.readyState == 4) 
		{
			if( !parentMap.jsonMarkers )
				parentMap.jsonMarkers = [];
			
			var marker;
			
			var centerLatMin = 99999, centerLatMax = -99999;
			var centerLngMin = 99999, centerLngMax = -99999;

			var markers = eval( request.responseText );
			
			for( i in markers )
			{
            	// get coordinates
            	var lat = parseFloat( markers[ i ].lat );
            	var lng = parseFloat( markers[ i ].lng );
				
				// find min/max marker positions
				if (lat < centerLatMin)
					centerLatMin = lat;
				if (lat > centerLatMax)
					centerLatMax = lat;
					
				if (lng < centerLatMin)
					centerLngMin = lng;
				if (lng > centerLngMax)
					centerLngMax = lng;

            	// has a custom icon been specified (icon="http://...")
            	if( markers[ i ].icon )
            	{
            		customIcon = new GIcon( G_DEFAULT_ICON );
            		customIcon.image = markers[ i ].icon;
            		markerOptions = { icon: customIcon };
            	}
				// has a custom icon been specified (customIcon:)
				else if( markers[ i ].customIcon )
				{
					customIcon = new GIcon();
					customIcon.image = markers[ i ].customIcon.iconUrl;
					customIcon.shadow = markers[ i ].customIcon.iconShadowUrl;
					customIcon.iconSize = new GSize( Number( markers[ i ].customIcon.iconSize.split(',')[0] ), Number( markers[ i ].customIcon.iconSize.split(',')[1] ));
					customIcon.shadowSize = new GSize( Number( markers[ i ].customIcon.iconShadowSize.split(',')[0] ), Number( markers[ i ].customIcon.iconShadowSize.split(',')[1] ));
					customIcon.iconAnchor = new GPoint( Number( markers[ i ].customIcon.iconAnchor.split(',')[0] ), Number( markers[ i ].customIcon.iconAnchor.split(',')[1] ));
					customIcon.infoWindowAnchor = new GPoint( Number( markers[ i ].customIcon.iconInfoAnchor.split(',')[0] ), Number( markers[ i ].customIcon.iconInfoAnchor.split(',')[1] ));
					markerOptions = { icon: customIcon };
				}
            	else
            		markerOptions = null;

				// info window html?
				if( markers[ i ].infoWindowHtml )
				{
					marker = Creuna.GoogleMaps.createMarkerSimple( lat, lng, markerOptions, markers[ i ].infoWindowHtml );
//					parentMap.addOverlay( Creuna.GoogleMaps.createMarkerSimple( lat, lng, markerOptions, markers[ i ].infoWindowHtml ) );
				}
				
				// info window tabs?
				else if( markers[ i ].infoWindowTabs )
				{
					tabs = {};
					for( r in markers[ i ].infoWindowTabs )
					{
						tabs[ markers[ i ].infoWindowTabs[ r ].title ] = markers[ i ].infoWindowTabs[ r ].html;
					}
					marker = Creuna.GoogleMaps.createMarkerTabs( lat, lng, markerOptions, tabs );
//					parentMap.addOverlay( Creuna.GoogleMaps.createMarkerTabs( lat, lng, markerOptions, tabs ) );
				}
				
				// neither info window html or info window tabs: add simple tab
				else
					marker = Creuna.GoogleMaps.createMarkerSimple( lat, lng, markerOptions, null );
//					parentMap.addOverlay( Creuna.GoogleMaps.createMarkerSimple( lat, lng, markerOptions, null ));
				
				if( onlyNewMarkers )
				{
					// check if the a marker with the same coords already exists
					var exists = false;
					for( i in parentMap.jsonMarkers )
						if( parentMap.jsonMarkers[ i ].getLatLng().lat() == lat && parentMap.jsonMarkers[ i ].getLatLng().lng() == lng )
						{
							exists = true;
							break;	// no need to continue iteration
						}

					// if no marker with these coords exist...
					if( !exists )
					{
						// ... add it
						parentMap.addOverlay( marker );
						parentMap.jsonMarkers.push( marker );
					}
				}
				else
				{
					// just add the marker
					parentMap.addOverlay( marker );
					parentMap.jsonMarkers.push( marker );
				}
				
			}
			
			// place map in the center of markers
			/* Comment in this section to enable auto-zoom to loaded markers
			var centerLat = centerLatMin + (centerLatMax - centerLatMin) / 2;
			var centerLng = centerLngMin + (centerLngMax - centerLngMin) / 2;

			var bounds = new GLatLngBounds(new google.maps.LatLng(centerLatMin, centerLngMin), new google.maps.LatLng(centerLatMax, centerLngMax));			
			var zoom = parentMap.getBoundsZoomLevel(bounds);
			parentMap.setCenter(new google.maps.LatLng(centerLat, centerLng), zoom);
			*/
			
		} // end-if (readyState==4)
	} // end-inline-function
	
	request.send( null );
},

// utility function to test whether an array contains the specified element
// (this is necessary because IE does not support Array.indexOf)
arrayContains: function( array, element )
{
	for( var c=0; c < array.length; c++ )
		if( array[ c ] == element )
			return true;
	
	return false;
},

Metro: 
{
	addMarker: function( mapId, lat, lng )
	{
		Creuna.GoogleMaps.addMarker( mapId, lat, lng, {image: 'http://dev.metro/Metro/google-maps/arrow.png',shadow: 'http://dev.metro/Metro/google-maps/arrowshadow.png', iconSize: new GSize( 23, 23 ), shadowSize: new GSize( 23, 23 ), iconAnchor: new GPoint( 7,23 )} )
	}
}
};