﻿Type.registerNamespace('PComCs.Hubs.Controls');

PComCs.Hubs.Controls.LocatableMap = function(element)
{
    PComCs.Hubs.Controls.LocatableMap.initializeBase(this, [element]);
    this._map;
    this._mgr;
    this._markerRequestMgr;

    this._sectionQuery;
    this._queryImplementation;

    this._serviceClientFunction;
    this._defaultZoom;
    this._zoomToResults;
    this._northLatitude;
    this._southLatitude;
    this._eastLongitude;
    this._westLongitude;

    this._welcomeHTML;
}

PComCs.Hubs.Controls.LocatableMap.prototype =
{
    get_sectionQuery: function() {
        return this._sectionQuery;
    },
    set_sectionQuery: function(value) {
        this._sectionQuery = value;
    },
    get_queryImplementation: function() {
        return this._queryImplementation;
    },
    set_queryImplementation: function(value) {
        this._queryImplementation = value;
    },

    get_serviceClientFunction: function() {
        return this._serviceClientFunction;
    },
    set_serviceClientFunction: function(value) {
        this._serviceClientFunction = value;
    },

    get_markerImageSize: function() {
        return this._markerImageSize;
    },
    set_markerImageSize: function(value) {
        this._markerImageSize = value;
    },
    get_markerImagePath: function() {
        return this._markerImagePath;
    },
    set_markerImagePath: function(value) {
        this._markerImagePath = value;
    },
    get_markerShadowImagePath: function() {
        return this._markerShadowImagePath;
    },
    set_markerShadowImagePath: function(value) {
        this._markerShadowImagePath = value;
    },
    get_groupMarkerImagePath: function() {
        return this._groupMarkerImagePath;
    },
    set_groupMarkerImagePath: function(value) {
        this._groupMarkerImagePath = value;
    },
    get_groupMarkerShadowImagePath: function() {
        return this._groupMarkerShadowImagePath;
    },
    set_groupMarkerShadowImagePath: function(value) {
        this._groupMarkerShadowImagePath = value;
    },

    get_defaultZoom: function()
    {
        return this._defaultZoom;
    },
    set_defaultZoom: function(value)
    {
        this._defaultZoom = value;
    },
    get_zoomToResults: function() {
        return this._zoomToResults;
    },
    set_zoomToResults: function(value) {
        this._zoomToResults = value;
    },
    get_northLatitude: function() {
        return this._northLatitude;
    },
    set_northLatitude: function(value) {
        this._northLatitude = value;
    },
    get_southLatitude: function() {
        return this._southLatitude;
    },
    set_southLatitude: function(value) {
        this._southLatitude = value;
    },
    get_eastLongitude: function() {
        return this._eastLongitude;
    },
    set_eastLongitude: function(value) {
        this._eastLongitude = value;
    },
    get_westLongitude: function() {
        return this._westLongitude;
    },
    set_westLongitude: function(value) {
        this._westLongitude = value;
    },

    get_welcomeHTML: function() {
        return this._welcomeHTML;
    },
    set_welcomeHTML: function(value) {
        this._welcomeHTML = value;
    },

    initialize: function() {
        PComCs.Hubs.Controls.LocatableMap.callBaseMethod(this, 'initialize');

        // Create private functions.
        var getCoordinateBounds = function(map) {
            var coordinateBounds = new Object();

            coordinateBounds.northEast = new Object();
            coordinateBounds.southWest = new Object();

            coordinateBounds.northEast.latitude = map.getBounds().getNorthEast().lat();
            coordinateBounds.southWest.latitude = map.getBounds().getSouthWest().lat();
            coordinateBounds.northEast.longitude = map.getBounds().getNorthEast().lng();
            coordinateBounds.southWest.longitude = map.getBounds().getSouthWest().lng();

            return coordinateBounds;
        }

        if (GBrowserIsCompatible()) {
            // Set default center and zoom level.
            var center = new GLatLng(0, 0);
            var zoomLevel = this._defaultZoom;

            // Create the map.
            this._map = new GMap2(this.get_element());
            this._map.setCenter(center, zoomLevel, G_HYBRID_MAP);
            this._map.addMapType(G_PHYSICAL_MAP);
            this._map.setMapType(G_PHYSICAL_MAP);

            // Add a marker manager for the map.
            this._mgr = new MarkerManager(this._map);

            // Compute center and zoom based on the specified bounds, if specified.
            if (this._northLatitude &&
                this._southLatitude &&
                this._eastLongitude &&
                this._westLongitude) {
                var bounds = new GLatLngBounds(new GLatLng(this._southLatitude, this._westLongitude), new GLatLng(this._northLatitude, this._eastLongitude));

                this._map.setCenter(bounds.getCenter());
                this._map.setZoom(this._map.getBoundsZoomLevel(bounds));
            }

            // Add this._map controls.
            this._map.addControl(new GLargeMapControl());

            var mapControl = new GHierarchicalMapTypeControl();

            // Set up this._map type menu relationships
            mapControl.clearRelationships();
            mapControl.addRelationship(G_SATELLITE_MAP, G_HYBRID_MAP, "Labels", false);

            // Add control after you've specified the relationships
            this._map.addControl(mapControl);

            // Add the welcome baloon, if necessary.
            if (this._welcomeHTML) {
                this._map.openInfoWindowHtml(
                    this._map.getCenter(),
                    this._welcomeHTML,
                    {
                        pixelOffset: new GSize(-25, 75),
                        maxWidth: 500
                    });
            }

            // Add an event handler to retrieve markers on pan/zoom.
            var mgr = this._mgr;
            var map = this._map;
            var zoomToResults = this._zoomToResults;

            var markerImagePath = this._markerImagePath;
            var markerShadowImagePath = this._markerShadowImagePath;
            var groupMarkerImagePath = this._groupMarkerImagePath;
            var groupMarkerShadowImagePath = this._groupMarkerShadowImagePath;

            // Create an icon size if necessary.
            var markerImageGSize = null;
            if (this._markerImageSize) {
                markerImageGSize = new GSize(this._markerImageSize.Height, this._markerImageSize.Width);
            }

            var onLocatablesLoaded = function(results) {
                // Add markers for the specified projects from the service.
                if (results) {

                    var newBounds = null;

                    var convertToGMarkers = function(serviceMarkers, icon) {
                        var gMarkers = new Array();
                        for (var i = 0; i < serviceMarkers.length; i++) {
                            var serviceMarker = serviceMarkers[i];

                            var gLatLng = new GLatLng(serviceMarker.markerCoordinate.latitude, serviceMarker.markerCoordinate.longitude);
                            var gMarker = new GMarker(gLatLng, icon);
                            gMarker.bindInfoWindowHtml(serviceMarker.infoWindowHtml);

                            gMarkers.push(gMarker);

                            if (newBounds == null)
                                newBounds = new GLatLngBounds(gLatLng, gLatLng);
                            else
                                newBounds.extend(gLatLng);
                        }

                        return gMarkers;
                    };

                    // Add instance markers.
                    if (results.instanceMarkers.length > 0) {
                        // Only add to all zoom levels if the results has no groups.
                        var individualIcon = new GIcon(G_DEFAULT_ICON, markerImagePath);
                        if (markerImageGSize) individualIcon.iconSize = markerImageGSize;
                        if (markerShadowImagePath) individualIcon.shadow = markerShadowImagePath;
                        if (markerImageGSize) individualIcon.shadowSize = markerImageGSize;
                        if (results.clumpMarkers.length == 0)
                            mgr.addMarkers(convertToGMarkers(results.instanceMarkers, individualIcon), results.zoomLevel);
                        else
                            mgr.addMarkers(convertToGMarkers(results.instanceMarkers, individualIcon), results.zoomLevel, results.zoomLevel);
                    }

                    // Add clump markers at the current zoom level only.
                    if (results.clumpMarkers.length > 0) {
                        var groupIcon = new GIcon(G_DEFAULT_ICON, groupMarkerImagePath);
                        if (markerImageGSize) groupIcon.iconSize = markerImageGSize;
                        if (groupMarkerShadowImagePath) groupIcon.shadow = groupMarkerShadowImagePath;
                        if (markerImageGSize) groupIcon.shadowSize = markerImageGSize;
                        mgr.addMarkers(convertToGMarkers(results.clumpMarkers, groupIcon), results.zoomLevel, results.zoomLevel);
                    }

                    // Zoom to the current results if specified.
                    // (Do not zoom to results if the current region contains clumps.)
                    if (zoomToResults && results.clumpMarkers.length == 0 && newBounds != null) {
                        zoomToResults = false;
                        map.setCenter(newBounds.getCenter(), map.getBoundsZoomLevel(newBounds));
                    }

                    // Refresh the manager to show the markers.
                    mgr.refresh();
                }
            };

            // Create a marker request manager.
            var sectionQuery = this._sectionQuery;
            var queryImplementation = this._queryImplementation;
            var serviceClientFunction = eval(this._serviceClientFunction);

            var loadFunction = function(regionToLoad, zoomLevel, successCallback) {
                // Translate the lat/lng region to coordinate bounds.
                var coordinateBounds = new Object();

                coordinateBounds.northEast = new Object();
                coordinateBounds.southWest = new Object();

                coordinateBounds.northEast.latitude = regionToLoad.getNorthEast().lat();
                coordinateBounds.southWest.latitude = regionToLoad.getSouthWest().lat();
                coordinateBounds.northEast.longitude = regionToLoad.getNorthEast().lng();
                coordinateBounds.southWest.longitude = regionToLoad.getSouthWest().lng();

                // HACK: If the southwest longitude is 180, change it to -180.
                if (coordinateBounds.southWest.longitude == 180)
                    coordinateBounds.southWest.longitude = -180;

                // Find & execute the service function.
                serviceClientFunction(sectionQuery, queryImplementation, coordinateBounds, zoomLevel, successCallback);
            };

            this._markerRequestMgr = $create(PComCs.Hubs.Components.MarkerRequestManager);
            this._markerRequestMgr.set_loadMarkersFromServiceFunction(loadFunction);

            // Add an event handler to load markers when the map is moved.

            var markerRequestManager = this._markerRequestMgr;
            var onMoveEnd = function() {
                markerRequestManager.getMarkers(map.getBounds(), map.getZoom(), onLocatablesLoaded);
            };

            if (zoomToResults) {
                loadFunction(map.getBounds(), map.getZoom(), onLocatablesLoaded);
            }
            else {
                GEvent.addListener(this._map, "moveend", onMoveEnd);

                // Retrieve the initial set of markers.
                onMoveEnd();
            }
        }
    },

    dispose: function() {
        GUnload();

        if (this._markerRequestMgr)
            this._markerRequestMgr.dispose();

        $clearHandlers(this.get_element());
        PComCs.Hubs.Controls.LocatableMap.callBaseMethod(this, 'dispose');
    }
}

PComCs.Hubs.Controls.LocatableMap.registerClass('PComCs.Hubs.Controls.LocatableMap',Sys.UI.Control);
if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();