/*
 * Summary:
 * Estate.GoogleMaps returns an object that you can use to create a Google map.
 * you provide the object with a configuration object. You can choose to either
 * add a single location (by setting the config object) or a bunch of locations
 * by providing an URL to an xml file. If both are supplied the xml file rules
 * out the single location.
 * 
 * Usage:
	// START HTML
		<div id="map"></div>
		<div id="route"></div>
		
		<asp:TextBox ID="saddrWatermark" runat="server" TabIndex="100" ValidationGroup="route"></asp:TextBox>
		<ajaxToolkit:TextBoxWatermarkExtender runat="server" TargetControlID="saddrWatermark" WatermarkText="Bv. Beursplein 5, Amsterdam" />
		<input type="button" value="Bereken route" tabindex="101" validationgroup="route" />
	// END HTML
	
	// START JAVASCRIPT EXAMPLE 1 show one location
		var mapConfig = {
			mapId: 'map',
			mapKeys: {
				published: '[keystring]',
				ontwikkelOnline: '[keystring]',
				ontwikkelLocal: '[keystring]'
			},
			startLocation: {
				lng: 5.09206,
				lat: 51.57459,
				zoom: 13,
				text: 'Estate Internet'
			}
		}
		
		oMap = new Estate.GoogleMaps( mapConfig, "oMap" )
		oMap.Init()

		Estate.Events.AddEvent (
			document.getElementsByTagName('input')[0],
			function(e) {
				var KeyID = (window.event) ? event.keyCode : e.which;
				if (KeyID == 13) {
					Estate.GoogleMaps.Route.GetRouteInGoogleMaps( 'Vredesplein 5, Waalwijk', document.getElementById('saddr').value );
					return false;
				}
			},
			"onkeypress"
		)
	// END JAVASCRIPT EXAMPLE 1 
	
	// START JAVASCRIPT EXAMPLE 2 show multiple locations
		var mapConfig = {
			mapId: 'map',
			mapKeys: {
				published: '[keystring]',
				ontwikkelOnline: '[keystring]',
				ontwikkelLocal: '[keystring]'
			},
			locationsUrl: '/scripts/data/googleMaps-locations.xml',
		}
		
		oMap = new Estate.GoogleMaps( mapConfig, "oMap" )
		oMap.Init()
	// END JAVASCRIPT EXAMPLE 2

	// START JAVASCRIPT EXAMPLE 3: show route
		// Javascript: set click event on submit button
		Estate.GoogleMaps.Route.GetRouteInGoogleMaps()
		// ASP.NET codebehind: set enter event on textbox
		ClientScript.RegisterOnSubmitStatement(Me.GetType(), "submit", "return Estate.GoogleMaps.Route.GetRouteInGoogleMaps();")
	// END JAVASCRIPT EXAMPLE 3

	// START JAVASCRIPT EXAMPLE 4: load multiple maps on one page at once
		// You have to load the Google Maps code yourself before running
		   Estate.GoogleMaps. Otherwise only the last request will be successful.
		<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;sensor=false&amp;key=[GOOGLE MAPS KEY]" type="text/javascript"></script>
	// END JAVASCRIPT EXAMPLE 4
 */
Estate.GoogleMaps = ( function() {
	var Class = function() {
		/* START PRIVATE */
		var map;
		var aMarkers = new Array(0);
		var selectedMarker = {
			lat: 0,
			lng: 0
		};
		var config = {
			instanceName: '',
			mapId: 'map',
			mapKeys: {
				published: '',
				ontwikkelOnline: '',
				ontwikkelLocal: ''
			},
			mapConfig: {
				zoomControl: 'large',
				mapTypeControl: true,
				zoom: null,
				zoomBounds: {
					minimum: 1,
					maximum: 17
				}
			},
			startLocation: {
				lng: 5.09206,
				lat: 51.57459,
				zoom: 17,
				text: ''
			},
			centerMapLocation: {
				lng: undefined,
				lat: undefined
			},
			locationsUrl: '',
			markerImage: {
				url: '',
				dimensions: {
					width: '37',
					height: '31'
				},
				anchor: {
					xPosition: -1,
					yPosition: -1
				}
			},
			routeId: "route",
			routeNoDestination: "Selecteer eerst een bestemming voordat u een route kunt berekenen",
			textLoading: 'Bezig met laden kaart...',
			textBrowserIncompatible: 'Uw browser ondesteunt geen Google Maps of is zodanig ingesteld dat het niet ondersteunt.'
		}


		
		/* start getters, setters and checkers */
		function setConfig( newConfig, instanceName ) {
			var error
			error = Estate.Check.ArgumentsCount( arguments.length, [1,2] );
			if ( error != "" ) throw new Error( error );

			config.instanceName = instanceName;
			Estate.Check.UpdateLiteral( config, newConfig )
			
			Estate.GoogleMaps.Check.CheckConfig(config)
		}
		
		function getKey() {
			var error;
			error = Estate.Check.ArgumentsCount( arguments.length, 0 );
			if ( error != "" ) throw new Error( error );

			if (document.location.href.indexOf("ontwikkel.estate.nl") > 0 || document.location.href.indexOf("potemkin.estate.nl") > 0) {
				return config.mapKeys.ontwikkelLocal;
			} else if (document.location.href.indexOf("estate.nl") > 0 || document.location.href.indexOf("restyle") > 0) {
				return config.mapKeys.ontwikkelOnline;
			} else {
				return config.mapKeys.published;
			}
		}
		
		function mapKeysExists() {
			var error
			error = Estate.Check.ArgumentsCount(arguments.length, 0);
			if (error != "") throw new Error(error);
			
			Estate.Trace('key: ['+ getKey() +']')
			if (getKey() == '') {
				return false;
			}
			return true
		}
		
		function isLibraryLoaded() {
			if ( typeof(GBrowserIsCompatible) == 'undefined' ) {
				return false;
			}
			return true;
		}
		/* end getters, setters and checkers */



		function loadGoogleMapsLibrary() {
			var error;
			error = Estate.Check.ArgumentsCount( arguments.length, 0 );
			if ( error != "" ) throw new Error( error );
			if (mapKeysExists() == false) {
				throw new Error("Google Maps library not loaded and cannot be loaded dynamically without the appropriate key.");
			}
		
			var script = document.createElement( "script" );
			script.type = "text/javascript";
			script.src = "http://maps.google.com/maps?file=api&v=2.x&key="+ getKey() +"&async=2&callback="+ config.instanceName +".Init";
			document.body.appendChild(script);
		}
		
		function mapAddMarker( oGLatLng, locationText, configMarkerImage, locationsType ) {
			var error;
			error = Estate.Check.ArgumentsCount( arguments.length, 4 );
			if ( error != "" ) throw new Error( error );

			var newMarker = createMarker( oGLatLng, configMarkerImage );
			newMarker.LocationText = locationText;
			map.addOverlay( newMarker );
			var newMarkerLatLng = newMarker.getLatLng()
			if ( locationsType == "multiple locations" ) {
				GEvent.addListener(
					newMarker,
					"click",
					function() {
						if ( locationText != '' ) {
							newMarker.openInfoWindowHtml( locationText );
						}
						map.panTo( newMarkerLatLng );
						selectedMarker.lat = newMarkerLatLng.lat();
						selectedMarker.lng = newMarkerLatLng.lng();
					}
				);
			} else {
				selectedMarker.lat = newMarkerLatLng.lat();
				selectedMarker.lng = newMarkerLatLng.lng();
				if ( locationText != '' ) {
					newMarker.openInfoWindowHtml( locationText );
				}
			}
			var newMarkerId = aMarkers.length
			if (typeof(aMarkers[newMarkerId]) != "undefined") {
				newMarkerId += 1;
			}
			aMarkers[newMarkerId] = newMarker;
		}
		
		function createMarker( oGLatLng, configMarkerImage ) {
			var error;
			error = Estate.Check.ArgumentsCount( arguments.length, 2 );
			if ( error != "" ) throw new Error( error );

			var newMarker;
			if ( configMarkerImage.url != '' ) {
				// Create custom marker if available
				var markerIcon = new GIcon();
				markerIcon.image = configMarkerImage.url;
				markerIcon.iconSize = new GSize( configMarkerImage.dimensions.width, configMarkerImage.dimensions.height );
				if ( configMarkerImage.anchor.xPosition >= 0 && configMarkerImage.anchor.yPosition >= 0 ) {
					markerIcon.iconAnchor = new GPoint( configMarkerImage.anchor.xPosition, configMarkerImage.anchor.yPosition );
				} else {
					markerIcon.iconAnchor = new GPoint( Math.floor(configMarkerImage.dimensions.width / 2), configMarkerImage.dimensions.height );
				}
				markerIcon.infoWindowAnchor = new GPoint( Math.floor(configMarkerImage.dimensions.width / 2), 0 );
				return new GMarker( oGLatLng, markerIcon );
			} else {
				return new GMarker( oGLatLng );
			}
		}

		function mapSetZoomBounds() {
			var mapTypes = map.getMapTypes(); 
			for (var i=0; i<mapTypes.length; i++) {
				mapTypes[i].getMinimumResolution = function() {return config.mapConfig.zoomBounds.minimum;}
				mapTypes[i].getMaximumResolution = function() {return config.mapConfig.zoomBounds.maximum;}
			}
		}
		
		function loadExternalData( locationsUrl ) {
			var error;
			error = Estate.Check.ArgumentsCount( arguments.length, 1 );
			if ( error != "" ) throw new Error( error );

			if ( locationsUrl != '' ) {
				var point;
				var locationTextCollection;
				var location;
				var bounds = new GLatLngBounds();
				Estate.GoogleMaps.Check.CheckURL(locationsUrl)
				GDownloadUrl( locationsUrl, function( data, responseCode ) {
					var xml = GXml.parse(data);
					var markers = xml.documentElement.getElementsByTagName("marker");
					if (markers.length > 0) {
						for (var i = 0; i < markers.length; i++) {
							Estate.Check.UpdateLiteral(markerImage, config.markerImage);
							point = new GLatLng(parseFloat(markers[i].getAttribute("lat")), parseFloat(markers[i].getAttribute("lng")));
							bounds.extend(point);
							locationText = GXml.value(markers[i].getElementsByTagName("locationText")[0]);
							if (markers[i].getAttribute("imageUrl") != null) {
								markerImage.url = markers[i].getAttribute("imageUrl")
							}
							if (markers[i].getAttribute("width") != null) {
								markerImage.dimensions.width = markers[i].getAttribute("width")
							}
							if (markers[i].getAttribute("height") != null) {
								markerImage.dimensions.height = markers[i].getAttribute("height")
							}
							if (markers[i].getAttribute("anchorX") != null) {
								markerImage.anchor.xPosition = markers[i].getAttribute("anchorX")
							}
							if (markers[i].getAttribute("anchorY") != null) {
								markerImage.anchor.yPosition = markers[i].getAttribute("anchorY")
							}

							mapAddMarker(point, locationText, markerImage, "multiple locations");
						}
						zoomAndCenterOnAllMarkers(bounds);
					}
				});
			}
		}
		
		function zoomAndCenterOnAllMarkers( bounds ) {
			map.setCenter(bounds.getCenter());
			Estate.Events.AddEvent(
				window,
				function(){
					map.setCenter(bounds.getCenter());
				},
				"onresize"
			)
				
			if (typeof(config.mapConfig.zoom) == "number") {
				map.setZoom(config.mapConfig.zoom);
			} else {
				map.setZoom(map.getBoundsZoomLevel(bounds));
				Estate.Events.AddEvent(
					window,
					function(){
						map.setZoom(map.getBoundsZoomLevel(bounds));
						map.setCenter(bounds.getCenter());
					},
					"onresize"
				)
			}
		}

		function setCenter( startLocation ) {
			var centerPoint = startLocation
			if ( typeof(config.centerMapLocation.lng) != "undefined" && typeof(config.centerMapLocation.lat) != "undefined" ) {
				centerPoint = new GLatLng(config.centerMapLocation.lat, config.centerMapLocation.lng);
			}
			map.setCenter( centerPoint, config.startLocation.zoom );
		}
				
		function addControls() {
			var error;
			error = Estate.Check.ArgumentsCount( arguments.length, 0 );
			if ( error != "" ) throw new Error( error );
			
			
			if ( typeof(config.mapConfig.zoomControl) == "string" ) {
				switch(config.mapConfig.zoomControl) {
					case "large":
						map.addControl(new GLargeMapControl());
						break;
					case "small":
						map.addControl(new GSmallMapControl());
						break;
					case "smallest":
						map.addControl(new GSmallZoomControl());
						break;
				}
			}
			if ( typeof(config.mapConfig.mapTypeControl) == "boolean" ) {
				if ( config.mapConfig.mapTypeControl == true ) {
					map.addControl(new GMapTypeControl());
				}
			}
		}

		function createMap() {
			var error;
			error = Estate.Check.ArgumentsCount( arguments.length, 0 );
			if ( error != "" ) throw new Error( error );

			if ( GBrowserIsCompatible() ) {
				Estate.Events.AddEvent( window, GUnload, "onunload" )
				var startLocation = new GLatLng(config.startLocation.lat, config.startLocation.lng);

				map = new GMap2(document.getElementById(config.mapId));
				map.setCenter(startLocation, config.startLocation.zoom);
				addControls()
				map.enableScrollWheelZoom();
				mapSetZoomBounds();
				
				if ( config.locationsUrl != '' ) {
					loadExternalData( config.locationsUrl );
				} else {
					mapAddMarker( startLocation, config.startLocation.text, config.markerImage, "single location" );
				}
			} else {
				alert( config.textBrowserIncompatible );
			}
		}
		/* END PRIVATE */
		
		
		
		/* START PUBLIC */
		return function( newConfig, instanceName ) {
			var error
			error = Estate.Check.ArgumentsCount( arguments.length, 2 );
			if ( error != "" ) throw new Error( error );
			error = Estate.Check.LiteralUpdatable( config, newConfig );
			if ( error != "" ) throw new Error( error );

			setConfig( newConfig, instanceName );
			
			this.Init = function() {
				if ( isLibraryLoaded() == false ) {
					loadGoogleMapsLibrary();
				} else {
					Estate.Events.AddEvent( document, GUnload, "onunload" )
					createMap();
				}
			},
			
			this.LoadExternalData = function( newConfig ) {
				var error
				error = Estate.Check.ArgumentsCount( arguments.length, 1 );
				if ( error != "" ) throw new Error( error );
				error = Estate.Check.VariableType( newConfig, "object" );
				if ( error != "" ) throw new Error( error );
				error = Estate.Check.VariableType( newConfig.locationsUrl, "string" );
				if ( error != "" ) throw new Error( error );
				if ( config.locationsUrl == '') {
					throw new Error( "URL string is empty!" )
				}

				setConfig( newConfig )
				map.clearOverlays()
				loadExternalData( config.locationsUrl )
			},

			this.Goto = function( index ) {
				var error
				error = Estate.Check.ArgumentsCount( arguments.length, 1 );
				if ( error != "" ) throw new Error( error );
				error = Estate.Check.VariableType( index, "number" );
				if ( error != "" ) throw new Error( error );
				
				map.panTo(aMarkers[index].getLatLng())
				aMarkers[index].openInfoWindowHtml( aMarkers[index].LocationText );
			},			

			this.GetRoute = function( routeId, startLocation ) {
				var error
				error = Estate.Check.ArgumentsCount( arguments.length, 2 );
				if ( error != "" ) throw new Error( error );
				error = Estate.Check.ElementById( routeId );
				if ( error != "" ) throw new Error( error );
				error = Estate.Check.VariableType( startLocation, "string" );
				if ( error != "" ) throw new Error( error );
				
				if ( selectedMarker.lat == 0 || selectedMarker.lng == 0 ) {
					alert( config.routeNoDestination )
				}
				
				map.closeInfoWindow()
				Estate.GoogleMaps.Route.Init( routeId, startLocation, map, selectedMarker.lat, selectedMarker.lng )
				
				return false
			}
		}
		/* END PUBLIC */
	}()

	return Class;
})();






/* Code for makeing a route */
Estate.GoogleMaps.Route = ( function() {
	/* START PRIVATE */
	var routePanel;
	/* END PRIVATE */

	
	
	/* START PUBLIC */
	return {
		Init: function( routeId, startLocation, map, lat, lng ) {
			var error
			error = Estate.Check.ArgumentsCount( arguments.length, 5 );
			if ( error != "" ) throw new Error( error );
			error = Estate.Check.ElementById( routeId );
			if ( error != "" ) throw new Error( error );
			
			_routeId = routeId
			routePanel = document.getElementById(routeId);
			routePanel.innerHTML = ""
			Estate.CSSTools.RemoveClass( routePanel, "displayNone" )
			var directions = new GDirections(map, routePanel);
			GEvent.addListener(directions, "error", Estate.GoogleMaps.Route.ShowStatusError );
        	directions.clear()
			directions.load("from: "+ startLocation +" to: " + lat + ", " + lng);
		},

		ShowStatusError: function() {
			alert('Route kan niet geladen worden. Misschien heeft u geen geldig adres ingevoerd.')
			Estate.CSSTools.AddClass( routePanel, "displayNone" )
		},

		GetRouteInGoogleMaps: function(destinationAddress, startAddress) {
			window.open("http://maps.google.nl/maps?daddr="+ escape(destinationAddress) +"&geocode=&dirflg=&saddr="+ escape(startAddress) +"&f=d&sspn=0.010732,0.022488&ie=UTF8")
		},
		
		GetRouteInGoogleMapsLngLat: function(lng, lat, startAddress) {
			window.open("http://maps.google.nl/maps?daddr="+ escape(lng) +",+"+ escape(lat) +"&geocode=&dirflg=&saddr="+ escape(startAddress) +"&f=d&sspn=0.010732,0.022488&ie=UTF8")
		}
	}
})();






/* Checks for Google Maps code */
Estate.GoogleMaps.Check = ( function() {
	function httpRequest() {
		var obj;
		if (window.XMLHttpRequest) obj= new XMLHttpRequest(); 
		else if (window.ActiveXObject){
			try{
				obj= new ActiveXObject('MSXML2.XMLHTTP.3.0');
			}
			catch(er){
				try{
					obj= new ActiveXObject("Microsoft.XMLHTTP");
				}
				catch(er){
					obj= false;
				}
			}
		}
		return obj;
	}

	/* START PUBLIC */
	return {
		CheckConfig: function( config ) {
			var error
			error = Estate.Check.ArgumentsCount( arguments.length, 1 );
			if ( error != "" ) throw new Error( error );
			error = Estate.Check.VariableType( config, "object" );
			if ( error != "" ) throw new Error( error );
			
			error = Estate.Check.ElementById( config.mapId );
			if ( error != "" ) throw new Error( error );			
			error = Estate.Check.VariableType( config.startLocation.lng, "number" );
			if ( error != "" ) throw new Error( error );
			error = Estate.Check.VariableType( config.startLocation.lat, "number" );
			if ( error != "" ) throw new Error( error );
		},
		
		CheckURL: function( locationsUrl ) {
			var oHttpRequest = new httpRequest();
			oHttpRequest.open("HEAD", locationsUrl, false);
			oHttpRequest.send(null);		
			if (oHttpRequest.status != 200) {
				throw new Error( "Received an " + oHttpRequest.status +"-error while loading the URL '"+ locationsUrl +"'" )
			}
		}
	}
})();

