//global variables

var DEFAULTZOOM = 4;
var DEFAULT_SINGLE_LOCATION_ZOOM = 14;

var m_routing = false;
//map object
var m_map = null;

//map attributes
var m_mapControlName = null;
var m_zoom = DEFAULTZOOM;
var m_mapStyle = null;
var m_fixed = false;
var m_mapDimensionMode = null;
var m_showSwitch = true;
var m_titeBuffer = 0;
var m_printView = false;
var m_multilocation = true;

//------------ ROUTING -------------------------------
//route addesses
var m_startAddressLat = null;
var m_startAddressLong = null;
var m_endAddressLat = null;
var m_endAddressLong = null;

//page element ids to display route information
var m_totalDistanceId = -1;
var m_diretionsId = -1;
//page element id to hold zoom level
var m_zoomHolderId = -1;

//-------place holders------------------

//Place holder that gets substituted by a direction segment
var m_directionPlaceHolder = '[DIRECTIONS]';
//Place holder that gets replaced by direction segment distance
var m_distancePlaceHolder = '[DISTANCE]';
var m_directionsRowClassPlaceHolder = '[TDCLASS]';
var m_directionsImageClassPlaceHolder = '[IMGCLASS]';
var m_directionsNumberPlaceHolder = '[NUMBER]';

//place holder values
var m_rowClass = null;
var m_directionsStartImageClass = null;
var m_directionsEndImageClass = null;
var m_directionsBetweenImageClass = null;

//direction templates to format display information
var m_startEndTemplate = null;
var	m_itemTemplate = null;
//distance template to format distance info
var m_distanceTemplate = null;


//function to wire a function to body's onload event
function addLoadListener(functionToAdd)
{
 if ( typeof window.addEventListener != 'undefined' )
 {
  window.addEventListener('load', functionToAdd, false);
 }
 else if ( typeof window.document.addEventListener != 'undefined' )
 {
  window.document.addEventListener('load', functionToAdd, false);
 }
 else if ( typeof window.attachEvent != 'undefined' )
 {
  window.attachEvent('onload', functionToAdd);
 }
 else
 {
  if ( typeof window.onload != 'function' )
  {
   window.onload = functionToAdd;
  }
  else
  {
   var oldFunction = window.onload;

   window.onload = function()
   {
    oldFunction();
    functionToAdd();
   }
  }
 }
}

//It creates virtual earth control, creates pushpins, and display them on map
//It calls CreatePushPins function that is generated at runtime, which is done
//in code behind of map control
function GetMap()
{
try{
        m_map = new VEMap(m_mapControlName);
        m_map.LoadMap(new VELatLong(0,0), m_zoom, m_mapStyle, m_fixed, m_mapDimensionMode, m_showSwitch, m_titeBuffer);
        
        //Hide birds eye popup.
        if(document.getElementById('MSVE_obliqueNotification'))
        	document.getElementById('MSVE_obliqueNotification').style.visibility="hidden";
        //Hide birds eye button.
        if(document.getElementById('MSVE_navAction_ObliqueMapView'))
        	document.getElementById('MSVE_navAction_ObliqueMapView').style.visibility="hidden";
        //Hide labels button.
        if(document.getElementById('MSVE_navAction_showLabels'))
        	document.getElementById('MSVE_navAction_showLabels').style.visibility="hidden";
        //Hide labels button separator.
        if(document.getElementById('MSVE_navAction_separator2'))
        	document.getElementById('MSVE_navAction_separator2').style.visibility="hidden";
        //Hide labels button separator.
        if(document.getElementById('MSVE_navAction_separator3'))
        	document.getElementById('MSVE_navAction_separator3').style.visibility="hidden";

        
        //Disable zoom on mouse wheel
        m_map.AttachEvent('onmousewheel', MouseWheelHandler)
        //Handler for event that is fired when zoom ends
        m_map.AttachEvent('onendzoom', ZoomLevelHandler)
        
        //if it is a route map
        if (m_routing)
        {
            DrawRoute();
        }
        //if it is a location map
        else
        {
            var pushPinCollection = CreatePushPins();
            if (pushPinCollection != 'undefined' && pushPinCollection.length != 0)
            {
                AddPushPins(pushPinCollection);
            }   
        }

        //This is because map SetMapView sets the best possible zoom automatically but
        //if a zoom level has been specified, then we need to override it
        if (m_zoom != DEFAULTZOOM)
        {
            m_map.SetZoomLevel(m_zoom);  
        }
        //However, if it is a mulitlocation map but only one location could be found for search criteria, then
        //VE sets zoom level too close. Override it to reasonable zoom level  
        if (m_routing == false && m_multilocation == true && (pushPinCollection != 'undefined' && pushPinCollection.length == 1))
        {
            m_map.SetZoomLevel(DEFAULT_SINGLE_LOCATION_ZOOM)
        } 
        //Save the zoom level
        var zoomLevel = m_map.GetZoomLevel();
        SaveZoomLevel(zoomLevel);
    }
   catch(e)
   {
    alert(e.message);
   }
}

//It records the current zoom level in a hidden page element
//This is useful if the subsequent pages, e.g. print view, want to
//maintain the zoom level
function SaveZoomLevel(zoomLevel)
{
    var zoomHolderId = document.getElementById(m_zoomHolderId);
    zoomHolderId.value = zoomLevel; 
}

//Handler for zoom event. Save the zoom level whenever it changes.
function ZoomLevelHandler(e)
{
    var zoomLevel = e.zoomLevel;
    SaveZoomLevel(zoomLevel);   
}

//This function gets called on mouse wheel event. If it returns true, the
//event gets cancelled
function MouseWheelHandler(e)
{
  return true;  
}

//function to display pushpin collection to virtual earth
function AddPushPins(mapPushpins)
{
    m_map.AddShape(mapPushpins);
    m_map.SetMapView(mapPushpins);
}

//It sets virtual earth attributes
function SetMapAttributes(controlName, zoom, mapStyle, fixed, mapDimensionMode, showSwitch, tileBuffer, routing, printView, multilocation, zoomHolderId)
{
    m_mapControlName = controlName;
    m_zoom = zoom;
    m_mapStyle = mapStyle;
    m_fixed = fixed;
    m_mapDimensionMode = mapDimensionMode;
    m_showSwitch = showSwitch;
    m_tileBuffer = tileBuffer;
    m_routing = routing;
    m_printView = printView;
    m_multilocation = multilocation;
    m_zoomHolderId = zoomHolderId;
}

//draws route on the map
function DrawRoute()
{
    //These addresses should have been filled in by SetRouteAddresses method, which runs on page load
    var startAddress = new VELatLong(m_startAddressLat, m_startAddressLong);
    //var startAddress = new VELatLong(40.719406, -74.077787);
    var endAddress = new VELatLong(m_endAddressLat, m_endAddressLong);
    var locations = new Array(startAddress, endAddress);
    
    m_map.GetDirections(locations, m_routeOptions);
}

//This is the call back function that handles routing
function RouteHandler(route)
{
    DrawRouteOnMap(route)
}

//This function draws route on the map
function DrawRouteOnMap(route)
{
    //clear original route shape objects
    m_map.DeleteAllShapes();
    //get route legs
    var legs = route.RouteLegs;
    var leg = null;
    var shape = null;
    var numTurns = -1;
    
    //There should be only one leg because we are not adding in between locations
    for(var i=0; i<legs.length; i++)
    {
        leg = legs[i];
        //each leg has a collection of VERouteItineraryItem
        var turn        = null;  // The VERouteItineraryItem
        var legDistance = null;  // The distance for this itinerary item
        var itemCount = leg.Itinerary.Items.length
        
        var directions = ''; //holds direction information to be displayed on page
        
        //display total distance
        SetTotalDistance(leg.Distance.toFixed(1))
        
        for(var j=0; j<itemCount; j++)
        {
          numTurns++;
          turn = leg.Itinerary.Items[j];
          
	      shape = new VEShape(VEShapeType.Pushpin, turn.LatLong );
	      
	      //starting pin style
	      if (numTurns == 0)
	      {
	        shape.SetCustomIcon("<div class='" + m_directionsStartImageClass + "'></div>");
	        SetRouteHoverDescription(shape, turn.Text);
	        directions = directions + ApplyTemplate(m_startEndTemplate, m_directionsStartImageClass, numTurns, true, turn);
	      }
	      //ending pin style
	      else if (numTurns == itemCount - 1)
	      {
	        shape.SetCustomIcon("<div class='" + m_directionsEndImageClass + "'></div>");
	        SetRouteHoverDescription(shape, turn.Text);
	        directions = directions + ApplyTemplate(m_startEndTemplate, m_directionsEndImageClass, numTurns, true, turn);
	      }
	      //in between pin style
	      else
	      {
	        shape.SetCustomIcon("<div class='" + m_directionsBetweenImageClass + "'><div class='text'>"+ numTurns +"</div></div>");
	        SetRouteHoverDescription(shape, GetDirectionText(turn)); 
	        directions = directions + ApplyTemplate(m_itemTemplate, m_directionsBetweenImageClass, numTurns, false, turn);
	      }
	      
	      m_map.AddShape(shape);  
        }
	      
	    SetDirections(directions);
    }
}

//Don't show hover in print view
function SetRouteHoverDescription(shape, text)
{
    if (!m_printView)
    {
       shape.SetDescription(text);
    }
}

//Applies HTML templates to directions 
function ApplyTemplate(template, imageClass, rowNumber, startEnd, turn)
{
    var rowClass = "";
    if (rowNumber % 2 == 0)
    {
        rowClass = m_rowClass;
    }
    
    var directionText = GetDirectionText(turn);
	directionText =  template.replace(m_directionPlaceHolder, directionText);
	//row class
	directionText = directionText.replace(m_directionsRowClassPlaceHolder, rowClass)
	//set the image class
	directionText = directionText.replace(m_directionsImageClassPlaceHolder, imageClass)
	
	if (startEnd == false)
	{
	   directionText = directionText.replace(m_directionsNumberPlaceHolder, rowNumber) 
	}
    return directionText;
}

//format: direction text - (distance)
//e.g., turn left - (0.5 miles)
function GetDirectionText(turn)
{
	var formattedDistance = FormatDistance(turn);
	var directionText = turn.Text + ' ' + formattedDistance;
	return directionText;
}

//Replace placeholder by actual distance for a segment of directoin
function FormatDistance(turn)
{
	// Round distances to 1/10ths
    var distanceText =  m_distanceTemplate.replace(m_distancePlaceHolder, turn.Distance.toFixed(1));
    return distanceText ;
}

//Assigns direction information to a visual element. It prepares a table containing
//directions, then gets the element(usually a Div) by id (supplied by code), and sets its
//inner html to html table
function SetDirections(directions)
{
    var tableStart = '<table width="100%" cellspacing="0" cellpadding="0" border="0"><tbody>'
    var tableEnd = '</tbody></table>'
    table = tableStart + directions + tableEnd
    
    var directionsId = document.getElementById(m_diretionsId);
    directionsId.innerHTML = table;
}

//Assigns total distance to a visual element
function SetTotalDistance(distance)
{
    var distanceId = document.getElementById(m_totalDistanceId);
    distanceId.innerHTML = distance;
}

//This method runs on page load. It sets the ids of the page elements
//that are used to display direction information
function SetRoutingInformationElementIds(totalDistanceId, directionsId)
{
   m_totalDistanceId = totalDistanceId;
   m_diretionsId =  directionsId;
}

//this method is run on page load
function SetRouteAddresses(startAddressLat, startAddressLong, endAddressLat, endAddressLong)
{
    m_startAddressLat   = startAddressLat;
    m_startAddressLong  = startAddressLong;
    m_endAddressLat     = endAddressLat;
    m_endAddressLong    = endAddressLong;      
}

//It sets route options. This is not called from code. It has to be called before drawing route
function SetRouteOptions(routeUnit, red, blue, green, opacity, routeOptimization, routeWeight, routeBestView, routeDisambiguity, showErrorMessages, useMapPointEngine)
{
    m_routeOptions = new VERouteOptions;
    
    m_routeOptions.DistanceUnit        = routeUnit;
    m_routeOptions.DrawRoute           = true;
    m_routeOptions.RouteCallback       = RouteHandler;
    m_routeOptions.RouteColor          = new VEColor(red, blue, green, opacity);
    m_routeOptions.RouteOptimize       = routeOptimization;
    m_routeOptions.RouteWeight         = routeWeight;
    m_routeOptions.SetBestMapView      = routeBestView;
    m_routeOptions.ShowDisambiguation  = routeDisambiguity;
    m_routeOptions.ShowErrorMessages   = showErrorMessages;
    m_routeOptions.UseMWS              = useMapPointEngine;
}


//this method is run on page load and sets templates that are used to format diaply information
function SetRoutingInformationTemplates(distanceTemplate, startEndTemplate, itemTemplate)
{
	m_distanceTemplate = distanceTemplate;
	m_startEndTemplate = startEndTemplate;
	m_itemTemplate = itemTemplate;
}

function SetRoutingClasses(rowClass, startImageClass, betweenImageClass, endImageClass)
{
    m_rowClass = rowClass;
    m_directionsStartImageClass = startImageClass;
    m_directionsBetweenImageClass = betweenImageClass;
    m_directionsEndImageClass = endImageClass;
}
