/*
 * 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()
	// 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" />
	// END JAVASCRIPT EXAMPLE 4
 */
Estate.GoogleMaps = (function() {
	var Class = function() {
		/* START PRIVATE */
		var map;
		var selectedMarker = {
			lat: 0,
			lng: 0
		};
		var config = {
			instanceName: '',
			mapId: 'map',
			mapKeys: {
				published: 'ABQIAAAABhsGdFqRSZLtKMbwb0G6lRQaiO2_Qty37uMyB1b9HqlUelpYQRQuV3UMSOGd3qmrVPdj8He88ZSySw',
				ontwikkelOnline: 'ABQIAAAABhsGdFqRSZLtKMbwb0G6lRTLZ5Djto5-BcZkFW6Kd0jaNewOEBRuyzjPHA8yr6O8E3u19VeLc0hYyg',
				ontwikkelLocal: 'ABQIAAAAW-zLW7LxJfj9zjXmYDl2wxT7zD-Q1Tu5tk6j7XjhlzsYo4OJLhRSzJ2ywH-nKhsc2dih43uxqkEGSg'
			},
			mapConfig: {
				zoomControl: 'large',
				mapTypeControl: true,
				zoomBounds: {
					minimum: 7,
					maximum: 17
				}
			},
			startLocation: {
				lng: 5.09065,
				lat: 51.56042,
				zoom: 12,
				text: ''
			},
			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)
		}

		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) {
				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);
			map.addOverlay(newMarker);
			var newMarkerLatLng = newMarker.getLatLng()
			selectedMarker.lat = newMarkerLatLng.lat()
			selectedMarker.lng = newMarkerLatLng.lng()
			if (locationsType == "multiple locations") {
				GEvent.addListener(
					newMarker,
					"click",
					function() {
						if (locationText != '') {
							newMarker.openInfoWindowHtml("<div class='infoWindow'>" + locationText +"</div>");
						}
						map.panTo(newMarkerLatLng);
					}
				);
			} else {
				if (locationText != '') {
					newMarker.openInfoWindowHtml(locationText);
				}
			}
		}

		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 locationText;
				var location;
				var bounds = new GLatLngBounds();
				var markerImage = {};
				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.setZoom(map.getBoundsZoomLevel(bounds));
			map.setCenter(bounds.getCenter());

			Estate.Events.AddEvent(
				window,
				function() {
					map.setZoom(map.getBoundsZoomLevel(bounds));
					map.setCenter(bounds.getCenter());
				},
				"onresize"
			)
		}

		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.LoadExternalDataReload = function(locationsUrl) {
				map.clearOverlays()
				loadExternalData(locationsUrl)
			},

			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;
})();






/* Makes an HTML element draggable */
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&z=11")
		}
	}
})();
