/*
 * 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" />
	// 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: 'ABQIAAAAdpC81TDuKHHkvpkGLIDQmhSPVVNg54lQPWhiz71C51Vv6HANIhRq6m0aiQuhv5xfsQd9z6Ufdo6HYA',
                ontwikkelOnline: 'ABQIAAAAVs33VuYAmTM0zCGOSXae6xSYuaZfRb0cqClsxyFkTaWBTits5RTV-UqqMYZoWNjOU56hW2Ns0rakZg',
                ontwikkelLocal: 'ABQIAAAAdpC81TDuKHHkvpkGLIDQmhSPVVNg54lQPWhiz71C51Vv6HANIhRq6m0aiQuhv5xfsQd9z6Ufdo6HYA'
            },
            mapConfig: {
                zoomControl: 'large',
                mapTypeControl: true,
                zoom: null,
                zoomBounds: {
                    minimum: 1,
                    maximum: 17
                }
            },
            startLocation: {
                lng: 5.09206,
                lat: 51.57459,
                zoom: 15,
                text: ''
            },
            centerMapLocation: {
                lng: undefined,
                lat: undefined
            },
            locationsUrl: '',
            markerImage: {
                url: '/images/Google_Maps_Marker.png',
                dimensions: {
                    width: '37',
                    height: '34'
                },
                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) {
                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();
					}
				);
                if (configMarkerImage.active == true) {
                    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("vestiging");
                    
                    if (markers.length > 0) {
                        for (var i = 0; i < markers.length; i++) {
                            var markerImage = config.markerImage;
                            var latitude = GXml.value(markers[i].getElementsByTagName("latitude")[0]);
                            var longitude = GXml.value(markers[i].getElementsByTagName("longtitude")[0]);
                            var text = GXml.value(markers[i].getElementsByTagName("text")[0]);
                            text = text.replace(/<!\[CDATA\[/, "");
                            text = text.replace(/\]\]>/, "");
                            var naam = GXml.value(markers[i].getElementsByTagName("naam")[0]);
                            naam = naam.replace(/<!\[CDATA\[/, "");
                            naam = naam.replace(/\]\]>/, "");

                            point = new GLatLng(parseFloat(latitude), parseFloat(longitude));
                            bounds.extend(point);
                            locationText = "<strong>" + naam + "</strong><br />" + text;
                            locationText += "<br /><br />"
                            locationText += "<a target=\"_blank\" href=\"http://maps.google.nl/maps?f=d&source=s_d&daddr=" + latitude + ",+" + longitude + "\">Routebeschrijving naar deze bibliotheek</a><br />"
                            locationText += "<a target=\"_blank\" href=\"http://maps.google.nl/maps?f=d&source=s_d&saddr=" + latitude + ",+" + longitude + "\">Routebeschrijving vanaf deze bibliotheek</a>"
                            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")
                            }

                            markerImage.active = false
                            if (selLocatie) {
                                var url = GXml.value(markers[i].getElementsByTagName("url")[0]);
                                if (url.indexOf('/' + selLocatie + '.aspx') > 0) {
                                    markerImage.active = true
                                }
                            }

                            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")
		}
	}
})();


/* 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 +"'" )
			}
		}
	}
})();

