function MapManager()
{
    /**
     * Map div element id
     */
    var mapElement=null;
    this.MapElement=null;
    
    var isCategorySearch = null;
    
    var wayPointLetters = new Array("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q",
                                    "R", "S", "T", "U", "V", "W", "X", "Y", "Z");
    
    //The index mapping to VEMapStyles. The default (index 0) is set to road.
    var mapStyleList = new Array(null, VEMapStyle.Road, VEMapStyle.Aerial, VEMapStyle.Hybrid);
    
    //variables to hold selected map info
    //TODO clear this when user logs out
    var SelectedMapId=null;
    var SelectedMapInfo = {mapID: SelectedMapId, Latitude: null, Longitude: null, ZoomLevel: null, MapStyle: null};
    
    // Used to track if mapsearch() is attached to onendpan and onendzoom events
    var mapSearchAttachedPZ = false;
    this.MapSearchAttachedPZ = mapSearchAttachedPZ;
    
    // Used to track if mapSearch() can be re-attached to onendpan and onendzoom events
    var mapSearchReAttachablePZ = false;

    /* returns corresponding letter for driving directions waypoint */
    this.GetWayPointLetter = function(index)
    {
        return wayPointLetters[index];
    }
    this.GetIsCategorySearch = function()
    {
        return isCategorySearch;
    }
    this.SetCategorySearch = function(value)
    {
        isCategorySearch = value;
    }
    
    this.SetSelectedMap = function(value)
    {
        SelectedMapInfo = value;
    }
    this.GetSelectedMap = function()
    {
        return SelectedMapInfo;
    }
    
    this.SetSelectedMapId=function(value)
    {
        SelectedMapId=value;
    }
      
    this.GetSelectedMapId=function()
    {
        return SelectedMapId;
    }
      
    this.GetMapStyle=function(mapStyleInt)
    {
        return mapStyleList[mapStyleInt];
    }
    
    this.GetMapStyleIndex = function(mapStyle)
    {
        var ctr = "";
        for (var i=0; i < mapStyleList.length; i++)
        {
            if (mapStyleList[i] == mapStyle)
            {
                return i;
            }
        }
        return ctr;
    }

    
    this.keyDownOnMap = function(e) 
    { 
        var keyIsBirdsEyeShortcut = (e.keyCode == 66 || e.keyCode == 79);        
        return keyIsBirdsEyeShortcut;
    }
    
    /**
     * VE map instance/property
     */
    var map=null;
    this.Map=map;
    
    this.GetPrintMap = function(mapDivElement)
    {
        map=new VEMap(mapDivElement);
        this.Map=map;
        map.LoadMap();
        map.HideDashboard();
        map.SetScaleBarDistanceUnit(VEDistanceUnit.Kilometers);
    }
    
    /**
    * standardizes canadian addresses for mappoint geocoding
    *
    * @param address - address to be standardized
    *
    * returns the standardized address
    */
    this.PrepareForMapPointGeocoding = function(address) {        
        // get the postal code
        var postalCode = address.match(/([a-z])(\d)([a-z])\s?(\d[a-z]\d)?/i);
        // get the first letter in fsa of postal code
        var firstFSALetter = '';
        var FSA = '';
        // set FSA and firstFSALeter if postalCode present
        if (postalCode != null) {
            // set firstFSALetter to the first letter of the postal code
            firstFSALetter = postalCode[1];
            // include each defined digit of FSA
            FSA = (postalCode[1] != undefined ? postalCode[1] : '') + (postalCode[2] != undefined ? postalCode[2] : '') + (postalCode[3] != undefined ? postalCode[3] : '');
            // return postal code if address is only postal code
            if (address == postalCode[0])
                // include pass between first and last 3 digits
                return (postalCode[1]+postalCode[2]+postalCode[3]+' '+postalCode[4]);
                //return address;
            // else remove postal code from address
            else
                address = address.replace(postalCode[0], "");
        }

        // Put a space between a number and a text
        address = address.replace(/(\d)([a-zA-Z])/g, "$1 $2");

        // Strip U## or S##, which is typically designation for Suite/Unit numbers
        address = address.replace(/^[uUsS]\d+[\-\s]+(\d)/, "$1");

        // For U##-## addresses, the number before the dash is the unit number,
        // endorsed by Canada Post. Strip it or else it will cause the geocoder
        // to give wrong addresses
        address = address.replace(/^\d+\s*\-\s*(\d+)[\s,]/, "$1 ");

        // Remove all instances of Unit/Bureau/Suite/Apartment ### from the address
        // line.  The less MapPoint knows, the better.
        address = address.replace(/\b(unite?|u|bureau|suite|app(artement)?|apartment|apt)\s*\d+[a-z]*(\s*&\s*\d+[a-z]*)?/i, " ");

        // Remove all forms of floor information.  The below regular expresison
        // is good for both English and French ordinal numbers.
        address = address.replace(/\b\d+(st|nd|rd|th)?\s*(fl|floor)\b/i, " ");

        address = address.replace(/\bfirst floor\b/i, "");
        address = address.replace(/\b\d+\s*(er?|i[èe]me?|eme)\s[eé]tage\b/i, "");
        // Convert, expand and standardize all vector in an address (regardless of language)
        address = address.replace(/\bE(st)?\b/i, "East");
        address = address.replace(/\bS(ud)?\b/i, "South");
        address = address.replace(/\b(Ouest|O|W)\b/i, "West");
        address = address.replace(/\bN(ord)?\b/i, "North");

        // Remove PO Box and Station Information
        address = address.replace(/\b(po|p\.o\.) box [a-z0-9]+/gi, "");
        address = address.replace(/^box [a-z0-9]+/i, "");
        address = address.replace(/\b(stn|station) (main|[a-z])\b/i, "");

        // Replace 'at' with 'and'
        address = address.replace(/\b(at)\b/i, "and");

        // return formatted address with postal code
        return (address + FSA);
    }

    /**
    * calculates appropriate map width and height
    *
    * returns an array with map width as the first element and map height as the second element
    */
    this.GetMapWidthHeight = function() {
        //Find Browser Window Size
        var myWidth = 0
        var myHeight = (browserManager.BrowserName == 'msie' ? (0-1) : (browserManager.BrowserName == 'safari' ? (0 - 7) : 0));

        //Non-IE
        if (typeof (window.innerWidth) == 'number') {
            myWidth += window.innerWidth;
            myHeight += window.innerHeight;
        }
        //IE 6+ in 'standards compliant mode'
        else if (document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) {
            myWidth += document.documentElement.clientWidth;
            myHeight += document.documentElement.clientHeight;
        }
        //IE 4 compatible
        else if (document.body && (document.body.clientWidth || document.body.clientHeight)) {
            myWidth += document.body.clientWidth;
            myHeight += document.body.clientHeight;
        }

        // extra 78px because what's near by is hidden
        //NA var mapHeight = parseInt(myHeight - 118);
        var mapHeight = parseInt(myHeight - 100);
        mapHeight = mapHeight < 200 ? 200 : mapHeight;

        //NA var mapWidth = myWidth - 282;
        var mapWidth = myWidth;
        //UP mapWidth = mapWidth < 200 ? 200 : mapWidth;
        
        if($('yp_DrivingDirections0').style.display == "block") {
        	var maxWidth = 750;
        	/*
        	$('ypgCornersWrapper').style.width = '754px';
        	$('ypgCornersWrapper').style.left = '228px';
        	$('MainMap').style.left = '-225px';
        	*/
        } else {
        	var maxWidth = 976;
		}
        // Override for Full Merchant Page situation
        if(isMerchantPage == true) 
        {
        	if(isMPMapExpanded == true)
        	{
        		mapHeight = 450;
        		
                if($('yp_DrivingDirections0').style.display == "block") {
                	var maxWidth = 735; // was 739.  reduced because of 2px borders on left & right
                	$('ypMerchtMap').addClassName('ypMerchtMapExpandedStyle');
                	$('navcontrol').addClassName('ypMerchtMapNavcontrolDDFix');
                	
                } else {
	        		if($('navcontrol') != undefined) {
    	    			$('navcontrol').removeClassName('ypMerchtMapNavcontrolDDFix');
       		 		}
            		maxWidth = 964; // was 966. reduced because of 2px borders on left and right
        		}
        		
        		$('ypMerchtMap').removeClassName('ypMerchtMapCollapsedStyle');
        	}
        	else
        	{
        		mapHeight = 247;
        		// mapWidth = 238;
        		mapWidth = 322;
        		$('ypMerchtMap').addClassName('ypMerchtMapCollapsedStyle');
        		$('ypMerchtMap').removeClassName('ypMerchtMapExpandedStyle');
        		if($('navcontrol') != undefined) {
        			$('navcontrol').removeClassName('ypMerchtMapNavcontrolDDFix');
        		}
        	}
        }
                    
        mapWidth = mapWidth > maxWidth ? maxWidth : mapWidth;
        var widthHeight = new Array();
        widthHeight.push(mapWidth);
        widthHeight.push(mapHeight);
        return widthHeight;
    }
    
    /**
    * Loads the VE Map, nav control, and sets window resizing
    *
    * @param mapDivElement - Map div element id
    * @param centerLatitude - latitude on which to centre map
    * @param centerLongitude - longitude on which to centre map
    * @param centerLongitude - zoom level to which to zoom map
    */
    this.GetMap = function(mapDivElement, centerLatitude, centerLongitude, zoom) {
        mapElement = mapDivElement;
        this.MapElement = document.getElementById(mapElement);


		var myWidthHeight = this.GetMapWidthHeight();

        document.getElementById(mapElement).style.width = myWidthHeight[0] + "px";
        document.getElementById(mapElement).style.height = myWidthHeight[1] + "px";

        map = new VEMap(mapDivElement);
        this.Map = map;

        paneNumber = -1;

        map.LoadMap(new VELatLong(centerLatitude, centerLongitude), zoom);
        //map.LoadMap();
        map.HideDashboard();
        map.SetScaleBarDistanceUnit(VEDistanceUnit.Kilometers);

        AddNavControl();
        if(isMerchantPage == false) {
	        $('navPanel').setOpacity( 0.8 );
	        $('imInfoBar').setOpacity( 0.7 );
        }
        //NA AddMiniControl();
        //NA AddMyLocationControl();
        AddMaplevelAlertMessageControl();
        //NA AddTrafficAlertMessageControl();
        //NA AddTrafficBrandingControl();

        //if(debug)AddMyControl();

		map.ClearInfoBoxStyles();

        // attach events to map (resizing, clicking, panning, zooming, and style changing)
        map.AttachEvent('onresize', this.OnMapResize);  // fix positioning of navcontrol
        map.AttachEvent('onclick', MouseHandler);  //VEPopup
        map.AttachEvent('onstartpan', HideCurrentEro); //VEPopup
        map.AttachEvent('onstartzoom', HideCurrentEro); //VEPopup
        map.AttachEvent('onendpan', ShowCurrentEro); //VEPopup
        map.AttachEvent('onendpan', this.updateClientCacheCenter);
        map.AttachEvent('onendzoom', this.updateClientCacheZoom);
        // Comment out next line if using customCluster algorithm
        //map.AttachEvent('onendzoom', this.updateClusterOnOff);
        map.AttachEvent("onchangemapstyle", this.updateClientCacheStyle);
		map.AttachEvent("onchangemapstyle", this.detachPZSearchCheck);

		// Let me know if a birdseye scene is available
		map.AttachEvent("onobliqueenter", OnObliqueEnterHandler);
		map.AttachEvent("onobliqueleave", OnObliqueLeaveHandler);
		
        //Should only attach onendpan and onendzoom after a search has been run (after ajax and after the pan/zoom to plot points)
	    //map.AttachEvent("onendpan", mapSearch);
	    //map.AttachEvent("onendzoom", mapSearch);
		map.AttachEvent("onmouseover", this.mouseoverCB);
		map.AttachEvent("onmouseout", this.mouseoutCB);

        // setup What's Nearby? links
        //NA CarouselManager.DisplayCarousel();
        // set onresize event for window
        window.onresize = this.MapResize;
        
        if (browserManager.BrowserName != 'msie')
            MapControl.Features.ScaleBarKilometers = true;

        // hide link to close mini map (since mini map not displayed on map load)
        //NA document.getElementById('CloseMini').style.display = "none";

        // position footer relative to bottom of map
        //NA document.getElementById('footerdiv').style.top = document.getElementById(mapElement).offsetHeight + 167 - (document.getElementById('PanelWhatsNearby').style.display == "none" ? 78 : 0) + "px";
        //NA document.getElementById('div_traffic_branding').style.top = document.getElementById(mapElement).offsetHeight + 167 - (document.getElementById('PanelWhatsNearby').style.display == "none" ? 78 : 0) + "px";

        //Get window height for accordion window resize
        browserManager.GetWindowHeight();
    }

    function AddMyControl() {
       var control;
       if (control == null)
       {
          control = document.createElement("div"); 
          control.id = "myControl";
          control.style.top ="100px"; 
          control.style.right = "100px"; 
          control.style.width = "100px";
          control.style.border = "2px solid black";
          control.style.background = "White";
          control.innerHTML = "my control";  

          mapManager.Map.AddControl(control);
       }
    }

    // For onendpan and onendzoom events, not form searches
	function mapSearch(mapEvent) {
		// Check for how far away center has changed in pixels.
		// TODO: If less than x or y pixels don't initiate another search
		
        // previous lat/lon
		var lastLat = ClientCache.Retrieve("Latitude");
		var lastLong = ClientCache.Retrieve("Longitude");
		
		var lastZoomSearch = ClientCache.Retrieve("zoomSearch");
		var curZoomLevel = mapManager.Map.GetZoomLevel();
		if(debug)console.log("In mm.mapSearch: lastZoomSearch: %s curZoomLevel: %s", lastZoomSearch, curZoomLevel);
		
		// current lan/lon
		var curLat = mapManager.Map.GetCenter().Latitude;
		var curLong = mapManager.Map.GetCenter().Longitude;

		/*
		lastLat=Math.round(lastLat*10)/10;
		lastLong=Math.round(lastLong*10)/10;
		curLat=Math.round(curLat*10)/10;
		curLong=Math.round(curLong*10)/10;
		 */
		
		if(debug)console.log("==== mapSearch triggered by ===", mapEvent);
		// if close enough, abort search
		
        //var s1 = mapManager.Map.LatLongToPixel(mapManager.Map.GetCenter()).y;
		
		var threshold = 0.03; // zoom level 13 lon threshold
		//if (lastLat == curLat && lastLong == curLong) {
		var latDiff = Math.abs(lastLat - curLat);
		var lonDiff = Math.abs(lastLong - curLong);
		if(debug)console.log("In mm.mapSearch: lastVsCur lat: %f %f lon %f %f. [Diff latDiff: %f lonDiff: %f]", lastLat, curLat, lastLong, curLong, latDiff, lonDiff);

		// if lat & lon has not changed much and if zooming closer to the ground, no need to perform another search
		if ( (latDiff < threshold) && (lonDiff < threshold) && (curZoomLevel >= lastZoomSearch)) {
				if(debug)console.log("In mm.mapSearch: Prevented onendpan/onendzoom from triggering another search.  curZoomLevel: %s >= lastZoomSearch: %s so skip running search", curZoomLevel, lastZoomSearch);
				return false; // Not sure if returning true means handled by us and will cancel default action???
		}

		if(debug)console.log('**** !!!! Starting another search... !!!!');
		mapManager.NewFindBusiness();
	}

	/* detach onendpan/onendzoom from triggering search if user changes mapstyle to
	   VEMapStyle.Birdseye 'o' or VEMapStyle.BirdseyeHybrid 'b' because
	   can not get lat/lon of map's center */
	this.detachPZSearchCheck = function(e) {
	    if (e.mapStyle == "o" || e.mapStyle == "b") {
	    	if(debug)console.log("In mm.detachPZSearchCheck:  Connected: %s.", mapSearchAttachedPZ);
	        if (mapSearchAttachedPZ)
	        {
	        	if(debug)console.log("In mm.detachPZSearchCheck:  Connected: %s.  Going to disconnect.", mapSearchAttachedPZ);
	            mapManager.Map.DetachEvent('onendpan', mapSearch);
	            mapManager.Map.DetachEvent('onendzoom', mapSearch);
	            mapSearchAttachedPZ = false;
	            mapSearchReAttachablePZ = true;
	        }
        } else {
			/* Attach onendpan and onendzoom to map search only if previously attached meaning
			   there was a previously initiated search */
			if (mapSearchReAttachablePZ)
			{
	        	if(debug)console.log("In mm.detachPZSearchCheck:  Connected: %s.  Going to connect. mapSearchReAttachablePZ: %s", mapSearchAttachedPZ, mapSearchReAttachablePZ);
	            
	        	mapManager.Map.AttachEvent('onendpan', mapSearch);
	            mapManager.Map.AttachEvent('onendzoom', mapSearch);
	            mapSearchAttachedPZ = true;
	            mapSearchReAttachablePZ = false;
	        }
        }
	}

	this.AttachPanZoomEventMapSearch = function() {
	    map.AttachEvent('onendpan', mapSearch);
	    map.AttachEvent('onendzoom', mapSearch);
	    mapSearchAttachedPZ = true;
	}

	function OnObliqueEnterHandler()
	{
		if(map.IsBirdseyeAvailable())
		{
			if(debug)console.log('OnObliqueEnterHandler: map.IsBirdseyeAvailable() is true');
			$('a_birdseye').removeClassName('ypgNavDisabled');
		}
	}

	function OnObliqueLeaveHandler()
	{
		if(!map.IsBirdseyeAvailable())
		{
			if(debug)console.log('OnObliqueLeaveHandler: map.IsBirdseyeAvailable() is false');
			$('a_birdseye').addClassName('ypgNavDisabled');
		}
	}
    
    /* displays map too zoomed out warning message box on map with VEMap.AddControl */
    function AddMaplevelAlertMessageControl() {
        var div_zoom_alert = document.getElementById('div_maplevel_alert_message');
        map.AddControl(div_zoom_alert);
    }

    /* displays traffic coverage area message box map with VEMap.AddControl */
    function AddTrafficAlertMessageControl() {
        var div_traffic_alert = document.getElementById('div_traffic_alert_message');
        map.AddControl(div_traffic_alert);
    }

    /* displays Live!Traffic branding on map with VEMap.AddControl */
    function AddTrafficBrandingControl() {
        var div_traffic_branding = document.getElementById('div_traffic_branding');
        map.AddControl(div_traffic_branding);
    }

    /**
    * Validates find input and syncs client cache with find input fields
    *
    * @param clientCacheId: find input client cache id
    * @param value: find input value
    * @param fieldId: find input field id
    *
    * returns validated input
    */
    this.validateFindInput = function(clientCacheId, value, fieldId) {
        // return value in find input field if value passed in is null or undefined
        var returnValue = value;
        if (returnValue == undefined || returnValue == null) {
            returnValue = ClientCache.Retrieve(clientCacheId);
            if (returnValue == undefined || returnValue == null) {
                returnValue = document.getElementById(fieldId).value;
            }
        }

        // save return value to client cache
        ClientCache.Save(clientCacheId, returnValue);

		if(debug)console.log("mm.validateFindInput: clientCacheId:%s, returnValue:%s", clientCacheId, returnValue);

        // outline field red and return null on invalid find input
        document.getElementById('ErrHeaderTxt').style.visibility = returnValue.trim() == "" ? "visible" : "hidden";
        document.getElementById(fieldId).style.border = returnValue.trim() == "" ? "1px solid red" : "1px solid black";
        returnValue = returnValue.trim() == "" ? null : returnValue;

        document.getElementById(fieldId).value = returnValue;

        return returnValue;
    }

    /**
    * calls mapManager.Find for a specified pane
    *
    * @param selectedPane - pane to of which to re-perform find
    * @param newPane - whether or not to create a new pane
    */
    this.PerformSelectedSearch = function(selectedPane, newPane) {
        // get number of selected pane from ClientCache if slectedPane param not given
        paneNumber = selectedPane == null ? ClientCache.Retrieve('selected_pane_num') : selectedPane;
        // perform find if a pane was selected
        if (paneNumber != -1)
            // do not perform find in new pane if newPane param not given
            this.Find((newPane == null ? false : newPane), ClientCache.Retrieve('lastSearch'));
    }

    /**
    * Prepares for a Find (handles all search types)
    *
    * @param newFind - whether or not to create a new pane
    * @param searchType -   type of search
    * @param first -    from location for driving directions search
    *                   search input for find on a map search
    *                   location for find a business or find a person search
    * @param second -   to location for driving directions search
    *                   null for for find on a map search
    *                   keyword for find a business or find a person search
    */
    this.Find = function(newFind, searchType, first, second) {
        //NA FindNearbyClick(true);

        var validatedInputs = this.PrepareForFindLookup(newFind, searchType, first, second);

        // PERFORM FIND
        this.FindLookup(validatedInputs[0], validatedInputs[1]);

        //NA this.resizeLeftDiv();

        ClientCache.Save('lastSearchFailed', 'false');

        //HideLoading();
    }

    // FIND ON A MAP
    /* performs find on a mp search */
    this.NewFindLookup = function(txtFind) {
        txtFind = (txtFind == undefined ? document.getElementById('txtFind').value : txtFind);
        TopNav('FindMap');
        this.Find(true, 'fm', txtFind);
    }
    /* prepares for find on a mp search */
    this.PrepareForNewFindLookup = function(txtFind) {
        TopNav('FindMap');
        this.PrepareForFindLookup(true, 'fm', txtFind);
    }

    // FIND A BUSINESS
    /* performs find a business search */
    this.NewFindBusiness = function(latLongMode, SkipHistory, keyword, location) {
        // Hide current popup 
        HideCurrentEro(null);

		if(debug)console.log("In NewFindBusiness: Input ARGS: latLongMode:%s, SkipHistory:%s, keyword:%s, location:%s ", latLongMode, SkipHistory, keyword, location);

        if( $('yp_DrivingDirections0').style.display == 'block') {
            $('yp_DrivingDirections0').setStyle({display : 'none'});
            // Follow 3 lines added because of corners wrapper
            /*
            $('ypgCornersWrapper').style.width = '980px';
        	$('ypgCornersWrapper').style.left = '0px';
        	$('MainMap').style.left = '0px';
        	*/
        	
            this.OnMapResize(null);
            this.MapResize();
        }

    	if(debug)console.log("In mm.NewFindBusiness:  Connected: %s.", mapSearchAttachedPZ);
        if (mapSearchAttachedPZ)
        {
        	if(debug)console.log("In mm.NewFindBusiness:  Connected: %s.  Going to disconnect.", mapSearchAttachedPZ);
            mapManager.Map.DetachEvent('onendpan', mapSearch);
            mapManager.Map.DetachEvent('onendzoom', mapSearch);
            mapSearchAttachedPZ = false;
        }
        
        //This is initially saved into paneNumber -1... but after PrepareForFindLookup the what/where are resaved to paneNumber 0
        //And everything working off of paneNumber 0 from then on.
		//if (location == undefined && document.getElementById('txtBusLocation').value != "")
        //    ClientCache.Save('pane_0_EnteredLocationInput', document.getElementById('txtBusLocation').value);
        
        var skipGeoCode = false;
        
        location = (location == undefined ? document.getElementById('txtBusLocation').value : location);
        keyword = (keyword == undefined ? document.getElementById('txtBusName').value : keyword);
        if (location == undefined || location == null || location == '') {
            location = this.Map.GetCenter().Latitude + ',' + this.Map.GetCenter().Longitude;
            if(debug)console.log("In NewFindBusiness: location is empty.  Getting map center lat/lon location: %s.  Current map style: ", location, map.GetMapStyle());
			skipGeoCode = true;
        }
        //NA TopNav('FindBusiness');

        ClientCache.Save('pane_' + paneNumber + '_LocationInput', location);
        ClientCache.Save('pane_' + paneNumber + '_NameInput', keyword);
		if(debug)console.log("In NewFindBusiness: Saved what:[%s] where:[%s] into paneNumber: %d", keyword, location, paneNumber);
        ClientCache.Save('pane_' + paneNumber + '_inputTypeToValidate', 'BusLoc');
        //map.Find(null, this.PrepareForMapPointGeocoding(location), null, null, null, null, null, null, false, false, mapManager.FindInputValidatorCallback);

		//if location is lat,lon --> don't call PrepareForMapPointGeocoding and don't make ajax call because our YP geocode interface doesn't take lat,lon
		if(skipGeoCode) {
       		var placeArray = mapManager.LatLongToPlaceArray(location, "");
			mapManager.FindInputValidatorCallback(null, null, placeArray);
		} else {
        	this.YPFind(this.PrepareForMapPointGeocoding(location), mapManager.YPFindInputValidatorCallback);
		}
		

    }

	this.YPFind = function(location, callback) {
		var qString = "?where=" + location;
        var request = new AjaxRequest("/ajax/location.html" + qString, callback);
        request.Execute();
    }

    /* prepares for find a business search */
    this.PrepareForNewFindBusiness = function(location, keyword) {
        //NA TopNav('FindBusiness');
        this.PrepareForFindLookup(true, 'bus', location, keyword);
    }

    // FIND A PERSON
    /* performs find a person search */
    this.NewFindPerson = function(latLongMode, SkipHistory, keyword, location) {
        location = (location == undefined ? document.getElementById('txtPersonLocation').value : location);
        keyword = (keyword == undefined ? document.getElementById('txtPersonName').value : keyword);
        if (location == undefined || location == null || location == '')
            location = this.Map.GetCenter().Latitude + ',' + this.Map.GetCenter().Longitude;
        TopNav('FindPerson');

        ClientCache.Save('pane_' + paneNumber + '_LocationInput', location);
        ClientCache.Save('pane_' + paneNumber + '_NameInput',keyword);

        ClientCache.Save('pane_' + paneNumber + '_inputTypeToValidate', 'PerLoc');
        map.Find(null, this.PrepareForMapPointGeocoding(location), null, null, null, null, null, null, false, false, mapManager.FindInputValidatorCallback);
    }
    /* prepares for find a person search */
    this.PrepareForNewFindPerson = function(location, keyword) {
        TopNav('FindBusiness');
        this.PrepareForFindLookup(true, 'per', location, keyword);
    }

    // GET DIRECTIONS
    /* performs get directions search */
    this.GetNewDirections = function(origin, destination) {
    
        if (mapSearchAttachedPZ)
        {
            mapManager.Map.DetachEvent('onendpan', mapSearch);
            mapManager.Map.DetachEvent('onendzoom', mapSearch);
            mapSearchAttachedPZ = false;
        }
        
        origin = (origin == undefined ? document.getElementById('txtFrom').value : origin);
        destination = (destination == undefined ? document.getElementById('txtTo').value : destination);
        if (origin == undefined || origin == null || origin == '')
            origin = this.Map.GetCenter().Latitude + ',' + this.Map.GetCenter().Longitude;
        else if (destination == undefined || destination == null || destination == '')
            destination = this.Map.GetCenter().Latitude + ',' + this.Map.GetCenter().Longitude;
        //NA TopNav('DrivingDirections');

        // add searched waypoint to client cache as last waypoint
        ClientCache.Save('pane_' + paneNumber + '_FromInput', origin);
        ClientCache.Save('pane_' + paneNumber + '_ToInput', destination);

        ClientCache.Save('pane_' + paneNumber + '_inputTypeToValidate', 'From');
        map.Find(null, this.PrepareForMapPointGeocoding(origin), null, null, null, null, null, null, false, false, mapManager.FindInputValidatorCallback);
    }
    /* prepares for get directions search */
    this.PrepareForGetNewDirections = function(origin,destination) {
        TopNav('DrivingDirections');
        this.PrepareForFindLookup(true, 'dd', origin, destination);        
    }
    /* adds a waypoint to a get directions search */
    this.AddWaypoint = function(location) {
        var numWaypoints = (ClientCache.Retrieve('pane_' + paneNumber + '_NumWaypoints'));

        location = ((location == undefined) ? document.getElementById('txtWaypoint' + paneNumber).value : location);
        numWaypoints = (numWaypoints == undefined ? 0 : numWaypoints);

        // add searched waypoint to client cache as last waypoint
        ClientCache.Save('pane_' + paneNumber + '_WaypointInput' + numWaypoints, location);
        ClientCache.Save('pane_' + paneNumber + '_NumWaypoints', numWaypoints);

        ClientCache.Save('pane_' + paneNumber + '_inputTypeToValidate', 'Waypoint');
        map.Find(null, this.PrepareForMapPointGeocoding(location), null, null, null, null, null, null, false, false, mapManager.FindInputValidatorCallback);
    }

    /**
    * VE find callback to test validity of searched input
    *
    * @param shapeLayer - Destination shape layer
    * @param findResultsArray - Found locations
    * @param placeArray - Found places
    */
    this.FindInputValidatorCallback = function(shapeLayer, findResultArray, placeArray) {
        // IF NO FIND RESULTS
        if (placeArray == null) {
            mapManager.onFailedSearch();
        } else {
            var validatedInputType = ClientCache.Retrieve('pane_' + paneNumber + '_inputTypeToValidate');
            // perform find in existing pane
            if (validatedInputType == 'Waypoint') {
                // update waypoint counter stored in client cache
                ClientCache.Save('pane_' + paneNumber + '_NumWaypoints', ClientCache.Retrieve('pane_' + paneNumber + '_NumWaypoints') + 1);
                mapManager.Find(false, 'dd');
            } else if (validatedInputType == 'From') {
                ClientCache.Save('pane_' + paneNumber + '_inputTypeToValidate', 'To');
                mapManager.Map.Find(null, mapManager.PrepareForMapPointGeocoding(ClientCache.Retrieve('pane_' + paneNumber + '_ToInput')), null, null, null, null, null, null, false, false, mapManager.FindInputValidatorCallback);
            } else if (validatedInputType == 'To') {
                mapManager.Find(true, 'dd', ClientCache.Retrieve('pane_' + paneNumber + '_FromInput'), ClientCache.Retrieve('pane_' + paneNumber + '_ToInput'));
            } else if (validatedInputType == 'PerLoc') {
                mapManager.Find(true, 'per', ClientCache.Retrieve('pane_' + paneNumber + '_LocationInput'), ClientCache.Retrieve('pane_' + paneNumber + '_NameInput'));
            } else if (validatedInputType == 'BusLoc') {
                if(debug)console.log("In mm.FindInputValidatorCallback: placeArray[0].Name -> [%s]", placeArray[0].Name);                
                mapManager.Find(true, 'bus', ClientCache.Retrieve('pane_' + paneNumber + '_LocationInput'), ClientCache.Retrieve('pane_' + paneNumber + '_NameInput'));
            }
        }
    }

    /**
    * Process YP location json data
    */
    this.ProcessLocation = function(rText) {
	    try {
	        g_locationResult = eval('(' + rText + ')');

	        if (g_locationResult != undefined && g_locationResult[0].location != null) {
	        	var locationResult = g_locationResult[0];
	        	var locationName = locationResult.street + ", " + locationResult.city + ", " + locationResult.province + ", " + locationResult.postalCode;
	        	var placeArray = mapManager.LatLongToPlaceArray(locationResult.location.latitude+","+locationResult.location.longitude, mapManager.PrepareForMapPointGeocoding(locationName));
	        }
	    }
	    catch(e)
	    {
	        //alert(e.message);
	        if(debug)console.log("Catch Block: ProcessLocation: %s", e.message);
	    }
	    
		return placeArray;
    }

    /**
    * Callback wrapper to process location json data and call original callback FindInputValidatorCallback
    */
    this.YPFindInputValidatorCallback = function(rText) {
	    var placeArray = mapManager.ProcessLocation(rText);
		mapManager.FindInputValidatorCallback(null, null, placeArray);
    }

    /**
    * validates search inputs and prepares left pannel for search
    *
    * @param newFind - whether or not to create a new pane in left pannel
    * @param searchType - type of search being performed
    * @param first - find input for find on a map search
                   - from input for driving directions search
                   - location input for business or person search
    * @param second - null for find on a map search
                    - to input for driving directions search
                    - keyword input for business or person search
    *
    * returns array with validated first as first element and validated second as second element
    */
    this.PrepareForFindLookup = function(newFind, searchType, first, second) {
//console.trace();
        newFind = (ClientCache.Retrieve('lastSearchFailed') == 'true' ? false : newFind);
/*NA 
        // open pane
        if (newFind)
            AjaxControlManager.openLeftNavPane(5);
        // get number of next pane to be opened
        var nextPaneNumber = (newFind ? AjaxControlManager.getNextPaneNumber() : paneNumber);
*/
		// TODO: Figure out what to do with paneNumber and nextPaneNumber - for now just always use 0
		// I don't think paneNumber was ever set in this method... just nextPaneNumber
		// paneNumber initially set to??
		paneNumber = (paneNumber == 5 ? paneNumber++ : 0) // this test is incorrect
		var nextPaneNumber = paneNumber;
		//var nextPaneNumber = 0;
		
		//var nextPaneNumber = (newFind ? (paneNumber != 5 ? paneNumber++ : 0) : paneNumber); // wierd result
		if(debug)console.log("In PrepareForFindLookup: paneNumber:", paneNumber, " nextPaneNumber:", nextPaneNumber);

        // set last search client cache variable
        var lastSearchType = ClientCache.Retrieve('lastSearch');
        ClientCache.Save('lastSearch', searchType);

        // VALIDATE SEARCH INPUTS
        var validatedFirst = '';
        var validatedSecond = '';
        // find on a map        
        if (searchType == 'fm') {
            validatedFirst = this.validateFindInput('pane_' + nextPaneNumber + '_FindInput', first, 'txtFind');
            validatedSecond = null;
        }
        // driving directions
        else if (searchType == 'dd') {
            validatedFirst = this.validateFindInput('pane_' + nextPaneNumber + '_FromInput', first, 'txtFrom');
            validatedSecond = this.validateFindInput('pane_' + nextPaneNumber + '_ToInput', second, 'txtTo');
            // initialize NumWaypoints to 0 if not already set
            if (ClientCache.Retrieve('pane_' + nextPaneNumber + '_NumWaypoints') == undefined)
                ClientCache.Save('pane_' + nextPaneNumber + '_NumWaypoints', 0);
        }
        // find a business or find a person
        else {
        	// Save away user entered location for AJAX calls and HBX purposes
        	if (document.getElementById('txtBusLocation').value != "")
        		ClientCache.Save('pane_' + nextPaneNumber + '_EnteredLocationInput', document.getElementById('txtBusLocation').value);
            $('siWhat').value = second;
        	$('siWhere').value = ClientCache.Retrieve('pane_' + nextPaneNumber + '_EnteredLocationInput');
        	
            validatedFirst = this.validateFindInput('pane_' + nextPaneNumber + '_LocationInput', first, searchType == 'bus' ? 'txtBusLocation' : 'txtPersonLocation');
            validatedSecond = this.validateFindInput('pane_' + nextPaneNumber + '_NameInput', second, searchType == 'bus' ? 'txtBusName' : 'txtPersonName');
        }

        // SETUP PANE
        var divIdPrefix = '';
        var paneTitle = '';
        if (searchType == 'fm') {
            divIdPrefix = 'yp_FindOnMap';
            paneTitle = validatedFirst;
        }
        else if (searchType == 'dd') {
            divIdPrefix = 'yp_DrivingDirections';
            paneTitle = resourceFrom + ": " + (validatedFirst.indexOf("@") != -1 ? validatedFirst.split("@")[0] : validatedFirst) + " " + resourceTo + ": " + (validatedSecond.indexOf("@") != -1 ? validatedSecond.split("@")[0] : validatedSecond);
        }
        else if (searchType == 'bus') {
            divIdPrefix = 'yp_FindBusiness';
            paneTitle = '';
        }
        else {
            divIdPrefix = 'yp_FindPerson';
            paneTitle = '';
        }

        // add new pane to accordion
        if (newFind) {
            //NA paneNumber = AjaxControlManager.addPaneToBusinessDirectionFind(paneTitle, divIdPrefix, validatedSecond, validatedFirst);

            // Added to reset driving directions for yp.ca
            // RESET DISAMBIGUATION TEXT
            // if driving directions were previously occupying the pane
            if (ClientCache.Retrieve('lastSearchFailed') == 'false') {
	            if (lastSearchType == 'dd') {
	                var previousNumWaypoints = ClientCache.Retrieve('pane_' + paneNumber + '_NumWaypoints');
	                // reset the latest waypoint disambiguation if there was one
	                if (previousNumWaypoints > 0) {
	                    ClientCache.Save('pane_' + paneNumber + '_Waypoint' + previousNumWaypoints, undefined);
	                }
	                // else reset the from and to disambiguations
	                else {
	                    ClientCache.Save('pane_' + paneNumber + '_From', undefined);
	                    ClientCache.Save('pane_' + paneNumber + '_To', undefined);
	                }
	            }
            }
        }
        // if pane being reused because previous search failed
        else if (ClientCache.Retrieve('lastSearchFailed') == 'true') {
            // RESET DISAMBIGUATION TEXT
            // if driving directions were previously occupying the pane
            if (lastSearchType == 'dd') {
                var previousNumWaypoints = ClientCache.Retrieve('pane_' + paneNumber + '_NumWaypoints');
                // reset the latest waypoint disambiguation if there was one
                if (previousNumWaypoints > 0) {
                    ClientCache.Save('pane_' + paneNumber + '_Waypoint' + previousNumWaypoints, undefined);
                }
                // else reset the from and to disambiguations
                else {
                    ClientCache.Save('pane_' + paneNumber + '_From', undefined);
                    ClientCache.Save('pane_' + paneNumber + '_To', undefined);
                }
            }
            // if a find on a map search was previously occupying the pane
            else if (lastSearchType == 'fm') {
                // reset the from and to disambiguations
                ClientCache.Save('pane_' + paneNumber + '_Find', undefined);
            }

            // RESET HEADER
            //NA AjaxControlManager.setBusinessDirectionFindHeader(paneNumber, paneTitle, divIdPrefix, validatedSecond, validatedFirst);
            //NA AjaxControlManager.setBusinessDirectionFindContent(paneNumber, divIdPrefix);
        }
        //NA AjaxControlManager.OpenAccordionPane(AjaxControlManager.getBusinessDirectionFindAccordion(), paneNumber);

        // save search type to client cache
        ClientCache.Save('pane_' + paneNumber + '_type', searchType);

        if (searchType == 'fm') {
            findOnMap = document.getElementById(divIdPrefix + paneNumber);
            findOnMap.innerHTML = '';

            // result disambiguation
            AmbiguityDiv = document.createElement("div");
            findOnMap.appendChild(AmbiguityDiv);
            // find waypoint result disambiguation
            findOnMapFindAmbiguity = document.createElement("div");
            // find waypoint result disambiguation
            AmbiguityDiv.appendChild(findOnMapFindAmbiguity);

            // results
            findOnMapResultDiv = document.createElement("div");
            //findOnMapResultDiv.id = "findOnMapResultDiv";
            findOnMapResultDiv.id = "firstResultDiv" + paneNumber;
            findOnMapResultDiv.style.overflow = "hidden";
            findOnMap.appendChild(findOnMapResultDiv);

            findOnMapResultDiv.innerHTML = '<div class="DefaultLocation"><img style="margin-top: 15px; margin-left: 15px;" src="Images/dartblue.gif"/><span class="Arial12" style="margin-left: 6px;">' + validatedFirst + '</span></div>';
        }
        else if (searchType == 'dd') {
            // get div contained in pane
            var paneContentDiv = document.getElementById(divIdPrefix + paneNumber);
            paneContentDiv.innerHTML = '';

            // CREATE WAYPOINT DISAMBIGUATION DIVS
            var ambiguityDiv = document.createElement("div");
            ambiguityDiv.id = "outerAmbiguityDiv" + paneNumber;
            paneContentDiv.appendChild(ambiguityDiv);

            var innerAmbiguityDiv = document.createElement("div");
            innerAmbiguityDiv.id = "firstAmbiguityDiv" + paneNumber;
            innerAmbiguityDiv.style.display = 'none';
            ambiguityDiv.appendChild(innerAmbiguityDiv);

            var innerAmbiguityDiv = document.createElement("div");
            innerAmbiguityDiv.id = "secondAmbiguityDiv" + paneNumber;
            innerAmbiguityDiv.style.display = 'none';
            ambiguityDiv.appendChild(innerAmbiguityDiv);

            // CREATE CONTENT DIVS
            // results
            var resultDiv = document.createElement("div");
            resultDiv.id = "firstResultDiv" + paneNumber;
            resultDiv.style.overflow = "auto";
            $('yp_DrivingDirections' + paneNumber).style.display = "block";
            this.OnMapResize(null); // trigger re-positioning of dashboard control
            this.MapResize(); // trigger resize of map
            
            paneContentDiv.appendChild(resultDiv);

            // distance
            resultDiv = document.createElement("div");
            resultDiv.id = "secondResultDiv" + paneNumber;
            paneContentDiv.appendChild(resultDiv);

            // footer
            resultDiv = document.createElement("div");
            resultDiv.id = "thirdResultDiv" + paneNumber;
            // disclaimer
            disclaimer = "<div style='margin-left:15px; overflow:auto; font-size: 10px;'>" + resourceDDDisclaimer + "</div>";
            // add destination box
            //NA addDestination = "<div style='font:12px Arial; margin-left:15px;'><span>" + resourceDDAddDestination + "</span><span style='left:96px;'><img id='addLocationArrow" + paneNumber + "' alt='RightArrow' src='Images/rightarrow.gif' onclick='mapManager.toggleAddLocation(" + paneNumber + ")'/></span></div><div id='addDestinationPanel" + paneNumber + "'><div style='font:11px Arial; margin-left:15px; margin-top:5px;'>" + resourceDDAddressPlace + "</div><form><input id='txtWaypoint" + paneNumber + "' style='margin-left:15px; float:left;' type='text' onkeydown='ExecuteFindFromInput(\"addDestinationButton\", event);' /><img id='addDestinationButton' style='margin-left:10px;' class='handicon' src='" + images + "addButton.gif' onclick='mapManager.AddWaypoint()'/></form><div style='margin-left:15px;' class='ExampleText'>" + resourceDDExampleAddress + "</div>";
            // grey divider line
            greyLine = "<div class='grey_line_div' style='top:0px;margin-top:5px;margin-bottom:5px;' id='grey_line_div'></div>";
            // include in footer the disclamer, add destination box, and grey line
            //UP resultDiv.innerHTML = disclaimer + greyLine + addDestination;
            
            //printDDLink = "<div style='margin-left:15px; overflow:auto; font-size: 10px;'><a href='" + "/search/print/map.html?" + "'>Print Driving Directions</a></div>";
            printDDLink = "<div id='printDDLink'></div>";
            
            resultDiv.innerHTML = disclaimer + greyLine + printDDLink;
            
            paneContentDiv.appendChild(resultDiv);
        }
        var validatedInputs = new Array();
        validatedInputs.push(validatedFirst);
        validatedInputs.push(validatedSecond);
        return validatedInputs;
    }

    /**
    * Finds a geographic location by name (handles all search types)
    *
    * @param txtFrom - from location for driving directions search
    *                  search input for find on a map search
    *                  location for find a business or find a person search
    * @param txtTo - to location for driving directions search
    *                null for for find on a map search
    *                keyword for find a business or find a person search
    */
    this.FindLookup = function(txtFrom, txtTo) {
        mapManager.clearRoute();
        mapManager.ClearSearchRelatedShapes();

        var searchType = ClientCache.Retrieve('pane_' + paneNumber + '_type');
        ClientCache.Save('selected_pane_num', paneNumber);

        //store the 'from' so that, even if the user changes the textbox during callback,
        //it does not affect the actual from
        var searchInput = txtFrom;

        // instantiate array to hold waypoints
        waypointsArray = new Array();

        ShowLoading();
        //NA AjaxControlManager.findDisplayed(true);
        mapManager.FindOnMap(true, searchInput);
        //HideLoading();
    }

    /**
    * Determines type of search input and calls FindInCanadaCallback appropriatly
    *
    * @param searchCanada - whether or not to search for input in Canada (by appending ', Canada')
    * @param searchInput - location to find on map
    */
    this.FindOnMap = function(searchCanada, searchInput) {
    	if(debug)console.log("In mm.FindOnMap: paneNumber: %s, searchInput: %s", paneNumber, searchInput);
        if (searchInput == undefined) {
            mapManager.onFailedSearch();
            return;
        }

        // check if from location search are lat/long coords
        var latLongLocation = false;
        if (this.IsLatLong(searchInput)) {
            latLongLocation = true;
        }

        // location input is a name and lat/long coord pair
        if (searchInput.indexOf("@") != -1) {
            mapManager.FindCallback(null, null, this.LatLongToPlaceArray(searchInput.split("@")[1], this.PrepareForMapPointGeocoding(searchInput.split("@")[0])));
        }
        // location input is a lat/long coord
        else if (latLongLocation) {
            mapManager.FindCallback(null, null, this.LatLongToPlaceArray(searchInput));
        }
        // location is a normal where search
        else {
            // New search being performed that does not look like a lat/lon & is not the 1st time GNB query.  Can reset YPSearchManager.isGNBForListingPopup to false to indicate not to plot SELECTED pin used for proximity search around it.
            if(YPSearchManager.isGNBForListingPopup == true && YPSearchManager.ranGNBOnce == true) {
                YPSearchManager.isGNBForListingPopup = false;
                YPSearchManager.ranGNBOnce = false;
                YPSearchManager.g_GNBSelectedData = new Object;
                if(debug)console.log('In mm.FindOnMap: reset isGNBForListingPopup and ranGNBOnce to false. No need to show selected pin of proximity search anymore');
            } else if (YPSearchManager.isGNBForListingPopup == true) {
                YPSearchManager.ranGNBOnce = true;
                if(debug)console.log("In mm.FindOnMap: setting ranGNBOnce to true so next time through this method with a non lat/lon where search ... it will reset isGNBForListingPopup back to false");
            }

			if(debug)console.log("In mm.FindOnMap: paneNumber: %s, ccr_type: %s", paneNumber, ClientCache.Retrieve('pane_' + paneNumber + '_type'));


            if (ClientCache.Retrieve('pane_' + paneNumber + '_type') == 'per' || ClientCache.Retrieve('pane_' + paneNumber + '_type') == 'bus') {
            	if(debug)console.log("In mm.FindOnMap: run map.Find with callback FindBusPerCallback");

                //map.Find(null, this.PrepareForMapPointGeocoding(searchInput) + ', Canada', null, null, null, null, null, null, false, false, mapManager.FindBusPerCallback);
                //this.YPFind(this.PrepareForMapPointGeocoding(searchInput) + ', Canada', mapManager.YPFindBusPerCallback);
                this.YPFind(this.PrepareForMapPointGeocoding(searchInput), mapManager.YPFindBusPerCallback);  // Adding Canada to where may change lat/lon returned - depending on value of where
            } else {
            	if(debug)console.log("In mm.FindOnMap: run map.Find with callback of either FindInCanadaCallback or FindCallback [searchCanada:%s]", searchCanada);
            
                if (searchCanada) {
                    map.Find(null, this.PrepareForMapPointGeocoding(searchInput) + ', Canada', null, null, null, null, null, null, false, false, mapManager.FindInCanadaCallback);
                }
                else {
                    map.Find(null, this.PrepareForMapPointGeocoding(searchInput), null, null, null, null, null, null, false, false, mapManager.FindCallback);
                }
            }
        }
    }

    /**
    * VE find callback called after apppending Canada to search input
    * (checks if location is Canadian (i.e. 'london' does not, but 'london, Canada' does return 'London, ON'))
    *
    * @param shapeLayer - Destination shape layer
    * @param findResultsArray - Found locations
    * @param placeArray - Found places
    *
    * returns null on successuflly performing search
    */
    this.FindInCanadaCallback = function(shapeLayer, findResultArray, placeArray) {
        // GET SEARCH TYPE AND NUM WAYPOITNS TO ADD
        var numWaypoints = ClientCache.Retrieve('pane_' + paneNumber + '_NumWaypoints');
        var searchType = ClientCache.Retrieve('pane_' + paneNumber + '_type');

        // CANADIAN LOCATION
        if (placeArray != null && placeArray[0].Name != 'Canada') {
            // find on a map
            if (searchType == 'fm') {
                // display results
                mapManager.DisambiguateFindResults(placeArray, 'FindInput', 'Find');

                // READ WAYPOINTS ARRAY
                HideLoading();
                mapManager.ReadWaypointsArray(searchType);
            }

            // driving directions
            else if (searchType == 'dd') {
            	if(debug)console.log("In FindInCanadaCallback: waypointsArray.length: ", waypointsArray.length);
            	
                // from input
                if (waypointsArray.length == 0) {
                    // display results
                    mapManager.DisambiguateFindResults(placeArray, 'FromInput', 'From');
                    // find to location on map
                    mapManager.FindOnMap(true, ClientCache.Retrieve('pane_' + paneNumber + '_ToInput'));
                    return;
                }
                // to input
                else if (waypointsArray.length == 1) {
                    // display results
                    mapManager.DisambiguateFindResults(placeArray, 'ToInput', 'To');
                    // find next additional waypoint location on map
                    if ((waypointsArray.length - 2) < numWaypoints) {
                        mapManager.FindOnMap(true, ClientCache.Retrieve('pane_' + paneNumber + '_WaypointInput' + (waypointsArray.length - 2)));
                        return;
                    }
                    mapManager.ReadWaypointsArray(searchType);
                    return;
                }
                // additional waypoint input
                else {
                    // display results
                    mapManager.DisambiguateFindResults(placeArray, 'WaypointInput' + (waypointsArray.length - 2), 'Waypoint' + (waypointsArray.length - 1));
                    // find next additional waypoint location on map
                    if ((waypointsArray.length - 2) < numWaypoints) {
                        mapManager.FindOnMap(true, ClientCache.Retrieve('pane_' + paneNumber + '_WaypointInput' + (waypointsArray.length - 2)));
                        return;
                    }
                    mapManager.ReadWaypointsArray(searchType);
                    return;
                }
            }

            // find a business or find a person
            else {
                mapManager.FindBusPerCallback(shapeLayer, findResultArray, placeArray);
            }
            return;
        }

        // NON-CANADIAN LOCATION
        else {
            var searchInput;
            // find on a map
            if (searchType == 'fm') {
                searchInput = ClientCache.Retrieve('pane_' + paneNumber + '_FindInput');
                mapManager.FindOnMap(false, searchInput);

                // READ WAYPOINTS ARRAY
                HideLoading();
            }
            // driving directions
            else if (searchType == 'dd') {
                // from input
                if (waypointsArray.length == 0)
                    searchInput = ClientCache.Retrieve('pane_' + paneNumber + '_FromInput');
                // to input
                else if (waypointsArray.length == 1)
                    searchInput = ClientCache.Retrieve('pane_' + paneNumber + '_ToInput');
                // additional waypoint input
                else if ((waypointsArray.length - 2) < numWaypoints)
                    searchInput = ClientCache.Retrieve('pane_' + paneNumber + '_WaypointInput' + (waypointsArray.length - 2));
                //map.Find(null, searchInput, null, null, null, null, null, null, false, true, mapManager.FindCallback);
                mapManager.FindOnMap(false, searchInput);

                // READ WAYPOINTS ARRAY
                HideLoading();
            }

            // find a business or find a person
            else {
                searchInput = ClientCache.Retrieve('pane_' + paneNumber + '_NameInput');
                mapManager.FindOnMap(false, searchInput);
            }
        }
    }

    /**
    * Displays appropriate failed search message and save HBXSearch
    *
    * @param inputType - type of find being performed
    * @param invalidInputFieldID - DOM element id of input field for which to display error message
    *
    * return null
    */
    this.onFailedSearch = function(inputType, invalidInputFieldID) {
        ClientCache.Save('lastSearchFailed', 'true');

        var searchInputField = document.getElementById(invalidInputFieldID);

        document.getElementById('ErrHeaderTxt').style.visibility = "visible";
        if (searchInputField != undefined)
            document.getElementById(invalidInputFieldID).style.border = "1px solid red";

        var searchInput = searchInputField != undefined ? searchInputField.value : ClientCache.Retrieve('pane_' + paneNumber + '_' + inputType + 'Input');

        search = inputType + searchInput;

        if (searchInput != '' && (inputType != null || invalidInputFieldID != null))
            YPSearchManager.HBXSearch('map', 0, null, search);

        HideLoading();

        if (searchInput == undefined) {
            var error = '';
            var divIdPrefix = '';

            switch (ClientCache.Retrieve('lastSearch')) {
                case 'fm':
                    error = resourceErrorFOM;
                    divIdPrefix = 'yp_FindOnMap';
                    break;
                case 'bus':
                    error = resourceErrorFAB;
                    divIdPrefix = 'yp_DrivingDirections';
                    break;
                case 'per':
                    error = resourceErrorFAB;
                    divIdPrefix = 'yp_FindBusiness';
                    break;
                case 'dd':
                    error = resourceErrorGDD;
                    divIdPrefix = 'yp_FindPerson';
                    break;
            }

            document.getElementById('ErrHeaderTxt').innerHTML = error;
            //NA AjaxControlManager.setBusinessDirectionFindHeader(paneNumber, error, divIdPrefix, searchInput);
            //TEMP document.getElementById(divIdPrefix + paneNumber).innerHTML = '<div class="TopErrorText" style="visibility:visible">' + error + '</div>';
        }

        return;
    }

    /**
    * VE find callback
    *
    * @param shapeLayer - Destination shape layer
    * @param findResultsArray - Found locations
    * @param placeArray - Found places
    *
    * returns null on successuflly performing search
    */
    this.FindCallback = function(shapeLayer, findResultArray, placeArray) {
        // GET SEARCH TYPE AND NUM WAYPOITNS TO ADD
        var numWaypoints = ClientCache.Retrieve('pane_' + paneNumber + '_NumWaypoints');
        var searchType = ClientCache.Retrieve('pane_' + paneNumber + '_type');

        // IF NO FIND RESULTS
        if (placeArray == null) {
            mapManager.onFailedSearch('Find','txtFind');
            return;
        }

        // IF AT LEAST ONE FIND RESULT
        else {
            // find on a map
            if (searchType == 'fm') {
                // display results
                mapManager.DisambiguateFindResults(placeArray, 'FindInput', 'Find');
                mapManager.ReadWaypointsArray(searchType);
            }

            // driving directions
            else if (searchType == 'dd') {
            	if(debug)console.log("In FindCallback: waypointsArray.length: ", waypointsArray.length);
            	
                // from input
                if (waypointsArray.length == 0) {
                    // display results
                    mapManager.DisambiguateFindResults(placeArray, 'FromInput', 'From');
                    // check if to location is Canadian
                    mapManager.FindOnMap(true, ClientCache.Retrieve('pane_' + paneNumber + '_ToInput'));
                }
                // to input
                else if (waypointsArray.length == 1) {
                    // display results
                    mapManager.DisambiguateFindResults(placeArray, 'ToInput', 'To');
                    // check if next additional waypoint location is Canadian
                    if ((waypointsArray.length - 2) < numWaypoints) {
                        mapManager.FindOnMap(true, ClientCache.Retrieve('pane_' + paneNumber + '_WaypointInput' + (waypointsArray.length - 2)));
                        return;
                    }
                    mapManager.ReadWaypointsArray(ClientCache.Retrieve('pane_' + paneNumber + '_type'));
                    return;
                }
                // additional waypoint input
                else {
                    // display results
                    mapManager.DisambiguateFindResults(placeArray, 'WaypointInput' + (waypointsArray.length - 2), 'Waypoint' + (waypointsArray.length) - 1);
                    // check if next additional waypoint location is Canadian
                    if ((waypointsArray.length - 2) < numWaypoints) {
                        mapManager.FindOnMap(true, ClientCache.Retrieve('pane_' + paneNumber + '_WaypointInput' + (waypointsArray.length - 2)));
                        return;
                    }
                    mapManager.ReadWaypointsArray(ClientCache.Retrieve('pane_' + paneNumber + '_type'));
                    return;
                }
            }

            // find a business or find a person
            else {
                mapManager.FindBusPerCallback(shapeLayer, findResultArray, placeArray);
            }
        }
    }

    /**
    * Calls functions to disambiguate find results and display default result on map
    *
    * @param placeArray - Found places
    * @param searchInputId - type of find input being disambiguated
    * @param searchId - type of find for which input being disambiguated
    */
    this.DisambiguateFindResults = function(placeArray, searchInputId, searchId) {
        var search = ClientCache.Retrieve('pane_' + paneNumber + '_' + searchId);

        // if search disambiguated in client cache
        if (search != undefined) {
            waypointsArray.push(search);
        }
        // else if search not disambiguated in client cache
        else {
            var disambiguationText = mapManager.getDisambiguationText(searchId, placeArray, ClientCache.Retrieve('pane_' + paneNumber + '_' + searchInputId));
            if (searchId == 'Find') {
                findOnMapFindAmbiguity.innerHTML = disambiguationText;
                //mapManager.resizeLeftDiv();
                mapManager.resizeLeftDD();
            }
            else if (disambiguationText != '') {
                if (searchId == 'From') {
                    document.getElementById("firstAmbiguityDiv" + paneNumber).style.display = 'block';
                    document.getElementById("firstAmbiguityDiv" + paneNumber).innerHTML = disambiguationText;
                }
                else if (searchId == 'To') {
                    document.getElementById("secondAmbiguityDiv" + paneNumber).style.display = 'block';
                    document.getElementById("secondAmbiguityDiv" + paneNumber).innerHTML = disambiguationText;
                }
                else {
                    // create waypoint result disambiguation
                    var innerAmbiguityDiv = document.createElement("div");
                    innerAmbiguityDiv.id = "Waypoint" + (waypointsArray.length - 2) + "AmbiguityDiv" + paneNumber;
                    innerAmbiguityDiv.innerHTML = disambiguationText
                    document.getElementById("outerAmbiguityDiv" + paneNumber).appendChild(innerAmbiguityDiv);
                }
            }
        }
    }

    /**
    * re-performs find of specified pane in that pane
    *
    * @param paneClicked - id number of pane for which to re-perform find
    * @param first - from location for driving directions search
    *              - search input for find on a map search
    *              - location for find a business or find a person search
    * @param second - to location for driving directions search
    *               - null for for find on a map search
    *               - keyword for find a business or find a person search
    * @param sbn - null for find on a map, find a person, and driving directions search
    *            - whether or not to perform business name search for find a business
    */
    this.EmulateSelectedPaneFind = function(paneClicked, first, second, sbn) {
        HideLoading();

        FindNearbyClick(true);
        paneNumber = paneClicked;

        switch (ClientCache.Retrieve('pane_' + paneClicked + '_type')) {
            case 'fm':
                TopNav('FindMap');

                findOnMap = document.getElementById('yp_FindOnMap' + paneClicked);

                // get result disambiguation div
                AmbiguityDiv = findOnMap.childNodes[0];

                // get results
                findOnMapResultDiv = findOnMap.childNodes[1];
                first = ClientCache.Retrieve('pane_' + paneClicked + '_FindInput');
                second = null;

                center = this.Map.GetCenter();
                zoomLevel = this.Map.GetZoomLevel();

                this.Map.SetCenterAndZoom(center, zoomLevel);
                this.Map.SetCenterAndZoom(center, 5);
                this.Map.SetCenterAndZoom(center, zoomLevel);

                break;
            case 'bus':
                TopNav('FindBusiness');

                paneNumber = paneClicked;

                break;
            case 'per':
                TopNav('FindPerson');

                paneNumber = paneClicked;

                break;
            case 'dd':

                TopNav('DrivingDirections');

                // get div contained in pane
                drivingDirections = document.getElementById('yp_DrivingDirections' + paneNumber);

                // CREATE WAYPOINT DISAMBIGUATION DIVS

                // get div holding all disambigaution divs
                AmbiguityDiv = drivingDirections.childNodes[0];

                // from waypoint result disambiguation
                drivingDirectionsFromAmbiguity = AmbiguityDiv.childNodes[0];

                // to waypoint result disambiguation
                drivingDirectionsToAmbiguity = AmbiguityDiv.childNodes[1];

                // CREATE CONTENT DIVS

                // results
                drivingDirectionResultDiv = drivingDirections.childNodes[1];

                // distance
                drivingDirectionDistanceDiv = drivingDirections.childNodes[2];

                HideLoading();
                break;
        }

        AjaxControlManager.openLeftNavPane(5);

        this.FindLookup(first, second);
    }

    /**
    * deletes any search specific shapes from map and clears all search input fields
    */
    this.ClearFind = function() {
        this.clearRoute();
        this.ClearSearchRelatedShapes();

        // blank out all search fields
        //NA document.getElementById('txtFind').value = '';
        document.getElementById('txtBusLocation').value = '';
        /* Don't clear what text field for now */
        //document.getElementById('txtBusName').value = '';
        //NA document.getElementById('txtPersonLocation').value = '';
        //NA document.getElementById('txtPersonName').value = '';
        //NA document.getElementById('txtFrom').value = '';
        //NA document.getElementById('txtTo').value = '';
    }
    
    /**
     * Category Search
     */
    this.CategorySearch = function()
    {
        document.getElementById('txtBusName').value = document.getElementById('txtCategorySearch').value;
        var center = mapManager.Map.GetCenter();
        document.getElementById('txtBusLocation').value = (Math.round(center.Latitude*100)/100) + ', ' + (Math.round(center.Longitude*100)/100);
        TopNav("FindBusiness");
        this.SetCategorySearch(true);
        this.NewFindBusiness(true);
    }

    /**
     * VE business or person search callback
     *
     * @param shapeLayer - Destination shape layer
     * @param findResultsArray - Found locations
     * @param placeArray - Found places
     */
    this.FindBusPerCallback = function(shapeLayer, findResultArray, placeArray) {
        if (placeArray) {
            // Take first entry
            if (placeArray.length > 0)
                YPSearchManager.Search(ClientCache.Retrieve('lastSearch'), false, placeArray);
        }
        else {
            YPSearchManager.Search(ClientCache.Retrieve('lastSearch'));
        }
        //reset back to -1 so that, it creates a new pane by default
        findBusinessResultsPaneNumber = -1;
    }
    
    /**
    * Callback wrapper to process location json data and call original callback FindBusPerCallback
    */
    this.YPFindBusPerCallback = function(rText) {
	    var placeArray = mapManager.ProcessLocation(rText);
		mapManager.FindBusPerCallback(null, null, placeArray);
    }

    /**
    * deletes any search specific shapes or routes from map and clears all search input fields
    */
    this.clearRoute = function()
    {
        var map = mapManager.Map;
        var shapeLayerCount = map.GetShapeLayerCount();
        map.DeleteRoute();
        for(var i = 0; i < shapeLayerCount; i++) 
        {
            var shapeLayer = map.GetShapeLayerByIndex(i);
            if (shapeLayer == null)
            {
                break;
            }
        
            var shapeCount = shapeLayer.GetShapeCount();
            for(var j = 0; j < shapeCount ; j++) 
            {
                var shape = shapeLayer.GetShapeByIndex(j);
                var icon = shape.GetCustomIcon();
                if (!(typeof icon == "string")){
                    break;
                }
                else if(icon.search('A_Icon.gif') > 0)
                { 
                    map.DeleteShapeLayer(shapeLayer); 
                    break; 
                }
            }
        }
    }

    /**
     * Switches text inside From/To textboxes for Get Driving Directions
     */
    this.SwitchDirections = function()
    {
        var txtFrom = document.getElementById('txtFrom').value;
        document.getElementById('txtFrom').value = document.getElementById('txtTo').value
        document.getElementById('txtTo').value = txtFrom;
    }

    /**
     * pushes most appropriate result from placeArray into waypointsArray
     *
     * @param id - type of search for which input being disambiguated
     * @param placeArray - returned results of search for input
     * @param input - original user entered input
     *
     * returns html table of results in placeArray as disambiguation block
     */
    this.getDisambiguationText = function(id, placeArray, input) {
        var name;
        var postal;
        var lat;
        var lon;
        var display = 'block';
        var ambiguationText = "";
        var index = 0;
        // text for ambiguous 'from' locations
        var ambiguityArray = new Array;
        var ambiguityTextArray = new Array;
        for (var i = 0; i < placeArray.length; i++) {
            ambiguityArray[i] = new Array;
            name = placeArray[i].Name;
            // if the current location match contains a postal or province code
            if (name.match((/([a-zA-Z][0-9][a-zA-Z])(\s*[0-9][a-zA-Z][0-9])?/)) || name.match(/,\s(AB|BC|MB|NB|NL|NS|NT|NU|ON|PE|QC|SK|YT)/)) {
                // only update default location to current if match confidence is higher (match confidence enum is lower)
                index = placeArray[i].MatchConfidence < placeArray[index].MatchConfidence ? i : index;
            }
            // push ambiguous results into array
            ambiguityTextArray.push(name + ";" + "new VELatLong(" + placeArray[i].LatLong.Latitude + "," + placeArray[i].LatLong.Longitude + ")',\'" + id + "\');\">" + name);
            //ambiguityTextArray.push(placeArray[i].Name + ";" + "new VELatLong(" + placeArray[i].LatLong.Latitude.toFixed(4) + "," + placeArray[i].LatLong.Longitude.toFixed(4) + ")');\">" + name);
        }
        // if ambiguous results returned
        if (ambiguityArray.length > 1) {
            ambiguationText += "<span class='DisambiguationText'>" + resourceYourSearchOf + " </span><span class='DisambiguationLocation'>" + input + "</span>";
            // if more than 3 results returned
            if (ambiguityArray.length > 3) {
                // do not open ambiguous results list
                display = 'none';
                ambiguationText += ' ' + resourceReturnedMultiple + ' <a id="' + id + 'AmbiguationExpand" style="cursor:pointer" onclick="mapManager.changeDisplay(\'' + id + paneNumber + 'AmbiguationTable\');">+</a>';
            } else ambiguationText += "<span class='DisambiguationText'> " + resourceReturnedMultiple + ":" + "</span>";
            // display ambiguous results in list
            ambiguationText += "<table id='" + id + paneNumber + "AmbiguationTable' style='display:" + display + "'><tr><td><div class='handicon locationunderlined' onclick=\"mapManager.disambiguateWaypoint('" + placeArray[index].Name + "','" + ambiguityTextArray.join("</div><div class='handicon locationunderlined' onclick=\"mapManager.disambiguateWaypoint('" + placeArray[index].Name + "','") + "</div></td></tr></table>";
            ambiguationText += "<div class='lines'></div>";
        }
        // take the result containing a postal or province code as default to display
        var defaultLocation = placeArray[index].Name + ";" + "new VELatLong(" + placeArray[index].LatLong.Latitude + "," + placeArray[index].LatLong.Longitude + ")";
        // include default location in waypoints array
        waypointsArray.push(defaultLocation);

        // save default location to client cache
        ClientCache.Save('pane_' + paneNumber + '_' + id, defaultLocation);

        if(debug)console.log("mm.getDisambiguationText(): ", placeArray[index].Name );


        return ambiguationText;
    }

    /**
    * pushes most appropriate result from placeArray into waypointsArray
    *
    * @param toRemoveName - location being replaced in waypoints array
    * @param toAdd - location replacing old location in waypoints array
    * @param id - type of search for which input being disambiguated
    */
    this.disambiguateWaypoint = function(toRemoveName, toAdd, id) {
        var waypoint;
        var waypointName;
        var index = 0;
        for (var i = 0; i < waypointsArray.length; i++) {
            waypoint = waypointsArray[i].split(';');
            waypointName = waypoint[0];
            if (waypointName == toRemoveName) {
                waypointsArray[i] = toAdd;
                index = i;
                break;
            }
        }

        // CLEAR DISAMBIGUATION TEXT FOR DISAMBIGUATED WAYPOINT
        if (ClientCache.Retrieve('pane_' + paneNumber + '_type') == 'dd')
            AmbiguityDiv = document.getElementById('outerAmbiguityDiv' + paneNumber);
        var ambiguationDivs = AmbiguityDiv.childNodes;
        ambiguationDivs[index].innerHTML = "";
        ambiguationDivs[index].style.display = "none";

        // only update if disambiguation not default
        if (toRemoveName != toAdd) {

            // UPDATING CLIENT CACHE
            // update client cache with disambiguated location after user chooses a disambiguation
            ClientCache.Save('pane_' + paneNumber + '_' + id, waypointsArray[index]);

            // READ WAYPOINTS ARRAY
            // if there is more than one waypoint
            if (waypointsArray.length > 1) {
                // get driving directions between waypoints
                this.ReadWaypointsArray('dd');
            }
            // else, find waypoint on map
            else {
                // add disambiguated content in active pane, set lastSearchFailed to true to have old content removed
                ClientCache.Save('lastSearchFailed', 'true');
                this.PrepareForFindLookup(false, 'fm', this.extractPlaceValues(false, 0), null);
                ClientCache.Save('lastSearchFailed', 'false');
                
                mapManager.ClearSearchRelatedShapes();
                this.ReadWaypointsArray('fm');
                ClientCache.Save('selected_pane_num', paneNumber);
            }
        }

    }

    /* removes all shapes from map */
    this.ClearSearchRelatedShapes = function() {
        if(debug)console.log("In ClearSearchRelatedShapes()");

// Debugging Start		
        if(debug) {
			// Something is clearing the pins and cluster pins as the zoom is changing... I don't see any explict calls in FormatClusterShapes() or customCluster() methods
			// Wierd thing is something is remembering the marker images and puts them back on the page!!

	        var map = mapManager.Map;
	        var shapeLayerCount = map.GetShapeLayerCount();
	        console.log("In ClearSearchRelatedShapes: shapeLayerCount:%d", shapeLayerCount);
			for(var i = 0; i < shapeLayerCount; i++) 
	        {
	            var shapeLayer = map.GetShapeLayerByIndex(i);
	            if (shapeLayer == null)
	            {
	                break;
	            }
	        
	            var shapeCount = shapeLayer.GetShapeCount();
	            if(debug)console.log("In ClearSearchRelatedShapes: shapeLayer:%d has %d shapes", i, shapeCount);        
	/*            
	            for(var j = 0; j < shapeCount ; j++) 
	            {
	                var shape = shapeLayer.GetShapeByIndex(j);
	                var icon = shape.GetCustomIcon();
	                if (!(typeof icon == "string")){
	                    break;
	                }
	                else if(icon.search('A_Icon.gif') > 0)
	                { 
	                    map.DeleteShapeLayer(shapeLayer); 
	                    break; 
	                }
	            }
	*/
	        }
        }
// Debugging End
        
        mapManager.Map.DeleteAllShapes();
        if(debug)console.log("In ClearSearchRelatedShapes: Just ran mapManager.Map.DeleteAllShapes()");
                
		// If I zoom out higher than last zoom level I made a search at -> more shapeLayers are being created by Cluster.js AddShapes() method !!!
		// Following deletes empty shape layers
        var map = mapManager.Map;
        var shapeLayerCount = map.GetShapeLayerCount();
        if(debug)console.log("In ClearSearchRelatedShapes: shapeLayerCount:%d", shapeLayerCount);
		for(var i = 0; i < shapeLayerCount; i++) 
        {
            var shapeLayer = map.GetShapeLayerByIndex(i);
            if (shapeLayer == null)
            {
                break;
            }      
            var shapeCount = shapeLayer.GetShapeCount();
            if(debug)console.log("In ClearSearchRelatedShapes: shapeLayer:%d has %d shapes", i, shapeCount);
            
            if (shapeCount == 0) {
            	map.DeleteShapeLayer(shapeLayer); 
            	if(debug)console.log("In ClearSearchRelatedShapes: Deleting shapeLayer:%d because it has %d shapes", i, shapeCount);
            } 
        }
        var shapeLayerCount = map.GetShapeLayerCount();
        if(debug)console.log("In ClearSearchRelatedShapes: shapeLayerCount:%d", shapeLayerCount);

        //TEMP POIManager.HidePOIs();
    }

    /** 
     * gets lat/long coords from waypoints array and adds shapes to map based on find type
     *
     * @param type - type of find for which shapes are being added
     */
    this.ReadWaypointsArray = function(type) {
        ShowLoading();

        var waypointsLLArray = new Array();
        for (var i = 0; i < waypointsArray.length; i++) {
            waypointsLLArray.push(eval(this.extractPlaceValues(true, i)));
        }

        // get driving directions between waypoints
        if (type == 'dd') {
            //Route preferences as decided through YPG Mockups
            var options = new VERouteOptions();
            options.RouteColor = new VEColor(0, 73, 134, 0.5);
            options.RouteWeight = 6;
            options.RouteCallback = this.onGotRoute;
            options.ShowDisambiguation = false;
            options.ShowErrorMessages = false;
            options.DistanceUnit = VERouteDistanceUnit.Kilometer;
            map.GetDirections(waypointsLLArray, options);

            // SAVE USERS ROUTE QUERY WITH YPSEARCHMANAGER
            var query = YPSearchManager.CreateSearchQuery('route', null, null, null, ClientCache.Retrieve('pane_' + paneNumber + '_FromInput'), ClientCache.Retrieve('pane_' + paneNumber + '_ToInput'));
            YPSearchManager.PersistQuery(query, 'route');

            var origin = ClientCache.Retrieve('pane_' + paneNumber + '_FromInput');
            var destination = ClientCache.Retrieve('pane_' + paneNumber + '_ToInput');

            ClientCache.Save('origin', origin);
            ClientCache.Save('destination', destination);
            ClientCache.Save('lastSearch', 'dd');

            //YPSearchManager.HBXSearch('directions', 1, null, "From " + origin + " To " + destination);
        }
        // find waypoint on map
        else {
            waypoint = waypointsArray[0].split(';');
            var waypointName = waypoint[0];
            var waypointVELatLon = waypoint[1].split('(');
            var waypointLatLon = waypointVELatLon[1].split(',');
            var waypointLat = waypointLatLon[0];
            var waypointLon = waypointLatLon[1].substring(0, waypointLatLon[1].length - 1);

            YPSearchManager.includePlaces(this.LatLongToPlaceArray(waypointLat + ',' + waypointLon, waypoint[0]));

            this.findOnMap(0, waypointName, waypointLat, waypointLon);

            // SAVE USERS FIND ON MAP QUERY WITH YPSEARCHMANAGER
            var query = YPSearchManager.CreateSearchQuery('map', null, waypointName, new VELatLong(waypointLat, waypointLon), null, null);
            YPSearchManager.PersistQuery(query, 'map');

            POIManager.RefreshPOIs();

            var location = document.getElementById('txtFind').value;

            ClientCache.Save('location', location);
            ClientCache.Save('lastSearch', 'fm');

            YPSearchManager.HBXSearch('map', 1, null, location);
        }
        //NA mapManager.resizeLeftDiv();
    }

    /** 
    * splits specified location into lat/long coord and place name
    *
    * @param getLatLong - whether or not to return lat/long coord
    * @param index - index of location in waypoints array
    *
    * returns - lat/long coord if getLatLong set to true
    *         - place name if getLatLong set to false
    */
    this.extractPlaceValues = function(getLatLong, index) {
        var itemArray = waypointsArray[index].split(';');
        //Return either VE location latlong or place name
        if (getLatLong) {
            return itemArray[1];
        }
        else {
            return itemArray[0];
        }
    }

    /**
     * sets the style.display value for the element with id=id to none or block
     *
     * @param id - id of DOM element of which to set style.display
     */
    this.changeDisplay = function(id){
        var element = document.getElementById(id);
        var display = element.style.display;
        if (display == 'block')
            element.style.display = 'none';
        else
            element.style.display = 'block';
    }
    
    /**
    * Adds pushpin for location at lat,lon to map
    *
    * @param index - id of pushpin being
    * @param location - name of pushpin location
    * @param latitude - latitude of pushpin location
    * @param longitude - longitude of pushpin location
    */
    this.findOnMap = function(index, location, latitude, longitude) {
        ShowLoading();

        var divHeight = "170px";
        var topMargin = "8px";
        var dartImg = "dartblue.gif";

        var description = '<div style="height: ' + divHeight + ';margin-top:' + topMargin + ';"><div class="popupTop"><div class="popupTopLeft"><div style="display:block; margin-top:5px; margin-bottom:5px;"><img src="Images/dartblue.gif"></img></div><div style="font-weight: bold; font: 12px/14px Arial;"><strong>' + location + '</strong></div></div><div class="popupTopRight"><div id=\"AL_ACTION_' + index + '\" class="popupActionArea" style="top:10px;"><div id=\"AL_EMPTY_' + index + '\" style="height:130px; width:100px;"></div><div id=\"AL_TO_' + index + '\" style="height:130px; display:none; margin-left:5px;"><div class="popupHeader"><strong>' + resourceDD + ':</strong></div><br/><div><img src="Images/tohereicon.gif">' + resourceToHere + ':</img></div><input type="text" id="l_toAddress' + index + '" style="width:158px;" onkeydown="ExecuteFindFromInput(\'l_imgTo' + (index) + '\', event);"/><br/><div class="popupLink" onclick="YPSearchManager.ShowActionDiv(\'AL_\', ' + index + ', \'FROM\');">' + resourceFromHere + '<img src="images/fromhereicon.gif"></div><div><img id="l_imgTo' + index + '" src="' + images + 'GetDD.gif" class="popupLink" style="left:100px; float: right;" onclick="YPSearchManager.GDDForLocationPopup(\'TO\');" /></div></div><div id=\"AL_FROM_' + index + '\" style="height:130px; display:none; margin-left:5px;"><div class="popupHeader"><strong>' + resourceDD + ': </strong></div><br/><div><img src="Images/fromhereicon.gif">' + resourceFromHere + ':</img></div><input type="text" id="l_fromAddress' + index + '" style="width:158px;" onkeydown="ExecuteFindFromInput(\'l_imgFrom' + (index) + '\', event);"/><br/><div class="popupLink" onclick="YPSearchManager.ShowActionDiv(\'AL_\', ' + (index) + ', \'TO\');">' + resourceToHere + '<img src="images/tohereicon.gif"></div><div><img id="l_imgFrom' + (index) + '" src="' + images + 'GetDD.gif" class="popupLink" style="left:100px; float: right;" onclick="YPSearchManager.GDDForLocationPopup(\'FROM\');"/></div></div><div id=\"AL_NEAR_' + index + '\" style="height:130px;display:none;"><div class="popupHeader"><strong>' + resourceWhatsNearby + ': </strong></div><br/><div class="popupSubheader">' + resourceSearchForCategory + ':<br/></div><input type="text" id="l_nearby' + index + '" style="width:158px;" onkeydown="ExecuteFindFromInput(\'l_imgNear' + (index) + '\', event);"/><br/><div style="float:left; width:110px">' + resourceWhatsNearbyExample + '</div><div><img id="l_imgNear' + (index) + '" src="' + images + 'GetDD.gif" class="popupLink" style="margin-top:11px; left:100px; float: right;" onclick="YPSearchManager.GNBForLocationPopup();"/></div></div><div id=\"AL_MAP_' + index + '\" style="height:130px;display:none;"><div id=\"AL_MAP_SAVE_' + index + '\" style="display:none"><div style="float:left;"><div class="popupHeader" style="width:110px"><strong>' + resourceSaveToAMap + ': </strong></div><br /><div style="width:110px">' + resourceSaveToAMapPrompt + '</div></div><div><img src="Images/' + dartImg + '" class="popupLink" style="margin-right:10px; margin-top:10px; float: right; border: 1px solid black;" /></div><div style="margin-top:10px;"><select id="mapSelect" style="width:158px;""></select><br/></div><div><img id="l_imgAdd' + (index) + '" src="' + images + 'doneButton.gif" class="popupLink" style="left:100px; float: right;" onclick="YPSearchManager.SaveLocationToCustomMap();"/></div></div><div id=\"AL_MAP_WARN_' + index + '\" style="float:left;display:none"><div class="popupHeader" style="width:110px"><strong>' + resourceSaveToAMap + ': </strong></div><br /><div style="width:180px">' + resourceLoginNeeded + '</div></div></div></div></div></div><div class="popupBottom"><table><tr><td><table><td><img src="images/drivingicon.gif" align="left" style="margin-right:3px;margin-left:3px"></img></td><td>' + resourceDD.toUpperCase() + '<div></div><span class="popupLink popupDrivingFunctionTo" onclick="YPSearchManager.ShowActionDiv(\'AL_\', ' + (index) + ', \'TO\');"><img src="images/tohereicon.gif"><span>' + resourceToHere.toUpperCase() + '</span></img></span><span> | </span><span class="popupLink popupDrivingFunctionFrom" onclick="YPSearchManager.ShowActionDiv(\'AL_\', ' + (index) + ', \'FROM\');"><img src="images/fromhereicon.gif"><span>' + resourceFromHere.toUpperCase() + '</span></img></span></td><td style="width:60px;margin-right:3px;"><span class="popupLink" onclick="YPSearchManager.ShowActionDiv(\'AL_\', ' + (index) + ', \'NEAR\');"><img src="images/nearbyicon.gif" align="left" style="margin-right:3px"></img><span class="popupLink">' + resourceWhatsNearby.toUpperCase() + '</div></span></td><td style="margin-right:3px; width:70px;"><span class="popupLink" onclick="YPSearchManager.ShowActionDiv(\'AL_\', ' + (index) + ', \'MAP\');"><img src="images/savemapicon.gif" align="left" style="margin-right:3px;margin-left:3px"></img>' + resourceAddToAMap.toUpperCase() + '</span></td></tr></table></div></div>';  // overall

        // Add prefix
        description = '(S)' + description;

        var shape = new VEShape(VEShapeType.Pushpin, new VELatLong(latitude, longitude));
        shape.SetTitle("");
        shape.SetDescription('fom||' + index);
        shape.SetCustomIcon("<div class='pin_blue'></div>");
        map.AddShape(shape);

        InfoBoxManager.StoreDescription('fom', index, description);

        this.ZoomToLocation(location, latitude, longitude);

        HideLoading();
    }
    
    /**
     * Function to zoom into latitude and longitude with zoom level based on complexity of name
     *
     * @param name - name of location
     * @param latitude - latitude of location
     * @param longitude - longitude of location
     */
    this.ZoomToLocation=function(name,latitude,longitude)
    {    
        var numSpaces = name.match(/\s/g);
        var zoomFactor = numSpaces!=null ? numSpaces.length : 0;
        var latLon = new VELatLong(latitude, longitude);
        map.SetCenterAndZoom(latLon,12+zoomFactor);
    }
    
    /**
     * Callback function on successful route calls (adds pushpins to map and left pane)
     *
     * @param route (VERoute) - path returned by VE    
     */
    this.onGotRoute = function(route) {
        //Handle route unable to be generated case
        if (route.RouteLegs.length == 0) {
            document.getElementById('ErrHeaderTxt').innerHTML = resourceDDGenerateError;
            document.getElementById('ErrHeaderTxt').style.visibility = "visible";
            document.getElementById('txtFrom').style.border = "1px solid red";
            document.getElementById('txtTo').style.border = "1px solid red";
            HideLoading();

            YPSearchManager.HBXSearch('directions', 0, null, "From " + document.getElementById('txtFrom').value + " To " + document.getElementById('txtTo').value);

            return;
        }
        document.getElementById('ErrHeaderTxt').style.visibility = "hidden";
        //NA document.getElementById('txtFind').style.border = "1px solid black";

        ShowLoading();

        //clear original route pushpins
        mapManager.ClearSearchRelatedShapes();
        // Unroll route
        var legs = route.RouteLegs;
        var numTurns = 0;

        // Leg is a VERouteLeg object
        var leg = null;
        var shape = null;

        var wayPointCount = 0;

        var legsArray = new Array;

        var prevPrevLatLons = legs[0].Itinerary.Items[0].LatLong;
        var prevLatLons = legs[0].Itinerary.Items[0].LatLong;
        var curLatLons = legs[0].Itinerary.Items[0].LatLong;
        var nextLatLons = legs[0].Itinerary.Items[0].LatLong;
        var nextNextLatLons = legs[0].Itinerary.Items[1].LatLong;

        var prevShape = new VEShape(VEShapeType.Pushpin, prevLatLons);
        var curShape;
        var nextShape = new VEShape(VEShapeType.Pushpin, nextLatLons);

        // array to hold ids of turnpoint shapes before saving to client cache
        var shapeIds = new Array();

        var prevPrevText = "";
        var prevText = "";
        var curText = legs[0].Itinerary.Items[0].Text;
        var nextText = legs[0].Itinerary.Items[0].Text;

        var prevStep = resourceStart;
        var curStep = resourceStart;
        var nextStep = "";

        var prevDist = "";
        var curDist = legs[0].Itinerary.Items[0].Distance;
        var nextDist = legs[0].Itinerary.Items[0].Distance;
        var totalDist = 0;

        // elapsed time, in seconds, to travers the step
        var prevTime = "";
        var curTime = legs[0].Itinerary.Items[0].Time;
        var nextTime = legs[0].Itinerary.Items[0].Time;
        var totalTime = 0;

        // Get intermediate legs
        for (var i = 0; i < legs.length; i++) {
            // Get this leg so we don't have to derefernce multiple times
            leg = legs[i];

            curLatLons = nextLatLons;
            curShape = nextShape;

            nextLatLons = nextNextLatLons;
            nextShape = new VEShape(VEShapeType.Pushpin, nextLatLons);

            nextText = leg.Itinerary.Items[1].Text;
            nextStep = resourceStep + " " + (numTurns + 1);
            nextDist = leg.Itinerary.Items[1].Distance;
            nextTime = leg.Itinerary.Items[1].Time;

            // increment nextNextLatLons if there is a point after the next point
            // if there are at least 3 points in the current leg
            if (leg.Itinerary.Items.length >= 3) {
                // set nextNextLatLons to the latLon of the third point
                nextNextLatLons = leg.Itinerary.Items[2].LatLong;
            }
            // if there are 2 points in the current leg
            else if (leg.Itinerary.Items.length == 2) {
                // if this is not the last leg
                if (i < legs.length - 1)
                // set the nextNextLatLons to the first point of the next leg
                    nextNextLatLons = legs[i + 1].Itinerary.Items[0].LatLong;
                else
                    nextStep = resourceFinalDestination;
            }
            // if there is only one step in the current leg it is the first step in the next leg
            else {
                // if this is the last leg
                if (i == (legs.length - 1)) {
                    nextStep = resourceFinalDestination;
                }
                // if this is not the last leg
                else {
                    nextText = legs[i + 1].Itinerary.Items[0].Text;
                    nextStep = resourceStep + " &#" + (i + 66) + ";";
                    // set the nextNextLatLons to the second point of the next leg
                    nextNextLatLons = legs[i + 1].Itinerary.Items[1].LatLong;
                }
            }
            var latLons = curLatLons + "," + prevLatLons;
            var shapeCustomIconImage = "Images/GreyIcons/" + iconArray[incrementWayPointCount(i)] + ".gif";
            var shapeDescriptionTitle = prevText;
            var shapeDescriptionItems = new Array();
            var shapeDescriptionCurrentItemTopRow = "<tr class='DDEroTextCurrentSeperator DDEroTextSeperatorCurrentTop DDEroTextCurrent'><td></td><td></td><td class='popupLink DDEroUpArrow' onclick='mapManager.ShowInfoBoxp;'></td></tr>";
            var wayPointLinks = new Array();
            var waypointType = '(DDI)';

            // WAYPOINT
            shapeDescriptionItems.push("<tr class='DDEroTextSeperator'><td></td><td></td><td></td></tr>" +
                                       "<tr class='DDEroTextPrevious'><td class='DDEroTextStepNum'>" + prevStep + "</td><td class='DDEroTextStepText'>" + prevText + "</td><td class='waypointDescriptionDistance'>" + mapManager.getDistTime(prevDist, prevTime) + "</td></tr>" +
                                       "<tr class='DDEroTextSeperator'><td></td><td></td><td></td></tr>");
            wayPointLinks.push(prevLatLons + "," + prevPrevLatLons + "," + curLatLons + ");'>prev");

            // if this is the first waypoint
            if (i == 0) {
                shapeCustomIconImage = "/images/shared/map/A_Icon.gif";
                mapManager.extractPlaceValues(false, 0);
                latLons = curLatLons;
                shapeDescriptionTitle = resourceStart;
                shapeDescriptionItems.pop();
                wayPointLinks.pop();
                curText = mapManager.extractPlaceValues(false, i);
                shapeDescriptionCurrentItemTopRow = "<tr class='DDEroTextSeperator DDEroTextSeperatorCurrentTop DDEroTextCurrent'><td></td><td></td><td></td></tr>";
                waypointType = '(DDF)';
            }
            shapeDescriptionItems.push(shapeDescriptionCurrentItemTopRow +
                                       "<tr class='DDEroTextCurrent DDEroTextStepText'><td class='DDEroTextStepNum DDEroTextStepNumSelected'>" + curStep + "</td><td class='DDEroTextStepText'>" + curText + "</td><td></td></tr>" +
                                       "<tr class='DDEroTextCurrentSeperator DDEroTextSeperatorCurrentBottom DDEroTextCurrent'><td></td><td></td><td class='popupLink DDEroDownArrow' onclick='mapManager.ShowInfoBoxn;'></td></tr>");
            wayPointLinks.push(curLatLons + "," + prevLatLons + "," + nextLatLons + ");'>zoom in");

            shapeDescriptionItems.push("<tr class='DDEroTextSeperator'><td></td><td></td><td></td></tr>" +
                                       "<tr class='DDEroTextNext'><td class='DDEroTextStepNum'>" + nextStep + "</td><td class='DDEroTextStepText'>" + nextText + "</td><td class='waypointDescriptionDistance'>+" + mapManager.getDistTime(nextDist, nextTime) + "</td></tr>" +
                                       "<tr class='DDEroTextSeperator'><td></td><td></td><td></td></tr>");
            wayPointLinks.push(nextLatLons + "," + prevLatLons + "," + nextNextLatLons + ");'>next");

            latLons += "," + nextLatLons;
            // add all points of the leg into the legs array to be included as driving directions content
            legsArray.push("<table class='directionsList' id='leg_" + i + "_title'><tr><td onclick='mapManager.CenterAndZoom(" + latLons + ")'><div class='drivingDirectionsWaypointIcon drivingDirectionsWaypointListIcon' style='background-image:url(\"" + shapeCustomIconImage + "\")'><b></b></div></td><td style='width:10px'></td><td><div class='drivingDirectionsListDetails'>" + curText + (i != 0 ? "</div><div>" + mapManager.getDistTime(totalDist, totalTime) : '') + "</div></td><td><a id='waypoint_" + i + "_Expand' style='cursor:pointer' onclick='mapManager.changeDisplay(\"leg_" + i + "_table\");'>+</a></td></tr></table><table style='display:block' class='directionsList' id='leg_" + i + "_table'>");
            shape = curShape;
            shape.SetDescription(waypointType + "<table id='turnpoint" + numTurns + "_table' class='DDEroText'>" +
                shapeDescriptionItems.join("") +
                "<tr style='height:14px; background:#66676a'><td></td><td></td><td></td></tr>" +
                "</table>");
            shape.SetCustomIcon("<div class='drivingDirectionsWaypointMapIcon drivingDirectionsWaypointIcon' style='background-image:url(\"" + shapeCustomIconImage + "\")'></div>");
            map.AddShape(shape);
            shapeIds.push(shape.GetID());

            // TURNPOINTS
            for (var k = 1; k < leg.Itinerary.Items.length - 1; k++) {
                numTurns++;
                // update latlons and shapes
                prevPrevLatLons = prevLatLons;
                prevLatLons = curLatLons;
                prevShape = curShape;

                curLatLons = nextLatLons;
                curShape = nextShape;

                nextLatLons = nextNextLatLons;
                nextShape = new VEShape(VEShapeType.Pushpin, nextLatLons);

                // update step texts
                prevStep = curStep;
                curStep = nextStep;
                nextStep = resourceStep + " " + (numTurns + 1);
                // update distances
                prevDist = curDist;
                curDist = nextDist;
                nextDist = leg.Itinerary.Items[k + 1].Distance;
                // update travel times
                prevTime = curTime;
                curTime = nextTime;
                nextTime = leg.Itinerary.Items[k + 1].Time;
                // update texts
                prevText = curText;
                curText = nextText;
                nextText = leg.Itinerary.Items[k + 1].Text;
                // if the next step is the last step in the current leg, but the first step in the next leg
                if ((k + 1) == (leg.Itinerary.Items.length - 1)) {
                    if (i < (legs.length - 1)) {
                        nextText = legs[i + 1].Itinerary.Items[0].Text;
                        nextStep = resourceStep + " &#" + (i + 66) + ";";
                    }
                    else {
                        nextStep = resourceFinalDestination;
                    }
                }
                // increment nextNextLatLons if there is a point after the next point
                // if there are at least k+3 points in the current leg
                if (leg.Itinerary.Items.length >= k + 3)
                // set nextNextLatLons to the latLon of the k+3^th point
                    nextNextLatLons = leg.Itinerary.Items[k + 2].LatLong;
                // if there is only one more point in the current leg
                else {
                    // if this is not the last leg
                    if (i < legs.length - 1)
                    // set the nextNextLatLons to the k+1^th point of the next leg
                        nextNextLatLons = legs[i + 1].Itinerary.Items[1].LatLong;
                }
                shapeDescriptionItems = new Array();
                wayPointLinks = new Array();
                // description
                shapeDescriptionItems.push("<td class='DDEroTextStepNum'>" + prevStep + "</td><td class='DDEroTextStepText'>" + prevText + "</td><td class='waypointDescriptionDistance'>" + mapManager.getDistTime(prevDist, prevTime) + "</td>");
                shapeDescriptionItems.push("<td class='DDEroTextStepNum DDEroTextStepNumSelected'>" + curStep + "</td><td class='DDEroTextStepText'>" + curText + "</td><td></td>");
                shapeDescriptionItems.push("<td class='DDEroTextStepNum'>" + nextStep + "</td><td class='DDEroTextStepText'>" + nextText + "</td><td class='waypointDescriptionDistance'>+" + mapManager.getDistTime(nextDist, nextTime) + "</td>");
                wayPointLinks.push(prevLatLons + "," + prevPrevLatLons + "," + curLatLons + ");'>prev");
                wayPointLinks.push(curLatLons + "," + prevLatLons + "," + nextLatLons + ");'>zoom in");
                wayPointLinks.push(nextLatLons + "," + prevLatLons + "," + nextNextLatLons + ");'>next");
                // side-bar text
                legsArray.push("<tr><td style='width:27px' onclick='mapManager.CenterAndZoom(" + curLatLons + "," + prevLatLons + "," + nextLatLons + ")'><div class='drivingDirectionsTurnIcon drivingDirectionsTurnListIcon' style='background-image:url(\"/images/shared/map/turnpointPushpin.png\")'><div class='drivingDirectionsTurnIconText'>" + numTurns + "</div></div></td><td style='width:10px'></td><td><div class='drivingDirectionsListDetails'><span>" + leg.Itinerary.Items[k].Text + "</span></div></td></tr>");
                // add turnpoint to map
                shape = curShape;
                shape.SetDescription("(DDI)<table id='turnpoint" + numTurns + "_table' class='DDEroText'><tr class='DDEroTextSeperator'><td></td><td></td><td></td></tr><tr class='DDEroTextPrevious'>" + shapeDescriptionItems[0] + "</tr><tr class='DDEroTextSeperator'><td></td><td></td><td></td></tr><tr class='DDEroTextCurrentSeperator DDEroTextSeperatorCurrentTop DDEroTextCurrent'><td></td><td></td><td class='popupLink DDEroUpArrow' onclick='mapManager.ShowInfoBoxp;'></td></tr><tr class='DDEroTextCurrent DDEroTextStepText'>" + shapeDescriptionItems[1] + "</tr><tr class='DDEroTextCurrentSeperator DDEroTextSeperatorCurrentBottom DDEroTextCurrent'><td></td><td></td><td class='popupLink DDEroDownArrow' onclick='mapManager.ShowInfoBoxn;'></td></tr><tr class='DDEroTextSeperator'><td></td><td></td><td></td></tr><tr class='DDEroTextNext'>" + shapeDescriptionItems[2] + "</tr><tr class='DDEroTextSeperator'><td></td><td></td><td></td></tr><tr style='height:14px; background:#66676a'><td></td><td></td><td></td></tr></table>");
                shape.SetCustomIcon("<div class='drivingDirectionsTurnMapIcon drivingDirectionsTurnIcon' style='background-image:url(\"/images/shared/map/turnpointPushpin.png\")'><div class='drivingDirectionsTurnIconText'>" + numTurns + "</div></div>");
                map.AddShape(shape);
                shapeIds.push(shape.GetID());
            }
            // update latlons and shapes
            prevPrevLatLons = prevLatLons;
            prevLatLons = curLatLons;
            prevShape = curShape;
            // update texts
            prevPrevText = prevText;
            prevText = curText;
            curText = nextText;
            // update step texts
            prevStep = curStep;
            curStep = nextStep;

            curDist = nextDist;
            curTime = legs[0].Itinerary.Items[0].Time;

            // update travel time/distance
            totalDist += leg.Distance;
            totalTime += leg.Time;
            // end set of turnpoints
            legsArray.push("</table>");
        }

        // deal with the last waypoint
        curLatLons = nextLatLons;
        curShape = nextShape;
        curText = nextText;
        curStep = nextStep;

        var shapeDescriptionItems = new Array();
        var wayPointLinks = new Array();

        shapeDescriptionItems.push("<td class='DDEroTextStepNum'>" + prevStep + "</td><td class='DDEroTextStepText'>" + prevText + "</td><td class='waypointDescriptionDistance'>" + mapManager.getDistTime(prevDist, prevTime) + "</td>");
        shapeDescriptionItems.push("<td class='DDEroTextStepNum DDEroTextStepNumSelected'>" + resourceFinalDestination + "</td><td class='DDEroTextStepText'>" + curText + "</td><td></td>");

        legsArray.push("<table class='directionsList' id='last_waypoint'><tr><td onclick='mapManager.CenterAndZoom(" + curLatLons + "," + prevLatLons + ")'><div class='drivingDirectionsWaypointIcon drivingDirectionsWaypointListIcon' style='background-image:url(\"/images/shared/map/" + iconArray[legs.length] + ".gif\")'><b></b></div></td><td style='width:10px'></td><td><div class='drivingDirectionsListDetails'>" + mapManager.extractPlaceValues(false, waypointsArray.length - 1) + "</div><div>" + mapManager.getDistTime(totalDist, totalTime) + "</div></td></tr>");

        shape = curShape;
        shape.SetDescription("(DDL)<table id='turnpoint" + numTurns + "_table' class='DDEroText'><tr class='DDEroTextSeperator'><td></td><td></td><td></td></tr><tr class='DDEroTextPrevious'>" + shapeDescriptionItems[0] + "</tr><tr class='DDEroTextSeperator'><td></td><td></td><td></td></tr><tr class='DDEroTextCurrentSeperator DDEroTextSeperatorCurrentTop DDEroTextCurrent'><td></td><td></td><td class='popupLink DDEroUpArrow' onclick='mapManager.ShowInfoBoxp;'></td></tr><tr class='DDEroTextCurrent DDEroTextStepText'>" + shapeDescriptionItems[1] + "</tr><tr class='DDEroTextSeperator DDEroTextSeperatorCurrentBottom DDEroTextCurrent'><td></td><td></td><td></td></tr><tr style='height:14px; background:#66676a'><td></td><td></td><td></td></tr></table>");
        shape.SetCustomIcon("<div class='drivingDirectionsWaypointMapIcon drivingDirectionsWaypointIcon' style='background-image:url(\"/images/shared/map/" + iconArray[legs.length] + ".gif\")'></div>");
        map.AddShape(shape);
        shapeIds.push(shape.GetID());

        ClientCache.Save('pane_' + paneNumber + '_turnpointIds', shapeIds.join('|'));

        // concat all sections together as contents of driving directions div
        document.getElementById("firstResultDiv" + paneNumber).innerHTML = legsArray.join("");

        //if(debug)console.log("Get lat/lon for print link: ", ClientCache.Retrieve('pane_' + paneNumber + '_From'), ClientCache.Retrieve('pane_' + paneNumber + '_To'))
		var fromDDInfoArray = mapManager.extractNameLatLon(0);
		var toDDInfoArray = mapManager.extractNameLatLon(1);
		if(debug)console.log("fromDDInfoArray: %s @ %s,%s", fromDDInfoArray[0], fromDDInfoArray[1], fromDDInfoArray[2]);
		if(debug)console.log("toDDInfoArray: %s @ %s,%s", toDDInfoArray[0], toDDInfoArray[1], toDDInfoArray[2]);

		// Update the print driving directions link
        $('printDDLink').innerHTML = "<a href='" + "/search/print/map.html?fromAddr=" + fromDDInfoArray[0] + "&fromLat=" + fromDDInfoArray[1] + "&fromLon=" + fromDDInfoArray[2] + "&toAddr=" + toDDInfoArray[0] + "&toLat=" + toDDInfoArray[1] + "&toLon=" + toDDInfoArray[2] + "'>" + resourcePrintDrivingDir + "</a>";


        //NA mapManager.resizeLeftDiv();
        mapManager.resizeLeftDD();
        POIManager.RefreshPOIs();

        HideLoading();
    }

    /** 
    * splits specified location into lat/long coord and place name
    *
    * @param getLatLong - whether or not to return lat/long coord
    * @param index - index of location in waypoints array
    *
    * returns - lat/long coord if getLatLong set to true
    *         - place name if getLatLong set to false
    */
    this.extractNameLatLon = function(index) {
        var itemArray = waypointsArray[index].split(';');
        //Return place name, lat, lon
        var name = itemArray[0];
        var latlon = itemArray[1];
        var returnArray = latlon.match(/\((.+)?,(.+)?\)/);
        returnArray.splice(0,1,name);
        return returnArray;
    }
    
    /**
     * sets the zoom level and centre/focus of the map (set includePredAndSuc to true)
     */
    this.CenterAndZoom = function(centerLat, centerLon, secondLat, secondLon, thirdLat, thirdLon) {
        var includePredAndSuc = false;
        var latLon = new VELatLong(centerLat, centerLon);
        map.SetCenterAndZoom(latLon, 15);
        if (includePredAndSuc) {
            if (!(typeof secondLat == "undefined")) {
                latLon = new VELatLong(secondLat, secondLon);
                map.IncludePointInView(latLon);
            }
            if (!(typeof thirdLat == "undefined")) {
                latLon = new VELatLong(thirdLat, thirdLon);
                map.IncludePointInView(latLon);
            }
            if (map.GetZoomLevel() < 18) {
                map.SetCenterAndZoom(latLon, 15);
            }
        }
    }

    /**
     * makes visible the info box of the VEShape with id shapeID
     * 
     */
    this.ShowInfoBox = function(shapeID) {        
        nextEro = new PushpinERO(shapeID, map);
        nextEro.Show();
    }
    
    /**
    * Function to format distance and time for a direction turnpoint or waypoint
    *
    * @param VERoute route  The route returned by VE    
    */
    this.getDistTime = function(dist, time) {
        var dist = Math.round(dist * 10) / 10 + " km";
        var time = "(" + Math.round(time / 60) + " min)";
        return dist+'<div>'+time+'</div>';
    }
    
    //Increment the way point counter. Since we only have 26 letters, once we hit the last letter,
    //always stay at the last letter. Although it's very unlikely the user will add more than 26 way points
    function incrementWayPointCount(wayPointCount)
    {
        if (wayPointCount == 25)
            return wayPointCount;
        else
            return wayPointCount + 1;
    }
    
    this.toggleAddLocation = function(index)
    {
        var addLocationElement = document.getElementById("addDestinationPanel" + index);
        var addLocationArrow = document.getElementById("addLocationArrow" + index);
        if (addLocationElement.style.display == "none")
        {
            addLocationElement.style.display = "block";
            addLocationArrow.src = "Images/downarrow.gif";
        }
        else
        {
           addLocationElement.style.display = "none"; 
           addLocationArrow.src = "Images/rightarrow.gif";
        }
    }
 
    /**
     * Resize the map to the available window area
     *
     */
    this.MapResize = function() {
    	//alert("MapResize");
    	if(debug)console.log("MapResize");
    	
        MapControl.Features.ScaleBarKilometers = true;
        OldMapCenter = map.GetCenter();
        OldMapZoomLevel = map.GetZoomLevel();

        // this.MapResize method is run many times because the window.onresize event fires multiple times
        // this.OnMapResize method is run once as there is only one VE map onresize event fired 
        // the onPanEnd variable is reset to false in this.OnMapResize method
        if (onPanEnd == false) {
            //NA closeMiniDisplay = document.getElementById('CloseMini').style.display;
            //NA openMiniDisplay = document.getElementById('ClosePanel').style.display;
            //NA closePanelDisplay = document.getElementById('OpenMini').style.display;
            onPanEnd = true;
        } 
		
		var toggledMapSearchAttachedPZ = false;
    	if(debug)console.log("In mm.MapResize:  Connected: %s. toggledMapSearchAttachedPZ: %s", mapSearchAttachedPZ, toggledMapSearchAttachedPZ);
	
		// detach onendpan and onendzoom from map search
		if (mapSearchAttachedPZ)
		{
        	if(debug)console.log("In mm.MapResize:  Connected: %s.  Going to disconnect. toggledMapSearchAttachedPZ: %s", mapSearchAttachedPZ, toggledMapSearchAttachedPZ);
            mapManager.Map.DetachEvent('onendpan', mapSearch);
            mapManager.Map.DetachEvent('onendzoom', mapSearch);
            toggledMapSearchAttachedPZ = true;
            mapSearchAttachedPZ = false;
        }

        var mapWidthHeight = mapManager.GetMapWidthHeight();
        var mapWidth = mapWidthHeight[0];
        //UP var mapHeight = mapWidthHeight[1] - (document.getElementById('PanelWhatsNearby').style.display == "none" ? (browserManager.BrowserName == 'msie' ? (0 - 6) : 0) : (browserManager.BrowserName == 'msie' ? 79 : 79));
        var mapHeight = mapWidthHeight[1] - (browserManager.BrowserName == 'msie' ? (0 - 6) : 0);

        //if What's near by is hidden we have some more space left for the map
        map.Resize(parseInt(mapWidth), mapHeight);
	    map.SetCenterAndZoom(OldMapCenter, OldMapZoomLevel);  //TEMP

		// attach onendpan and onendzoom to map search only if detached in this method
		if (toggledMapSearchAttachedPZ)
		{
			// Only toggle back on if this is not the merchant page.
			if(isMerchantPage == false) {
	        	if(debug)console.log("In mm.MapResize:  Connected: %s.  Going to connect. toggledMapSearchAttachedPZ: %s", mapSearchAttachedPZ, toggledMapSearchAttachedPZ);
	            
	        	mapManager.Map.AttachEvent('onendpan', mapSearch);
	            mapManager.Map.AttachEvent('onendzoom', mapSearch);
	            mapSearchAttachedPZ = true;
            } else {
	        	if(debug)console.log("In mm.MapResize:  Connected: %s.  Skipping the reconnect because this is Merchant Page. toggledMapSearchAttachedPZ: %s", mapSearchAttachedPZ, toggledMapSearchAttachedPZ);            
            }
        }

        //Get window height for accordion window resize
        browserManager.GetWindowHeight();
    }

    /**
     * VE map resize handler
     *
     * @param e - Map resize event object
     */
    this.OnMapResize = function(e) {
        //alert("OnMapResize" + e);
    	if(debug)console.log("OnMapResize: " + e);
    	
        //NA map.HideMiniMap();

        setTimeout(function() {
            //NA document.getElementById('OpenMini').style.display = closePanelDisplay;
            //NA document.getElementById('CloseMini').style.display = closeMiniDisplay;
            //NA document.getElementById('ClosePanel').style.display = openMiniDisplay;

            onPanEnd = false;
            //NA document.getElementById('OpenMini').style.left = map.GetLeft() + map.GetWidth() - 105 + "px";
//            document.getElementById('navcontrol').style.top = map.GetTop() + "px";
//            document.getElementById('navcontrol').style.left = map.GetLeft() + 1 + "px";

            //if(debug)console.log("OnMapResize Before: imInfoBar current width: %s and map width: %s", $('imInfoBar').style.width, map.GetWidth());
//            document.getElementById('imInfoBar').style.width = map.GetWidth() - 66 + "px";
            //if(debug)console.log("OnMapResize After: imInfoBar current width: ", $('imInfoBar').style.width);

			// IE needs a delay to see the updated size of the map
			// When switching between expanded and collapsed map states on merchant page, recenter the merchant pin
	        if(isMerchantPage == true) {
	        	if (YPSearchManager.g_FullMPSelectedData != null && YPSearchManager.g_FullMPSelectedData.listing != undefined) {
	                var currentListing = YPSearchManager.g_FullMPSelectedData;
	                map.SetCenter(new VELatLong(currentListing.listing.address.location.latitude, currentListing.listing.address.location.longitude));
	            }
	        }

            if($('yp_DrivingDirections0').style.display == "block")
                mapManager.resizeLeftDD();

            //NA document.getElementById('CloseMini').style.left = map.GetLeft() + map.GetWidth() - 152 + "px";

/* NA
            if (document.getElementById('CloseMini').style.display == "none") {
                if (images == "Images/") {
                    document.getElementById('ClosePanel').style.left = map.GetLeft() + map.GetWidth() - 161 + "px";
                }
                else {
                    document.getElementById('ClosePanel').style.left = map.GetLeft() + map.GetWidth() - 181 + "px";
                }
            }
            else {
                map.ShowMiniMap(map.GetWidth() - 154, 0);
                document.getElementById('ClosePanel').style.left = map.GetLeft() + map.GetWidth() - 209 + "px";
            }

            mapManager.resizeLeftDiv();
            
            document.getElementById('footerdiv').style.top = document.getElementById(mapElement).offsetHeight + 152 - (document.getElementById('PanelWhatsNearby').style.display == "none" ? 78 : 0) + "px";
            document.getElementById('div_traffic_branding').style.top = document.getElementById(mapElement).offsetHeight + 152 - (document.getElementById('PanelWhatsNearby').style.display == "none" ? 78 : 0) + "px";
            document.getElementById('div_traffic_branding').style.left = map.GetWidth() - (browserManager.BrowserName == 'msie' ? 712 : 710) + 'px';
*/
        }, 300);
    }

    /**
    * Adjusts height of left side driving directions div to match map height
    *
    */
    this.resizeLeftDD = function() {
        var mapOffsetHeight = $(mapElement).offsetHeight;
    
        if(debug)console.log("resizeLeftDD: %f", mapOffsetHeight);
        $('yp_DrivingDirections0').style.height = mapOffsetHeight + "px";
    }


    /**
    * Adjusts height of left side div to match map height
    *
    */
    this.resizeLeftDiv = function() {
        if (paneNumber != -1) {
            var numPanes = AjaxControlManager.getNextPaneNumber();
            var headerHeightSum = (browserManager.BrowserName == 'msie' ? 39 : (browserManager.BrowserName == 'safari' ? 17 : 10));
            for (var i = 0; i < numPanes; i++) {
                headerHeightSum += document.getElementById('header' + i).offsetHeight;
            }
            if (numPanes == 1 && browserManager.BrowserName == 'msie')
                headerHeightSum += 15;
            // find a business or person
            if (ClientCache.Retrieve('pane_' + paneNumber + '_type') == 'per' || ClientCache.Retrieve('pane_' + paneNumber + '_type') == 'bus') {
                document.getElementById("content" + paneNumber).style.height = document.getElementById(mapElement).offsetHeight - 15 - (browserManager.BrowserName == 'msie' ? 118 : (browserManager.BrowserName == 'safari' ? 157 : 65)) - headerHeightSum + (document.getElementById('PanelWhatsNearby').style.display == "none" ? 0 : 67) + "px";
            }
            // get driving directions
            else if (ClientCache.Retrieve('pane_' + paneNumber + '_type') == 'dd') {
            document.getElementById("content" + paneNumber).style.height = document.getElementById(mapElement).offsetHeight + 7 - headerHeightSum - (document.getElementById('PanelWhatsNearby').style.display == "none" ? (browserManager.BrowserName == 'msie' ? 120 : 80) : 0) + "px";
            document.getElementById('yp_DrivingDirections'+paneNumber).style.width = '93%';
            }
            // find on a map
            else {
                document.getElementById("yp_FindOnMap" + paneNumber).style.height = document.getElementById(mapElement).offsetHeight + 5 + (browserManager.BrowserName == 'msie' ? 38 : (browserManager.BrowserName == 'safari' ? 16 : 8)) - headerHeightSum - (document.getElementById('PanelWhatsNearby').style.display == "none" ? 80 : 0) + "px";
                document.getElementById("firstResultDiv" + paneNumber).style.width = "100%";
                document.getElementById("firstResultDiv" + paneNumber).style.overflow = "hidden";
            }
        }
    }

    /**
    * VE map pan handler, saves updated map center to client cache so map loaded here on refresh
    *
    * @param e - Map resize event object
    */
    this.updateClientCacheCenter = function(e) {
        var center = map.GetCenter();
        ClientCache.Save('center', center.Latitude + '|' + center.Longitude);
    }

    /**
    * VE map pan handler, saves updated map zoom to client cache so map loaded to this zoom on refresh
    *
    * @param e - Map resize event object
    */
    this.updateClientCacheZoom = function(e) {
        var center = map.GetCenter();
        ClientCache.Save('center', center.Latitude + '|' + center.Longitude);
        ClientCache.Save('zoom', map.GetZoomLevel());
    }

    /**
    * VE map pan handler, turn clustering on/off at a given zoom level
    *
    * @param e - Map resize event object
    */
    this.updateClusterOnOff = function(e) {
        var curZoom = map.GetZoomLevel();
	    if(debug)console.log("updateClusterOnOff: zoom:%d ", curZoom);
        if(curZoom >= clusterOnOffZoomThreshold)
        	clusterManager.ClusterOff(100);
        else
            clusterManager.ClusterOn(100);
    }

    /**
    * VE map pan handler, saves updated map style to client cache so map loaded to this style on refresh
    *
    * @param e - Map resize event object
    */
    this.updateClientCacheStyle = function(e) {
        ClientCache.Save('style', map.GetMapStyle());
    }

    this.GetTrafficToronto = function() {
        map.SetCenterAndZoom(new VELatLong(43.673334930320145, -79.420166015625), 11);
        ToggleTraffic();
        
        if(document.getElementById('PanelWhatsNearby').style.display=="none")
        {
        FindNearbyShow();
        ShowTrafficTab();
        }
    }
    
    /**
     * Determines whether the input string is formatted like a lat/long
     *
     * @param input - String to validate
     */
    this.IsLatLong = function(input)
    {
        var result = false;
        
        if(/^[-]?[\d]{1,3}[\.]?[\d]*[,][\s]?[-]?[\d]{1,3}[\.]?[\d]*$/.test(input))
        {
            var coords = input.replace(/[\s]/g,"").split(',');
            
            if(coords.length == 2)
            {
                var lat = coords[0];
                var lon = coords[1];
                
                if(lat >= -90 && lat <= 90 && lon >= -180 && lon <= 180)
                {
                    result = true;
                }
            }
        }

        return result;
    }
    
    /**
     * Converts a lat/long string or VELatLong object to an array of VEPlaces for Find-type callbacks
     *
     * @param input - lat/long to convert
     */
    this.LatLongToPlaceArray = function(input, placeName) {
        var latLong = null;
        var result = null;

        if (typeof (input) == "string") {
            var coords = input.replace(/[\s]/g, "").split(',');
            latLong = new VELatLong(coords[0], coords[1]);
        }
        else if (typeof (input) == "object") {
            latLong = input;
        }

        if (latLong != null) {
            if (placeName == null) {
                result = new Array(new VEPlace(latLong.toString(), latLong, null, 0, 0, 1));
            }
            else {
                result = new Array(new VEPlace(placeName, latLong, null, 0, 0, 1));
            }
        }

        return result;
    }

	/**
	 * Handles mouseover event to evaluate what to do when hovering over pin.
	 * If cluster or driving related pins then prevent display of default ERO.
	 *
	 * @param e - Event object
	 */	    
	this.mouseoverCB = function(e)
	{
		// if cluster pushpin prevent showing default mouseover ERO
		if (e.elementID != null && map.GetShapeByID(e.elementID) != null) {
			var shape = map.GetShapeByID(e.elementID);
			if(shape._customIcon != undefined) {
				//OLD var curCustomIconClass = shape._customIcon.match(/class=(["'])?(\w+)\1/)[2];
				var curCustomIconClass = shape._customIcon.match(/class=(["'])?([\w\s]*)\1/)[2];

				/* Currently using CSS to adjust x-axis offset of ERO popup -> .customInfoBox-with-leftBeak and .customInfoBox-with-rightBeak.
				   CSS approach does not take into account different pin types.  Below unfinished code can adjust x-axis offset based on type of pin image.
				
				if(debug)console.log("In mouseoverCB: curCustomIconClass: %s", curCustomIconClass);
				// If ERO container div has style rule for "right beak" need to offset ERO more to the right
				// Need to search DOM for div with .customInfoBox-with-rightBeak after VE has finished deciding if the ERO Body should be to the left or the right.
				setTimeout(
					function() {
						if($$('div.customInfoBox-with-rightBeak').length > 0) {
							var myArray = $$('div.customInfoBox-with-rightBeak');
							
							if(debug)console.log("In mouseoverCB delayed check: Found customInfoBox-with-rightBeak: %s", myArray.length);
							
						    //Need different offsets for different pin types 
							if (curCustomIconClass.match(/pin_wf|pin_v_wf)
								myArray[0].setStyle({marginLeft : '20px'});
								
							if (curCustomIconClass.match(/pin_nonad|pin_v_nonad)
								myArray[0].setStyle({marginLeft : '25px'});
						
						}						
					}
				, 300);
				*/
				
				if (curCustomIconClass.match(/^clusterPin|drivingDirectionsTurnMapIcon|drivingDirectionsWaypointMapIcon/i) != null)
					return true; //Cancel default action
				else
					return false;
			}
		} else {
			return false;
		}
	}

	/**
	 * Handles mouseout event to evaluate what to do when mouseout of pin.
	 * Prevent the default VE action of hiding ERO
	 *
	 * @param e - Event object
	 */	
	this.mouseoutCB = function(e)
	{
		// if cluster pushpin prevent showing default mouseover ERO
		if (e.elementID != null && map.GetShapeByID(e.elementID) != null) {
			var shape = map.GetShapeByID(e.elementID);
			if(shape._customIcon != undefined) {
				var curCustomIconClass = shape._customIcon.match(/class=(["'])?([\w\s]*)\1/)[2];
				if (curCustomIconClass.match(/^pin_wf|pin_v_wf|pin_nonad|pin_v_nonad/i) != null)
					return true; //Cancel default action
				else
					return false;
			}
		} else {
			return false;
		}	
	}
}

// Override the Virtual Earth drawing function to use SVG method for any of these rendering engines regardless of browser or version 
if (/(?:Gecko\/|AppleWebKit\/|Opera\/|KHTML)/.test(navigator.userAgent))
{
    Msn.Drawing.Graphic.CreateGraphic = function(f, b) {
        return new Msn.Drawing.SVGGraphic(f, b);
    }
}
