﻿/*
    Locator map object, responsible for location plotting, display and map navigation.
    Encapsulates the actual VEMap object with public access.
*/

function Map(mapID){

    /* Constants */
    
    // Zoom level to show locations at when 'Zoom to street level' is selected.
    var SHOW_LOCATION_ZOOM = 12;
    
    // Default map parameters
    //var defaultLocation = new VELatLong(39.4499983362581, -103.9079693709546);
    var defaultLocation = new VELatLong(40.579167, -83.09);
    var defaultZoom = 4;
    var defaultMapStyle = "r";
    var mapIsFixed = false;
    var mapMode = VEMapMode.Mode2D;
    var mapSwitch = false;
    
    // Restricted zoom levels (currently disabled)
    var AVAILABLE_ZOOM_LEVELS = new Array(4, 6, 8, 10, 12, 14, 15);
    // Keeps track of the last zoom level to determine if the user zoomed in or out.
    var lastZoomLevel = null;
    var userZoomed = true;
    var lastZoomCenter = null;
    
    /* End Constants */
    
    
    /* Members */

    // Handle to self's DOM object.
    var _mapID = mapID;
    
    // Handle to VE's map object.
    var _vemap = null;
    
    // Handle to self's collapse control DOM object.
    var _navControl = null;
    
    // Determines whether the filter is already enabled/disabled or if it needs to be.
    var _filterEnabled = true;
    
    //for a valid instance of an XMLHTTP object
    var req = null;
    
    var _printStartAddress = null;
    var _printEndAddress = null;
    
    /* End Members */
    
    _init();    


    // Constructor.
    function _getMap(){

        // Create a VE Map       
        _vemap = new VEMap(mapID);
        
        // Turn off default disambiuation due to lack of callback support.
        // replaced: after Map Load
        //_vemap.ShowDisambiguationDialog(false);   
        // v 6.1
        
       try{
            _vemap.SetDashboardSize(VEDashboardSize.Normal);

            // Attempt to load VE Map.
            //(VELatLong, zoom, style, fixed, mode, showSwitch, tileBuffer, mapOptions);
            _vemap.LoadMap(defaultLocation, defaultZoom, defaultMapStyle, mapIsFixed, mapMode, mapSwitch);
            
            //_vemap.LoadMap(defaultLocation, defaultZoom);
            _vemap.ShowDisambiguationDialog(false);
            
            // Apply transparency to navigation panel.
            //v 6.1 error! Custom panel doesn't support in v 6.1
//            _navControl = document.getElementById(mapID + '_dashboard');
//            _navControl.className += " transparent2"; //??????
//            
            // Resricted zoom level events (disabled)
            //_vemap.AttachEvent("onstartzoom", _onStartZoom);
            //_vemap.AttachEvent("onendzoom", _onEndZoom);
            
            //Construct JS Prototype to set Custom Property CustomShapeID to hold SiteId
            VEShape.prototype.CustomShapeId = null;  
            
            
            _vemap.AttachEvent("onchangemapstyle", _onChangeMapStyle);
            
            //this event will zoom to the cursor's position
            _vemap.SetMouseWheelZoomToCenter(false);
            
            
            //Show popup info box
            _vemap.AttachEvent("onmouseover", _mouseOverHandler);

        }
        catch(err){
            dal.LogClientsideError("Error creating VE Map. Error: " + err.message);
        }
    }
    
    // Constructor    
    function _init(){
        _getMap();
        _resize();
    }
    
    // Resizes the map to the given size.    
    function _resize(height, width){
    
        if (width ==  null){
            width = document.documentElement.clientWidth;
        }
        if (height == null){
            height = document.documentElement.clientHeight;
        }
        _vemap.Resize(width, height);
    }
    
    // Returns the map's DOM element.
    function _getElement(){
        return document.getElementById(_mapID);
    }
    
    // Plots locations/results on the map. 
    function _plot(locations, setBestMapView) {
        map.DetachAutoFind();      
        
        
        try {
            _clear();
            for (var i = 0; i < locations.length; i++) {
            
               // deprived AddPushpin method: _vemap.AddPushpin(locations[i].GetPushpin(i));
               //new object is VEShape in v 6.1                
                //var shape = new VEShape(VEShapeType.Pushpin, new VELatLong(locations[i].Latitude, locations[i].Longitude));
                              
                _vemap.AddShape(locations[i].GetPushpin(i));


                if (i % 20 == 0) {
                    sleep(1000);
                }
            }
            if (setBestMapView) {
	            userZoomed = false;
    	    
	        if (locations.length == 1){
		        _setCenterAndZoom(locations[0]);
	        }
	        else{
                    
            	        var bestMapViewArray = new Array;
	                    for (var i = 0; i < locations.length; i++) {
                		        bestMapViewArray.push(new VELatLong(locations[i].Latitude, locations[i].Longitude));
            	        }
            	        _vemap.SetCenterAndZoom(new VELatLong(82.7, 114.4), 15);
            	        _vemap.SetMapView(bestMapViewArray);
	        }
                }
        } catch (err) {
            messagebox.Show("Error plotting locations on map");
        }
            setTimeout("map.AttachAutoFind();", 2000); 
        
        }
    
     
    
    // Clears any pushpins and routes on the map.
    function _clear(){
        try{
            _vemap.DeleteAllShapes();
            _vemap.DeleteRoute();
            _printStartAddress = null;
            _printEndAddress = null;
        }
        catch (err){
        }
    }
    
    // Sets the map's center and zoom level just like VE but quickly jumps to a far away point and back
    // to prevent panning which prevents ero bubbles from disappearing right after appearing.
    function _setCenterAndZoom(location, zoom){
        
        // Notify the zoom events that the system rather than the user was responsible for zooming.
        userZoomed = false;
        
        map.DetachAutoFind();
        
        if (zoom == null){
            zoom = SHOW_LOCATION_ZOOM;
        }
        if ((isValid(location.Latitude)) && (isValid(location.Longitude))){
            _vemap.SetCenterAndZoom(new VELatLong(82.7, 114.4), 15);
            _vemap.SetCenterAndZoom(new VELatLong(location.Latitude, location.Longitude), zoom);
        }
        else{
            try{
                _vemap.SetCenterAndZoom(new VELatLong(location.LatLong.Latitude, location.LatLong.Longitude), zoom);
            }
            catch(err){
                
            }
        }
        map.AttachAutoFind();
    }
    
    
    //shows a bubble v 6.1
    function _mouseOverHandler(e){
    
       if (e.elementID){
                var shape = _vemap.GetShapeByID(e.elementID);
                if (shape != null){
                var _siteID = shape.CustomShapeID;
                
                 atShowPushpin(_vemap.GUID,_siteID, shape.Latitude,shape.Longitude, shape.Title, shape.Notes, "VE_PushPin_Popup_Title", "VE_PushPin_Popup_Body");
                }
         }
   }

    
    // Shows a location's ero / bubble.
    function _showEro(location){
    
        var pin = location.GetPushpin();
        
        //VEPushpin.Show - deprived        
        //VEPushpin.Show(pin.m_vemap.GUID, pin.ID, pin.LatLong.Latitude,pin.LatLong.Longitude, pin.Title, pin.Details, pin.TitleStyle, pin.DetailsStyle);
        // v 6.1 
        ////_vemap.GUID, pin.GetId(), pin.Latitude,pin.Longitude, pin.Title, pin.Notes, "VE_PushPin_Popup_Title", "VE_PushPin_Popup_Body");
        
        var currentShape = _vemap.GetShapeByID(pin.GetID());
        
        if(currentShape != null){
            var _siteID = currentShape.CustomShapeID;

            //update VEShape image
            atShowPushpin(_vemap.GUID,_siteID, currentShape.Latitude,currentShape.Longitude, currentShape.Title, currentShape.Notes, "VE_PushPin_Popup_Title", "VE_PushPin_Popup_Body");
            
            _vemap.ShowInfoBox(currentShape);
        }
        
   }
    
    // Shows a location's ero / bubble's driving directions input form.
    function _showBubbleDDInput(pinId){
        try{
            document.getElementById('bubbleData_' + pinId).style.display = "none";
            document.getElementById('bubbleDriveData_' + pinId).style.display = "block";
            var ddLink = document.getElementById('bubbleDDLink_' + pinId);
            ddLink.href = "javascript:map.ShowBubbleDetails(" + pinId + ")";
            ddLink.innerHTML = "Back to Details";
        }
        catch(err){}
    }
    
    // Shows a location's ero / bubble details.
    function _showBubbleDetails(pinId){
        try{
            document.getElementById('bubbleDriveData_' + pinId).style.display = "none";
            document.getElementById('bubbleData_' + pinId).style.display = "block";
            var ddLink = document.getElementById('bubbleDDLink_' + pinId);
            ddLink.href = "javascript:map.ShowBubbleDDInput(" + pinId + ")";
            ddLink.innerHTML = "Driving Directions";
        }
        catch(err){}
    }
    
    // Updates a location's image in its ero / bubble.
    function _updateBubbleImage(pinId, url){
        try{
            var curImage = document.getElementById('bubbleImage_' + pinId);
            curImage.src = url;
        }
        catch(err){
        }
    }
    
    // Gets a route and driving directions from a user specified location to the currently selected location
    function _getRoute(pinId){
        
        map.DetachAutoFind();
        
        var destinationLoc = panel_results.GetLocation2(pinId);
        
        // Get user-entered address information.
        var street = document.getElementById('txtDDStreet_' + pinId).value;
        var city = document.getElementById('txtDDCity_' + pinId).value;
        var state = document.getElementById('txtDDState_' + pinId).value;
        var zip = document.getElementById('txtDDZip_' + pinId).value;
        
        // Create VE search string.
        var address = "";
        
        if (isValid(street)){
            address += street + ", ";
        }
        if (isValid(city)){
            address += city + ", ";
        }
        if (isValid(state)){
            address += state + ", ";
        }
        if (isValid(zip)){
            address += zip + ", ";
        }
        //address += ", USA";
        
        if ((street.length < 1) && (city.length < 1) && (state.length < 1) && (zip.length < 1)){
            loadingbox.ShowAndStay("Please enter a valid address", false, 2000);
            return;
        }
        
        _clear(); 
        
        _printStartAddress = reformatString(address);
        _printEndAddress = destinationLoc.GetFormattedAddress();
        
        

//        dal.FindRoute(reformatString(address), destinationLoc.GetFormattedAddress(), _onGetRoute);
        dal.FindRoute(_printStartAddress, _printEndAddress, _onGetRoute);
    }
    
    // Callback for getting a location's route.
    function _onGetRoute(route){
        panel_results.Reset();
        map.DetachAutoFind();
       
        map.VE.SetZoomLevel(map.VE.GetZoomLevel() - 1);

        var resultsContainer = document.getElementById('ddContainer');
        if (resultsContainer == null){
            return;
        }
        
        var steps="";
        
        
        // check if we got the route obj
        
        if (route != null){
                
                //how many steps/turns
                //v 6.1 changed: var len = route.Itinerary.Segments.length;
                var len = route.RouteLegs[0].Itinerary.Items.length;
                
                //TODO: Convert time to HH:MM
                //var totalDistance = "Total distance: <b>" + route.Itinerary.Distance + " " + route.Itinerary.DistanceUnit + "</b>";    
                //var estimatedTime = "Estimated time: <b>" + route.Itinerary.Time + "</b>";
                var totalDistance = "Total distance: <b>" + route.Distance.toFixed(1) + " " + "miles" + "</b>";    
                var estimatedTime = "Estimated time: <b>" + dal.GetTime(route.Time)  + "</b>";
                
                var directionsTable = "<table class='ve_panel_directions_table'>";
                for(var i = 1; i < len ;i++){
                    directionsTable += "<tr><td valign='top'>"
                        directionsTable += "<div class='ve_panel_directions_icon' id='direction_graphic_" + i + "'>";
                            if (i == 1){
                                directionsTable += "<img src='" + Msn.VE.API.Constants.vedirectionsstarticon + "'/>";
                            }
                            
                            else if (i > 1 && i < len-1){
                                directionsTable += "<img src='" + Msn.VE.API.Constants.vedirectionsstepicon.replace("%1",i-1) + "'/>";
                            }
                            else if (i == len -1){
                                directionsTable += "<img src='" + Msn.VE.API.Constants.vedirectionsendicon + "'/>";
                            }
                        directionsTable += "</div>";            
                    directionsTable +=  "</td>";
                    
                    directionsTable += "<td>";
                        directionsTable += "<div class='ve_panel_directions_text' id='direction_text_" + (i+1) + "'>";
                            //directionsTable += "<a href='javascript:CenterDriveStep(" + (i-1) + ")'>"
                            directionsTable += route.RouteLegs[0].Itinerary.Items[i].Text;
                            if ((i > 1) && (i < len -1)){
                                directionsTable += " (" + route.RouteLegs[0].Itinerary.Items[i].Distance.toFixed(1) + " " + "miles" + ") ";
                            }
                            //directionsTable += "</a>";
                        directionsTable += "</div>";
                    directionsTable +=  "</td></tr>";
                }
                directionsTable += "</table>";
                
                var directionsDiv = directionsTable + "<br/>" + totalDistance + "<br/>" + estimatedTime;
                directionsDiv += "<br/><br/><a href='" + dal.GetPPRouteURL(route,_printStartAddress,_printEndAddress) + "' target='_blank'>Printer Friendly Directions</a><br/>";
                resultsContainer.innerHTML = directionsDiv;
                panel.ShowSectionOnly('directions', true);
                
        }
        loadingbox.ForceHide();
        
    }
    
    // Attaches all automatic search events.
    function _attachAutoFind(){
        if (_vemap == null){
            return;
        }
        
        _vemap.AttachEvent("onendzoom", _onChangeMapView);
        
        //v 6.1 changed Event onendcontinuouspan to onendpan
        //_vemap.AttachEvent("onendcontinuouspan", _onChangeMapView);
        _vemap.AttachEvent("onendpan", _onChangeMapView);
        
        //_vemap.AttachEvent("onchangeview", _onChangeMapView);
    }
    
    // Detaches all automatic search events.
    function _detachAutoFind(){
        if (_vemap == null){
            return;
        }
        
        _vemap.DetachEvent("onendzoom", _onChangeMapView);
        
        //v 6.1 changed Event onendcontinuouspan to onendpan
        _vemap.DetachEvent("onendpan", _onChangeMapView);
        //_vemap.DetachEvent("onchangeview", _onChangeMapView);
    }
    
    
    // Event which fires whenever the map view is changed.
    function _onChangeMapView(){
        _detachAutoFind();
        panel.FindByExtents();
        
        
        //do we want to switch to 3D?
     
    }
    
    // Event which fires whenever the map style (road/aerial/birds eye) is changed.
    function _onChangeMapStyle(){      
    
    if (map.VE.GetMapStyle() == VEMapStyle.Birdseye || map.VE.GetMapStyle() == VEMapStyle.BirdseyeHybrid ){      
            //_detachAutoFind();
            if (_filterEnabled){
                _filterEnabled = false;
                panel.EnableFilter(false);
            }
        }
        else{
            if (!_filterEnabled){
                _filterEnabled = true;
                panel.EnableFilter(true);
            }
        } 
    }
    
    // Event which fires as soon as zooming starts (currently disabled / not used / not attached).
    function _onStartZoom(e){
        if (userZoomed){
            lastZoomLevel = e.view.zoomLevel;
            lastZoomCenter = new VELatLong(e.view.latlong.latitude, e.view.latlong.longitude);
        }
    }
    
    // Event which fires when zooming ends (currently disabled / not used / not attached).
    function _onEndZoom(e){
        if ((map.VE.GetMapStyle() != VEMapStyle.Birdseye) && (userZoomed)){
        
            _detachAutoFind();
            panel.FindByExtents();        
        
            var curZoomLevel = e.view.zoomLevel;
            var direction = null;
            var newZoomLevel = null;
            
            if (curZoomLevel > lastZoomLevel){
                direction = 1;
                newZoomLevel = _getNextZoomLevel(0, direction, curZoomLevel);
            }
            else{
                direction = -1;
                newZoomLevel = _getNextZoomLevel(AVAILABLE_ZOOM_LEVELS.length - 1, direction, curZoomLevel);
            }
            
            userZoomed = false;
            
            //temporarily disable remembering zoom center.
            //_vemap.SetCenterAndZoom(lastZoomCenter, newZoomLevel);
            _vemap.SetCenterAndZoom(_vemap.GetCenter(), newZoomLevel);
            
        }
        setTimeout("userZoomed = true;", 500);
    }
    
    // Returns the next available zoom level from those which are permitted (in constants.js)
    function _getNextZoomLevel(index, direction, curZoomLevel){

        // Check boundary conditions
        if (index < 0){
            return AVAILABLE_ZOOM_LEVELS[0];
        }
        else if (index > AVAILABLE_ZOOM_LEVELS.length - 1){
            return AVAILABLE_ZOOM_LEVELS[AVAILABLE_ZOOM_LEVELS.length - 1];
        }
        
        if ((direction == 1) && (AVAILABLE_ZOOM_LEVELS[index] > curZoomLevel)){
            return AVAILABLE_ZOOM_LEVELS[index];
        }
        
        else if ((direction == -1) && (AVAILABLE_ZOOM_LEVELS[index] < curZoomLevel)){
            return AVAILABLE_ZOOM_LEVELS[index];
        }
        
        // keep trying for next available zoom level.
        return _getNextZoomLevel( (index + direction), direction , curZoomLevel);
    }
   
    // public accessors
    this.Init = _init; 
    this.Resize = _resize;
    this.Dashboard = _navControl;
    
    this.GetElement = _getElement;
    
    this.Plot = _plot;
    this.Clear = _clear;
    this.SetCenterAndZoom = _setCenterAndZoom;
    
    this.VE = _vemap;
    this.ShowBubble = _showEro;
    
    this.ShowBubbleDDInput = _showBubbleDDInput;
    this.ShowBubbleDetails = _showBubbleDetails;
    this.UpdateBubbleImage = _updateBubbleImage;
    
    this.GetRoute = _getRoute;
    
    this.AttachAutoFind = _attachAutoFind;
    this.DetachAutoFind = _detachAutoFind;
    
    this.OnGetRoute = _onGetRoute;
    
    
}
