﻿var stores = new EntityDict();
var events = new EntityDict();
var pushPins = new EntityDict();
var searchType = "fs";
var xmlhttp=false;


// Globalize results/ambig container and postback status for callbacks.
var geocodeResults = null;
var ambigTargetDiv = null;
var doPostback = true;
var driveToGeocodeResults = null;

// Required variables for route disambiguation between callback methods.
var geocodeRoute = false;
var routeOriginAddress = null;
var routeOriginLat = null;
var routeOriginLon = null;
var routeOriginDisambiguated = false;
var routeDestinationAddress = null;
var routeDestinationLat = null;
var routeDestinationLon = null;
var routeDestinationDisambiguated = false;
var searchLatitude = null;
var searchLongitude = null;
var searchLocation = null;

var storePageIndex = 1;
var eventPageIndex = 1;
var typeOfSearch = 'fs';
var moreResults = false;
var firstResponse = true;
var dontFire = false;
var directionsAmbigDiv;
var driveTo = true;
var printView = false;
var numberFound = 0;    //will show the number of results (stores or events) returned from web service

var latestRoute = null; //this is set with the route from any drive to/from or find route and is used to add the route to the print map

//geocode the drive to/from address. this needs to be different because the of type
function GeocodeDriveToAmbigResults(where, ambigTarget, driveto)
{
    directionsAmbigDiv = ambigTarget;
    driveTo = driveto;
    
    try{
       
        map.Find(
            null,           // what
            where,          // where
            null,           // find type
            null,           // shape layer
            null,           // start index
            null,           // number of results
            false,          // show results (show pushpins?)
            false,          // create results (create pushpins?)
            false,          // default disambig
            false,          // set best map view?
            onFoundDriveToResultsAmbig  // callback
        );

    }
    catch(error){
        ErrorLog.LogError(1,1,"GeocodeDriveToAmbigResults " + error.message);
        alert("There was an error processing " + address + " : " + error.message);
    }
}

// Callback for geocode, handles ambiguous matches for simple/route geocodes.
function onFoundDriveToResultsAmbig(layer, results, places, hasmore){
    // Results null or empty.
    if ((places == null) || (typeof places == 'undefined') || places.length == 0){
        alert("We're sorry. We don't recognize that as a location. Please change your search and try again.");
        return;
    }

    driveToGeocodeResults = places;
    
    // One result, proceed with find nearby of starbucks locations.
    if (places.length == 1){
        onFoundDriveToResultsHelper(0);
    }
    
    // Ambiguous results found, update panel.
    else{
        // fill ambigs with links to results page.
        var ambigHTML = "Did you mean... <br/><table>";
        
        // TODO: replace inline style with CSS styles.
        var formatString = "<tr><td style='vertical-align:top;'>{0}</td><td><span class='ambigiousLocatorLink'><a href='javascript: onFoundDriveToResultsHelper({1});'>{2}</a></span></td></tr>";
        for (var i = 0; i < places.length; i++){
            ambigHTML += formatString.replace("{0}", i+1).replace("{1}", i).replace("{2}", places[i].Name);
        }
        ambigHTML += "</table>";
        var ambigDiv = document.getElementById(directionsAmbigDiv);
        ambigDiv.innerHTML = ambigHTML;
        ambigDiv.style.display = "block";
    }
        
}


// Callback for user selection/disambiguation of a simple/route address.
function onFoundDriveToResultsHelper(index){
    var dataString;
    
    //show Processing Div
        if(!panningAndZooming)
            document.getElementById("ProcessingDiv").style.display = "block";

        dataString = escape(driveToGeocodeResults[index].Name) + "|" + 
                    driveToGeocodeResults[index].LatLong.Latitude + "|" + 
                    driveToGeocodeResults[index].LatLong.Longitude;
                    
                    
        //I need two pieces of information: driveto/from and if address is to or from
        if(driveTo)
        {
            //if drive to edit is visible....
            if(document.getElementById("DriveToToAddressEdit").style.display != "none")
                SetDisambiguatedDriveToToData(dataString);
            else
                 SetDisambiguatedDriveToFromData(dataString);
        }
        else
        {
            //if drive to edit is visible....
            if(document.getElementById("DriveFromToAddressEdit").style.display != "none")
                SetDisambiguatedDriveFromToData(dataString);
            else
                SetDisambiguatedDriveFromFromData(dataString);
        }
        
          
           //get lat/long and get the route
       var fromfld;
       var tofld;

       if(driveTo)
       {
           fromfld = document.getElementById("DriveToFromDisambigHdn");
           tofld = document.getElementById("DriveToToDisambigHdn");
       }
       else
       {
           fromfld = document.getElementById("DriveFromToDisambigHdn");
           tofld = document.getElementById("DriveFromFromDisambigHdn");
       }
       
       var fromData = fromfld.value.split("|");
       var toData = tofld.value.split("|");
       
       var from = new VELatLong(fromData[1].toString(),fromData[2].toString());
       var to = new VELatLong(toData[1].toString(),toData[2].toString());
       
       //hide the ambiguous list
        var ambigDiv = document.getElementById(directionsAmbigDiv);
        ambigDiv.style.display = "none";
        
        try
        {
            map.GetRoute(from, to, VEDistanceUnit.Miles, VERouteType.Quickest, DriveToProcessResults); 
        }
        catch(e)
        {
           ErrorLog.LogError(1,1,"OnFoundDriveToResultsHelper " + e.message);
        }
        

}


function DriveToProcessResults(route)
{
     latestRoute = route;

     ShowDriveToFromDirections(route);

}

function ShowDriveToFromDirections(route)
{

  var routeinfo = "<div style='margin:5px' class='copytext'><span class='subheader'>Route Summary</span><br/><table cellpadding='0' cellspacing='0'>";
  routeinfo += "<tr><td style='width:35px' valign='top'>From:</td><td valign='top'>" + detailsDriveFrom + "</td></tr>";   //this is defined in store and event details page
  routeinfo += "<tr><td valign='top'>To:</td><td valign='top'>" + detailsDriveTo + "</td></tr></table>";   //this is defined in store and event details page
  routeinfo += "Total distance: ";
  routeinfo += route.Itinerary.Distance + " ";
  routeinfo += route.Itinerary.DistanceUnit + "<br/>";
  
  var steps="<table style='margin:0px' cellpadding='3' cellspacing='0'>";
  var len = route.Itinerary.Segments.length;
  
  var currentBackground = "white";
   
  for(var i = 1; i < len ;i++)
  {
    //the first two "steps" aren't really depicted on the map. they are "start at x" and "depart x"
    //if(i > 1)
    //    steps += (i + 1).toString() + ". ";
    if(currentBackground == "white")
        currentBackground = "#EEEEEE;";
    else
        currentBackground = "white";
        
    //create the route icons    
    if( i == 0)
        steps = steps; //steps +="<tr><td width='10px' style='background-color:" + currentBackground + "'><br /></td><td style='background-color:" + currentBackground + "'>";
    else if( i == 1) //create start flag
        steps +="<tr><td width='10px' style='background-color:" + currentBackground + "'><img src='Images/Pins/pin_start.gif' /></td><td style='background-color:" + currentBackground + "'>";
    else if( i == (len - 1) )  //create end flag
        steps +="<tr><td width='10px' style='background-color:" + currentBackground + "'><img src='Images/Pins/pin_stop.gif' /></td><td style='background-color:" + currentBackground + "'>";
    else
        steps +="<tr><td width='10px' style='background-color:" + currentBackground + "'><img src='http://dev.virtualearth.net/mapcontrol/v6.1/i/bin/6.1.20080306152009.13/pins/RedCircle" + (i - 1) + ".gif'></td><td style='background-color:" + currentBackground + "'>";
    
    //create the route waypoint instruction
    if( i == (len - 1) )    
        steps += "Arrive at " + detailsDriveTo; 
    else
        steps += route.Itinerary.Segments[i].Instruction; 

    if( route.Itinerary.Segments[i].Distance != null)
    {
        steps += " -- (" + route.Itinerary.Segments[i].Distance + ") ";
        steps += route.Itinerary.DistanceUnit;
    }
    
   
    steps +="<br/></td></tr>";
    
  }
  routeinfo += "<br/><span class='subheader'>Driving directions</span><br/>" + steps;
  
  routeinfo += "</table></div>";
      
      var resultsDiv;
      if(driveTo)
        resultsDiv = document.getElementById("DriveToRouteDirectionsDiv");
      else
        resultsDiv = document.getElementById("DriveFromRouteDirectionsDiv");
      resultsDiv.innerHTML = routeinfo;
      resultsDiv.style.display = "block";
      
              
    //hide Processing Div
    document.getElementById("ProcessingDiv").style.display = "none";


}

// Geocodes an address.
function GeocodeHandleAmbigResults(where, type, postback, ambigTarget){

    ambigTargetDiv = ambigTarget;
    searchType = type;
    doPostback = postback;
    typeOfSearch = type;        //initially this is set in the page load of locatorresults.aspx, but if you click a tab and search, it needs to be set here
    searchLocation = where;
    
    try{
       
        map.Find(
            null,           // what
            where,          // where
            null,           // find type
            null,           // shape layer
            null,           // start index
            null,           // number of results
            false,          // show results (show pushpins?)
            false,          // create results (create pushpins?)
            false,          // default disambig
            false,          // set best map view?
            onFoundResultsAmbig  // callback
        );
    }
    catch(error){
        ErrorLog.LogError(1,1,"GeocodeHandleAmbigResults " + e.message);
        alert("There was an error processing " + address + " : " + error.message);
        
        //hide Processing Div
        document.getElementById("ProcessingDiv").style.display = "none";

    }
}

// Callback for geocode, handles ambiguous matches for simple/route geocodes.
function onFoundResultsAmbig(layer, results, places, hasmore){
  
    // Results null or empty.
    if ((places == null) || (typeof places == 'undefined') || places.length == 0){
        alert("We're sorry. We don't recognize that as a location. Please change your search and try again.");
        return;
    }
    
    geocodeResults = places;
    
    // One result, proceed with find nearby of starbucks locations.
    if (places.length == 1){
        onFoundResultsHelper(0);
    }
    
    // Ambiguous results found, update panel.
    else{
        // fill ambigs with links to results page.
        var ambigHTML = "Did you mean... <br/><table>";
        
        // TODO: replace inline style with CSS styles.
        var formatString = "<tr><td style='vertical-align:top;'>{0}</td><td><span class='ambigiousLocatorLink'><a href='javascript: onFoundResultsHelper({1});'>{2}</a></span></td></tr>";
        for (var i = 0; i < places.length; i++){
            ambigHTML += formatString.replace("{0}", i+1).replace("{1}", i).replace("{2}", places[i].Name);
        }
        ambigHTML += "</table>";
        
        var ambigDiv = document.getElementById(ambigTargetDiv);
        ambigDiv.innerHTML = ambigHTML;
        ambigDiv.style.display = "block";
    }
        
}

// Callback for user selection/disambiguation of a simple/route address.
function onFoundResultsHelper(index){ 
    // If we are disambiguating a route, check what we're disambiguating.
    if (geocodeRoute && (!routeOriginDisambiguated || !routeDestinationDisambiguated)){
        // Remember disambiguation for either origin or destination of route.
        if (!routeOriginDisambiguated){
            routeOriginDisambiguated = true;
            routeOriginLatitude = geocodeResults[index].LatLong.Latitude;
            routeOriginLongitude = geocodeResults[index].LatLong.Longitude;
            
        }
        else if (!routeDestinationDisambiguated){
        
            //RW: this is assuming that we're good on the dest. what is happening is that the origin is good, dest is not a place
            //      then, comes back origin is still good, so we must be disambiging the dest, but we're not, we're starting over....
            //      this is setting end == to start because geocoderesults is really the starting location.
            
            routeDestinationDisambiguated = true;
            routeDestinationLatitude = geocodeResults[index].LatLong.Latitude;
            routeDestinationLongitude = geocodeResults[index].LatLong.Longitude;
                                   
        }
    }
    
    // Post back to server only if
    // a. We are on the first/front page and a simple search was disambiguated.
    // b. We are on the first/front page and a route's origin and destination have been disambiguated.
    if (doPostback && (!geocodeRoute || (geocodeRoute && routeDestinationDisambiguated))){
   
        searchLatitude = geocodeResults[index].LatLong.Latitude;
        searchLongitude = geocodeResults[index].LatLong.Longitude;

        var dataString;
        if (searchType == "fs"){
            // address|lat|lon;
            dataString = escape(geocodeResults[index].Name) + "|" + 
                        geocodeResults[index].LatLong.Latitude + "|" + 
                        geocodeResults[index].LatLong.Longitude;
            
            SetDisambiguatedStoreData(dataString);
        }
        else if(searchType == "fe"){
         // address|lat|lon;
            dataString = escape(geocodeResults[index].Name) + "|" + 
                        geocodeResults[index].LatLong.Latitude + "|" + 
                        geocodeResults[index].LatLong.Longitude;
                        
            SetDisambiguatedEventData(dataString);
        }
        else if(searchType == "fr"){
         // origin address|origin lat|origin lon|dest address|dest lat|dest lon
            dataString = escape(routeOriginAddress) + "|" +
                        routeOriginLatitude + "|" +
                        routeOriginLongitude + "|" +
                        escape(routeDestinationAddress) + "|" +
                        routeDestinationLatitude + "|" + 
                        routeDestinationLongitude;
                        
            SetDisambiguatedRouteData(dataString);
        } 
        
        // Perform the actual redirection.
        
        // Modify postback value to post to new page (manual JS way of .NET 2.0 cross-page postback.
        var formActionFormatString = "LocatorResults.aspx?{0}=1";

        document.forms[0].action = formActionFormatString.replace("{0}",searchType);
        
        // Reset view state to avoid error.
        document.forms[0].__VIEWSTATE.name = 'NOVIEWSTATE';
        
        // Re-set filters going to the results page.
        document.forms[0].submit();
    }
    
    // We are not posting back, but rather running a new simple/route search on the page /w AJAX.
    else{
    
        document.getElementById(ambigTargetDiv).style.display = "none";
        var hiddenField;
        
        // We are disambiguating a regular search, not a route.
        if (!geocodeRoute){

            if (searchType == "fs"){
                //set the data to the hidden field
                hiddenField = document.getElementById("StoreDisambigHdn");
                hiddenField.value = geocodeResults[index].Name + "|" + geocodeResults[index].LatLong.Latitude + "|" + geocodeResults[index].LatLong.Longitude;
                ShowStores(geocodeResults[index].Name, geocodeResults[index].LatLong.Latitude, geocodeResults[index].LatLong.Longitude);
            }
            else if (searchType == "fe"){
                hiddenField = document.getElementById("EventDisambigHdn");
                hiddenField.value = geocodeResults[index].Name + "|" + geocodeResults[index].LatLong.Latitude + "|" + geocodeResults[index].LatLong.Longitude;
                ShowStores(geocodeResults[index].Name, geocodeResults[index].LatLong.Latitude, geocodeResults[index].LatLong.Longitude);
                //ShowEvents(geocodeResults[index].Name, geocodeResults[index].LatLong.Latitude, geocodeResults[index].LatLong.Longitude);
            }
        }
        
        // We are disambiguating a route
        else{
            // Route destination not disambiguated, disambiguate it.
            if (!routeDestinationDisambiguated){
                GeocodeHandleAmbigResults(routeDestinationAddress, searchType, doPostback, ambigTargetDiv);
            }
            // Finally generate the disambiguated route.
            else{
            
                    
        //show Processing Div
        if(!panningAndZooming)
            document.getElementById("ProcessingDiv").style.display = "block";

                geocodeRoute = false;
                GeocodeDisambiguatedRoute(
                    routeOriginLatitude,
                    routeOriginLongitude,
                    routeDestinationLatitude,
                    routeDestinationLongitude
                );
            }
        }
    }
}

// Geocodes a route, handles dismabiguation. Original function to call when generating a route.
function GeocodeRouteHandleAmbig(from, to, type, postback, ambigTarget){
    // Set global route variable so callbacks know what's going on.
    routeOriginAddress = from;
    routeDestinationAddress = to;
    geocodeRoute = true;
    searchLocation = from;
    
        
    // Geocode and disambiguate route origin address before generating the route.
    if(routeOriginDisambiguated)
        GeocodeHandleAmbigResults(routeDestinationAddress, type, postback, ambigTarget);
    else
        GeocodeHandleAmbigResults(routeOriginAddress, type, postback, ambigTarget);
}

// Once route disambiguation is finished, this method gets the actual route based on the
// disambiguated addresses (by lat/longs).
function GeocodeDisambiguatedRoute(olat, olon, dlat, dlon){
    routeOriginLat = olat;
    routeOriginLon = olon;
    routeDestinationLat = dlat;
    routeDestinationLon = dlon;
    GeocodeRoute(new VELatLong(olat, olon), new VELatLong(dlat, dlon), searchType);
}



//call this function to geocode a route
function GeocodeRoute(from,to,type)
{
    //clear current results
    CleanSlate(type);
    
    AddRouteGeocode(from,to);
  
}

function AddRouteGeocode(from,to)
{
    try
    {
        map.GetRoute(from, to, VEDistanceUnit.Miles, VERouteType.Quickest, ProcessRouteResults, FailedCallback); 
    }
    catch(e)
    {
       ErrorLog.LogError(1,1,"AddRouteGeocode " + e.message);
    }
    
}


//this just clears all the results from the map and the store and events dictionary objects
function CleanSlate(type)
{
   //clear current results
   events.Clear();
   stores.Clear();
   map.DeleteAllShapeLayers();
  
   searchType = type;
}

function ProcessRouteResults(route)
{
    //check to see if we have a route. crossing oceans won't give an error, but will cause a null route.
    if(route == null)
    {
        alert("Oops. We can't find that route.");
        
        //hide Processing Div
        document.getElementById("ProcessingDiv").style.display = "none";
        
        return;
    }
    latestRoute = route;
    ShowStoresAlongRoute(route);
    ShowDrivingDirections(route);
}
    
    var pinarray = new Array();

function SwapRoutePushpinIcons()
{ 
	//Track current direction number for multiple routes
	for(var i=map._dm.veroutecache.length - 1; i<map._dm.veroutecache.length;i++)
	{
		var shape = new VEShape(VEShapeType.Pushpin,map._dm.veroutecache[i].LatLong);
		shape.SetTitle(map._dm.veroutecache[i].Title);
		shape.SetDescription(map._dm.veroutecache[i].Details);

		//Place start and end flags, otherwise generate customized pins
		if(i == 1)
		{
				shape.SetCustomIcon("<img src='Images/Pins/pin_start.gif'>");
		}
		else if(i == map._dm.veroutecache.length - 1)
		{
				shape.SetCustomIcon("<img src='Images/Pins/pin_stop.gif'>");
		}
		else
		{
				shape.SetCustomIcon("<img src='http://dev.virtualearth.net/mapcontrol/v6.1/i/bin/6.1.20080306152009.13/pins/RedCircle" + (i - 1) + ".gif'>");
		}
		pinarray.push(shape);
	}

}

function ShowDrivingDirections(route)
{

  //get start from route control
  //get finish from route control
  
  var routeinfo = "<div style='margin:5px' class='copytext'><span class='subheader'>Route Summary</span><br/><table cellpadding='0' cellspacing='0'>";
  routeinfo += "<tr><td style='width:35px' valign='top'>From:</td><td valign='top'>" + routeOriginAddress + "</td></tr>";   //this is defined in store and event details page
  routeinfo += "<tr><td valign='top'>To:</td><td valign='top'>" + routeDestinationAddress + "</td></tr></table>";   //this is defined in store and event details page

  routeinfo += "Total distance: ";
  routeinfo += route.Itinerary.Distance+" ";
  routeinfo += route.Itinerary.DistanceUnit+"<br/>";
  
  var steps="<table style='margin:0px' cellpadding='3' cellspacing='0'>";
  var len = route.Itinerary.Segments.length;
  
  var currentBackground = "white";
  
  
  
  for(var i = 1; i < len ;i++)
  {
    //the first two "steps" aren't really depicted on the map. they are "start at x" and "depart x"
    //if(i > 1)
    //    steps += (i + 1).toString() + ". ";
    if(currentBackground == "white")
        currentBackground = "#EEEEEE;";
    else
        currentBackground = "white";
    if( i == 0)
        steps = steps; //steps +="<tr><td width='10px' style='background-color:" + currentBackground + "'><br /></td><td style='background-color:" + currentBackground + "'>";
    else if( i == 1) //create start flag
        steps +="<tr><td width='10px' style='background-color:" + currentBackground + "'><img src='Images/Pins/pin_start.gif' /></td><td style='background-color:" + currentBackground + "'>";
    else if( i == (len - 1) )  //create end flag
        steps +="<tr><td width='10px' style='background-color:" + currentBackground + "'><img src='Images/Pins/pin_stop.gif' /></td><td style='background-color:" + currentBackground + "'>";
    else
        steps +="<tr><td width='10px' style='background-color:" + currentBackground + "'><img src='http://dev.virtualearth.net/mapcontrol/v6.1/i/bin/6.1.20080306152009.13/pins/RedCircle" + (i - 1) + ".gif'></td><td style='background-color:" + currentBackground + "'>";
    if( i == (len - 1) )    
        steps += "Arrive at " + routeDestinationAddress; //+ " -- (";
    else
        steps += route.Itinerary.Segments[i].Instruction; // + " -- (";

    if( route.Itinerary.Segments[i].Distance != null)
    {
        steps += " -- (" + route.Itinerary.Segments[i].Distance + ") ";
        steps += route.Itinerary.DistanceUnit;
    }
    
    steps +="<br/></td></tr>";
    
  }
  routeinfo += "<br/><span class='subheader'>Driving directions</span><br/>" + steps;
  
  routeinfo += "</table></div>";
  
  var resultsDiv = document.getElementById("DrivingDirectionsDiv");
  resultsDiv.innerHTML = routeinfo;
}

function ShowStoresAlongRoute(route)
{
    try
    {
        var from = route.StartLocation;
        var to = route.EndLocation;
        
        var hdnFilter = document.getElementById("RouteFilterHdn");
        var filters = "";
       
        if (hdnFilter != null)
            filters = hdnFilter.value
            
        try
        {           
            if(panningAndZooming)
            {
                var dist = GetSearchDist(this.map.GetMapView());
                var center = this.map.GetCenter();
                
                FindLocations.EntitiesAlongRouteSegment("sbux", from.LatLong.Latitude, from.LatLong.Longitude, to.LatLong.Latitude, to.LatLong.Longitude, center.Latitude, center.Longitude, dist, filters, storePageIndex, GotStoresCallback, FailedCallback);
            }
            else
            {
                FindLocations.EntitiesFromStartFinish("sbux", from.LatLong.Latitude, from.LatLong.Longitude, to.LatLong.Latitude, to.LatLong.Longitude, filters, storePageIndex, GotStoresCallback, FailedCallback);
            }
        }
        catch(e)
        {
           ErrorLog.LogError(1,1,"ShowStoresAlongRoute (calling web service) " + e.message);
        }
    }
    catch(er)
    {
       ErrorLog.LogError(1,1,"ShowStoresAlongRoute (generic try) " + er.message);
    }
    
    
}

function FailedCallback(error)
{
    var stackTrace = error.get_stackTrace();
    var message = error.get_message();
    var statusCode = error.get_statusCode();
    var exceptionType = error.get_exceptionType();
    var timedout = error.get_timedOut();
   
    // Display the error.    
    var RsltElem = 
        "Stack Trace: " +  stackTrace + "<br/>" +
        "Service Error: " + message + "<br/>" +
        "Status Code: " + statusCode + "<br/>" +
        "Exception Type: " + exceptionType + "<br/>" +
        "Timedout: " + timedout;
        
    try
    {
       ErrorLog.LogError(1,1,"FailedCallback " + RsltElem);
    }
    catch(e)
    {
        //can't get to the service
    }

    //hide Processing Div
    document.getElementById("ProcessingDiv").style.display = "none";

}

function ShowStores(address, lat, lon)
{ 
   // TODO: reset distance upon new query, otherwise 1st zoomed in loc will restrict
   // nearby search of new query.

    //show Processing Div
    if(!panningAndZooming)
        document.getElementById("ProcessingDiv").style.display = "block";

    
   var dist = 25;
   
   if(!firstResponse)
        dist = GetSearchDist(this.map.GetMapView());    //do this on zoom and pan, NOT search button click

    
    //RW: added this to allow me to use the lat/lng later if no stores are found
    searchLatitude = lat;
    searchLongitude = lon;
    
    var hdnFilter = document.getElementById("StoreFilterHdn");
    var filters = "";
   
    if (hdnFilter != null)
        filters = hdnFilter.value;

    try
    {   
        FindLocations.EntitiesFromLatLon("sbux", lat, lon, dist, filters, storePageIndex, GotStoresCallback, FailedCallback);
    }
    catch(e)
    {
       ErrorLog.LogError(1,1,"ShowStores " + e.message);
    }
    
    


}

function ShowEvents(addres, lat, lon)
{
   var dist = 25;
      
   if(!firstResponse)
        dist = GetSearchDist(this.map.GetMapView());    //do this on zoom and pan, NOT search button click
        
    var hdnFilter = document.getElementById("EventFilterHdn");
    var filters = "";
   
    if (hdnFilter != null)
        filters = hdnFilter.value
               
    try
    {
        FindLocations.EntitiesFromLatLon("sbuxevents", lat, lon, dist, filters, eventPageIndex, GotEventsCallback, FailedCallback);
    }
    catch(e)
    {
       ErrorLog.LogError(1,1,"ShowEvents " + e.message);
    }
    
}
    
function GotStoresCallback(result, eventArgs)
{
   var data;

   try
   {
        data = eval('(' + result + ')');
        ValidateResponse(data, './Images/icon_sbuxstore.gif', 'stores', "pinStyleStore");
   }
   catch(e)
   {
       if(e.message == "'length' is null or not an object")
       {
            //not necessarily an error. if we didn't trap an error on the server side, then this just means that we didn't get any results
            //so, I need to try sending in the data object and continuing the process. 
            try
            {
                ValidateResponse(data, './Images/icon_sbuxstore.gif', 'stores', "pinStyleStore");
            }
            catch(er)
            {
                ErrorLog.LogError(1,1,"GotStoresCallback inner try/catch " + er.message);
            }
       }
       else
       {
            ErrorLog.LogError(1,1,"GotStoresCallback " + e.message);
       }
   }
}

function GotEventsCallback(result, eventArgs)
{
   var data;
    
   try
   {
        data = eval('(' + result + ')');
        ValidateResponse(data, './Images/icon_sbuxevent.gif', 'events', "pinStyleEvent");

   }
   catch(e)
   {
       ErrorLog.LogError(1,1,"GotEventsCallback " + e.message);
   }
}

function ValidateResponse(data, icon, dictName, iconStyle)
{

    if(data == null)
    {
        //TODO: design proper error handling scheme for client
        ErrorLog.LogError(1,2,"data sent to ValidateResponse is null");
        return;
    }
    
    if(data.error != null)
    {
        ErrorLog.LogError(1,1,"ValidateResponse " + data.error);
        return;
    }
    // Faulty check - cannot check length on results if it has none.
    //if (data.Results != null || data.Results.length > 0)
    if (data.Results != null)
    { 
        try
        {
            numberFound = data.NumberFound;
        }
        catch(e)
        {
            numberFound = 0;
        }
        
        if (numberFound > 0)
        {
            var reduceCount = firstResponse;
            try
            {
                AddPushpins(data.Results, icon, dictName, iconStyle);
            }
            catch(e)
            {
                //this probably isn't an error, but only an empty result set
            }
            
           //now that we have the best map view for this set of stores, we need to reset our result set for this view only
           //this should only happen if we have more than 10 stores in the result set
           //we need to do this here because we don't know the radius of the map until AFTER we add the pushpins, as the map is adjusted to the 
           //best view of those pushpins
           if((numberFound > 10) && (reduceCount))
           {
               reduceCount = false;
               ShowStores(searchLocation, searchLatitude, searchLongitude);
               return;
           }
           
            //this function will create the results and add the correct tab; it relies on the creation of the stores or events dictionary object in the AddPushpins funtion
            try
            {
                AddResultsTab(dictName);
            }
            catch(e)
            {
                ErrorLog.LogError(1,1,"ValidateResponse " + e.message);
            }
            
        }
        else
        { 
            //we only want to run this on the FIRST TIME (on submit, not on panning and zooming)
            if(firstResponse)
            {
               //RW: this is here to center and zoom the map if we don't have any store or event results
               var latlng = new VELatLong(searchLatitude,searchLongitude);
               var zoom = map.GetZoomLevel();
                if(zoom < 3)
                    zoom = 10;
               map.SetCenterAndZoom(latlng,zoom);
           }
           
           //we need to do this to clear our the results tab. if we didn't it would continue to show the last results
           AddResultsTab(dictName);

           if((typeOfSearch == 'fe') && (dictName  == 'events'))
           {
               //this is a search for events, but there arent' any, so we need to clear the events slider
               AddResultsTab(dictName);
           }
       }
    }
    else{
           //TODO: NEED TO MOVE MAP USING THE LAT/LONG FOUND DURING DISAMBIG PROCESS
            var latlng = new VELatLong(searchLatitude,searchLongitude);
            var zoom = map.GetZoomLevel();
            if(zoom < 3)
                zoom = 10;
            map.SetCenterAndZoom(latlng,zoom);
            AddResultsTab(dictName);
    }
    
    //reset firstResponse      
    //if searchtype = fe and dictionary = stores, then events has yet to fire, don't reset this
    if((searchType == 'fe') && (dictName  == 'stores'))
    {
        //firstResponse = true; //we still need to process the events
        ShowEvents('',searchLatitude,searchLongitude);
    }
    else
    {
        firstResponse = false;
                
        //hide Processing Div
        document.getElementById("ProcessingDiv").style.display = "none";
        
        //if this we're looking for events, show them
        if(searchType == 'fe')
            ShowTab('SearchEventsResultsSldr');
        
        //if this is a route, we need to pop those driving directions
        if(searchType == 'fr')
            ShowTab('DrivingDirectionsSldr');

    }
}

function GetSearchDist(mapView)
{
    var rect = mapView;
    var d;
    if ((typeof distCosineLaw != 'undefined') && (distCosineLaw != null))
    {
        // find 1/2 the width of the current zoom
        try
        {
            d = Math.min(250, Math.ceil(distCosineLaw(rect.TopLeftLatLong.Latitude, rect.TopLeftLatLong.Longitude, rect.BottomRightLatLong.Latitude, rect.BottomRightLatLong.Longitude) * .5));
        }
        catch(e)
        {
           ErrorLog.LogError(2,1,"GetSearchDist " + e.message);
        }
        
    }
    else
    {
        d = 1;
    }
    
    return d;
}



function CreateStoreInfobox(location, iconPath, dictName, iconStyle)
{
    var pinDetails;
    try
    {
        pinDetails = "<div style='text-align:left;'><span>" + location.Entity.Properties[1].Value.toString().replace("'","`") + "</span><br />";
        pinDetails += "<span>" + location.Entity.Properties[2].Value.toString().replace("'","`") + ", " + location.Entity.Properties[3].Value.toString() + " " + location.Entity.Properties[4].Value.toString() + "</span><br />";
        pinDetails += "<span>" + location.Entity.Properties[6].Value.toString() + "</span></div>";
                   
        pinDetails += "<div style='position:relative;background-color:#d9e8e1;height:42px;text-align:left;left:-11px;bottom:-10px;width:246px;'><div style='margin-left:10px;margin-top:10px;'>";
        pinDetails += "<span><a style='color:#036635;text-decoration:none' href='Javascript:DriveTo(&quot;" + location.Entity.ID.toString() + "&quot;,&quot;stores&quot;)'>Drive to</a>&nbsp;|&nbsp;<a style='color:#036635;text-decoration:none' href='Javascript:DriveFrom(&quot;" + location.Entity.ID.toString() + "&quot;,&quot;stores&quot;)'>Drive from</a></span><br />"; 
        pinDetails += "<span onclick='ShowSendToMobilePopup(this, &quot;" + location.Entity.Properties[0].Value.toString().replace("'","`") + "&quot;, &quot;" + location.Entity.Properties[1].Value.toString().replace("'","`") + "&quot;, &quot;" + location.Entity.Properties[2].Value.toString().replace("'","`") + ", " + location.Entity.Properties[3].Value.toString() + " " + location.Entity.Properties[4].Value.toString() + "&quot;, &quot;" + location.Entity.Properties[6].Value.toString() + "&quot;, &quot;" + location.Entity.Properties[5].Value.toString() + "&quot;);'><a style='color:#036635;text-decoration:none' href='javascript:;'>Send to mobile</a></span>"; 
        pinDetails += "&nbsp;|&nbsp;<a href='Javascript:InvitePopUp(&quot;" + location.Entity.ID.toString() + "&quot;,false)' style='color:#036635;text-decoration:none'>Invite a friend</span><br />";
        pinDetails += "</div></div>";
        
        //more details link
        var mapcoord = GetUserSearchCriteria() + "|" + map.GetCenter().Latitude + "|" + map.GetCenter().Longitude + "|" + map.GetZoomLevel();
        //if find route, we need to add the to and from coords to the mapcoord
        if(searchType == "fr")
        {
            mapcoord = mapcoord + "|" + routeOriginLat + "|" + routeOriginLon + "|" + routeDestinationLat + "|" + routeDestinationLon; //
        }
        pinDetails += "<br /><br /><div style='text-align:left;'><span><a style='color:#036635;text-decoration:none' href='Javascript:GoToDetails(&quot;storedetails.aspx?sid=" + location.Entity.ID.toString() + "&quot;,&quot;" + searchType + "&quot;)'>More details...</a></span></div>"; 
        //Javascript:GoToDetails(&quot;" + detailsPage + "?sid=" + location.Entity.ID.toString() + "&quot;,&quot;" + searchType + "&quot;)
    }
    catch(e)
    {
       ErrorLog.LogError(2,1,"CreateStoreInfobox " + e.message);
    }

    return pinDetails;
}


function CreateEventInfobox(location, iconPath, dictName, iconStyle)
{
    var pinDetails;
    try
    {
        pinDetails = "<div style='text-align:left;'><span>" + location.Entity.Properties[1].Value.toString().replace("'","`") + "</span><br />";
        pinDetails += "<span>" + location.Entity.Properties[2].Value.toString() + ", " + location.Entity.Properties[3].Value.toString() + " " + location.Entity.Properties[4].Value.toString() + "</span><br />";
        pinDetails += "<span>" + location.Entity.Properties[6].Value.toString() + "</span><br /><br />";

        pinDetails += "</div>";
                             
        pinDetails += "<div style='position:relative;background-color:#fae9d9;height:42px;text-align:left;left:-11px;bottom:-10px;width:246px;font-size:11px;'><div style='margin-left:10px;margin-top:10px;'>";
        pinDetails += "<span><a style='color:#dd6e00;text-decoration:none' href='Javascript:DriveTo(&quot;" + location.Entity.ID.toString() + "&quot;,&quot;events&quot;)'>Drive to event</a>&nbsp;|&nbsp;<a style='color:#dd6e00;text-decoration:none' href='Javascript:DriveFrom(&quot;" + location.Entity.ID.toString() + "&quot;,&quot;events&quot;)'>Drive from event</a></span><br />"; 
        //pinDetails += "<span><a style='color:#dd6e00;text-decoration:none' href='Javascript:ShowSendToMobilePopup(this, &quot;" + location.Entity.Properties[0].Value.toString() + "&quot;, &quot;" + location.Entity.Properties[1].Value.toString() + "&quot;, &quot;" + location.Entity.Properties[2].Value.toString() + ", " + location.Entity.Properties[3].Value.toString() + " " + location.Entity.Properties[4].Value.toString() + "&quot;, &quot;" + location.Entity.Properties[6].Value.toString() + "&quot;, &quot;" + location.Entity.Properties[5].Value.toString() + "&quot;);'>Send to mobile</a></span>&nbsp;|&nbsp;"; 
        pinDetails += "<a style='color:#dd6e00;text-decoration:none;font-size:11px;' href='Javascript:InvitePopUp(&quot;" + location.Entity.ID.toString() + "&quot;,true)'>Invite a friend</a><br />";
        pinDetails += "</div></div>";
        //more details link
        pinDetails += "<br /><br /><div style='text-align:left;'><span><a style='color:#dd6e00;text-decoration:none' href='Javascript:GoToDetails(&quot;eventdetails.aspx?sid=" + location.Entity.ID.toString() + "&quot;,&quot;" + searchType + "&quot;)'>More details...</a></span></div>"; 
    }
    catch(e)
    {
       ErrorLog.LogError(2,1,"CreateEventInfobox " + e.message);
    }
            
    return pinDetails;
}


function AddPushpins(results, iconPath, dictName, iconStyle)
{
    if (iconStyle == null)
    {
        iconStyle = 'pinStyleStore';
    }
    
    var bestMapViewArray = new Array();
    var iconNumberModifier = (storePageIndex * 10) - 10;
    var detailsPage = "storedetails.aspx";
    
    //clear the map - added to prevent odd results when less than ten result are returned
    //in the second pass -AW
    events.Clear();
    stores.Clear();
    map.DeleteAllShapeLayers();
    
    for(var i=0; i < results.length; i++)
    {
        var location = results[i].FoundLocation;
        var titleColor = "#036635";
                       

            var infobox = "";
            
            if(dictName == "stores")
            {
                infobox = CreateStoreInfobox(location, iconPath, dictName, iconStyle);
                titleColor = "#036635";
                iconNumberModifier = (storePageIndex * 10) - 10;
                iconStyle = "pinStyleStore";
                detailsPage = "storedetails.aspx";
            }    
            
            if(dictName == "events")
            {
                infobox = CreateEventInfobox(location, iconPath, dictName, iconStyle);
                titleColor = "#dd6e00";
                iconNumberModifier = (eventPageIndex * 10) - 10;
                iconStyle = "pinStyleEvent";
                detailsPage = "eventdetails.aspx";
            }    
            
            if(location.Entity.Properties.length > 12)
            {
                
                if (location.Entity.Properties[12].Value.toString() == "YES")
                    iconStyle = "pinStyleComingSoon";
            }
        try
        { 
            
            var shape = new VEShape(VEShapeType.Pushpin,new VELatLong(location.LatLong.Latitude, location.LatLong.Longitude)); 
            map.AddShape(shape);
            
            shape.SetCustomIcon("<div class='" + iconStyle + "' ><div class='text'>" + ((i + 1) + iconNumberModifier).toString() + "</div></div>"); 
            
             //wrap title with link to more details
            var mapcoord = GetUserSearchCriteria() + "|" + map.GetCenter().Latitude + "|" + map.GetCenter().Longitude + "|" + map.GetZoomLevel();
            var title = "<span><a class='subheader' style='color:" + titleColor + ";text-decoration:none' href='Javascript:GoToDetails(&quot;" + detailsPage + "?sid=" + location.Entity.ID.toString() + "&quot;,&quot;" + searchType + "&quot;)'>" + location.Entity.Properties[0].Value.toString().replace("'","`") + "</a></span>"; 
                       
            shape.SetTitle("<div class='subheader' style='color:" + titleColor + ";text-align:left;'>" + title + "</div>");
            shape.SetDescription(infobox);
        
            bestMapViewArray.push(new VELatLong(results[i].FoundLocation.LatLong.Latitude, results[i].FoundLocation.LatLong.Longitude));
            
            //create dictionary object of pushpin IDs. We'll use this when we create the results.
            pushPins.Add(location.Entity.ID,shape.GetID());

            if (dictName == "events")
            {
                events.Add(location.Entity.ID, location);
            }
            else
            {
                stores.Add(location.Entity.ID, location);
            }
        }
        catch (e) 
        {
            ErrorLog.LogError(2,1,"AddPushpins " + e.message);
        }        
    }
    try{
        if((firstResponse == true) && (searchType != 'fr'))
        {
            map.SetMapView(bestMapViewArray);
            //check zoom, if too close, back away
                //this should only fire if user clicked the search button.
                if(map.GetZoomLevel() > 17)
                    map.SetZoomLevel(12);
                    
        }
        firstResponse = false;
    }
    catch(error)
    {
       ErrorLog.LogError(2,1,"AddPushpins " + error.message);
    }
} 

function GoToDetails(url,stype)
{
    var mapcoord = GetUserSearchCriteria() + "|" + map.GetCenter().Latitude + "|" + map.GetCenter().Longitude + "|" + map.GetZoomLevel();

    location.href = url + "&coords=" + mapcoord + "&" + stype + "=1";
}

//get the criteria that the user typed into the location box. 
function GetUserSearchCriteria()
{
    var criteria = "";
    
    if(searchLocation == null)
    {
        if(IsTabVisible("SearchStoreAgainSldr"))
            criteria = document.getElementById("ctl00_MainContent_FindStoreCtl_StoreLocationTxt").value;
        if(IsTabVisible("SearchEventsAgainSldr"))
            criteria = document.getElementById("ctl00_MainContent_FindEventCtl_EventLocationTxt").value;
        if(IsTabVisible("SearchRouteAgainSldr"))
            criteria = document.getElementById("ctl00_MainContent_FindRouteCtl_FromTxt").value;
    }
    else
    {
        criteria = searchLocation;
    }

    return criteria;    
}


function AddResultsTab(dictName)
{
    var resDic;
    var resultsHtml = "<div id='resultsparentdiv' style='position:relative;width:100%;'><p class='copytext' style='margin:5px;'>No stores found. Try zooming or panning the map to find stores in the area. If you checked any boxes to limit your search, you might try unchecking them.</p>";
    var resultsDiv = document.getElementById("StoreResultsDiv");
    var iconStyle = "pinStyleStoreResults";
    var toggleIconStyle = "pinStyleStore";
    var iconNumberModifier = storePageIndex;
    var titleClass = "storeSubhead";
    var detailsPath = "storedetails.aspx";
    var resColor = "#036635";

    if (dictName == "stores")
    {
        iconStyle = "pinStyleStoreResults";
        toggleIconStyle = "pinStyleStore";
        resDic = stores;
        resultsDiv = document.getElementById("StoreResultsDiv");
        iconNumberModifier = (storePageIndex * 10) - 10;
        titleClass = "storeSubhead";
        detailsPath = "storedetails.aspx";
        resColor = "#036635";
    }
    else
    {
        iconStyle = "pinStyleEventResults";
        toggleIconStyle = "pinStyleEvent";
        resDic = events;
        resultsDiv = document.getElementById("EventResultsDiv");
        iconNumberModifier = (eventPageIndex * 10) - 10;
        resultsHtml = "<div id='resultsparentdiv' style='position:relative;width:100%;'><p class='copytext' style='margin:5px;'>Oops! There are no events scheduled here at this time. Try zooming or panning the map to find events in the area, or if you filtered by dates or event types, you might try changing your search criteria and trying again.</p>";
        titleClass = "eventSubhead";
        detailsPath = "eventdetails.aspx";
        resColor = "#dd6e00";
    }
    
              
    if(resDic.Count() > 0)
    {
        try
        {
            resultsHtml = "<div id='resultsparentdiv' style='position:relative;width:100%;'>";
            
            var next = ">>";
            var prev = "<<";
            var funcName = "ShowNewStorePage";
            var countDesc = "";
            
            //create paging header
            if(dictName == "stores")
            {
                if(typeOfSearch == 'fr')
                    funcName = "ShowNewStoresAlongRoutePage";
                
                if(storePageIndex > 1)
                    prev = "<a href='Javascript:" + funcName + "(-1);'><<</a>";
                
                if(resDic.Count() > 9)
                    next = "<a href='Javascript:" + funcName + "(1);'>>></a>";
                    
                //create count dialog
                countDesc = "Showing " + (iconNumberModifier + 1) + " - " + (resDic.Count() + (iconNumberModifier));
            }
            else
            {
                 if(eventPageIndex > 1)
                    prev = "<a href='Javascript:ShowNewEventPage(-1);'><<</a>";
                
                if(resDic.Count() > 9)
                    next = "<a href='Javascript:ShowNewEventPage(1);'>>></a>";
                    
                //create count dialog
                countDesc = "Showing " + (iconNumberModifier + 1) + " - " + (resDic.Count() + (iconNumberModifier));
            }
            
            
            //add results controls
            if((!printView) && ((prev != "previous") || (next != "next")))
                resultsHtml += "<div id='resultsControlsDiv' style='position:relative;width:100%;border-bottom:solid 1px #A9A9A9;'><table width='100%' class='copytext'><tr><td width='2px'><br /></td><td align='left'>" + prev + "&nbsp;&nbsp;" + countDesc + " of " + numberFound + "&nbsp;&nbsp;" + next + "</td></tr></table></div>";
                
                //now add div containing results table
            if(printView ==  true)
                resultsHtml += "<div id='resultsdiv' style='position:relative;width:100%;'><table style='width:100%;' cellpadding='0' cellspacing='0'>";
            else    
                resultsHtml += "<div id='resultsdiv' style='overflow:auto;position:relative'><table style='width:188px;' cellpadding='0' cellspacing='0'>";
                
            /*
                ENTITY PROPERTY MAP
                0 BIZ_NAME = name of store
                1 AddressLine = address
                2 PrimaryCity = City
                3 Subdivision = state
                4 PostalCode = zip
                5 CountryRegion = country
                6 PHONE = phone
                7 SecondaryCity = ??
                8 AIRPORT = Yes/No
                9 STORE_NO = store number
                10 KEYWORDS = ??
                11 RETAIL = ??
                12 COMING = coming soon (yes/no)
                13 NEW = new store (yes/no)
                14 OCS = ??
                15 EXPRESS = ?? (yes/no)
                16 UCO = Urban Coffee Opp (yes/no)
                17 LUNCH = lunch (yes/no)
                18 WIRELESS = wireless (yes/no)
                19 STARBUCKSCARD = yes/no
                20 DRIVETHRU = yes/no
                AddressLine2 = address line 2
                WOS = ??
                
                
            */
            for(var i = 0; i < resDic.Count(); i++)
            {
                if(printView)
                {
                    //we need to surpress the popups
                    resultsHtml += "<tr><td colspan='3' style='height:5px'>&nbsp;</td></tr>";
                    resultsHtml += "<tr><td width='8px'>&nbsp;</td><td valign='top' align='left'><div>";
                    resultsHtml += "<div class='" + iconStyle + "'><div class='text'>" + ((i + 1) + iconNumberModifier).toString() + "</div></div></div></td><td valign='top'><span>" + resDic.GetValue(i).Entity.Properties[0].Value.toString().replace("'","`") + "</span><br />";
                    resultsHtml += "<span>" + resDic.GetValue(i).Entity.Properties[1].Value.toString().replace("'","`") + "</span><br />";
                    resultsHtml += "<span>" + resDic.GetValue(i).Entity.Properties[2].Value.toString() + ", " + resDic.GetValue(i).Entity.Properties[3].Value.toString() + " " + resDic.GetValue(i).Entity.Properties[4].Value.toString() + "</span><br />";
                    resultsHtml += "<span'>" + resDic.GetValue(i).Entity.Properties[6].Value.toString() + "</span>";
                    resultsHtml += "</td></tr><tr><td colspan='3' style='height:5px;border-bottom:solid 1px #A9A9A9;width:190px'>&nbsp;</td></tr>"; 
                }
                else
                {
                    var pushpinid = pushPins.Get(resDic.GetValue(i).Entity.ID);
                    
                    var resClass = "text";
                    var iStyle = iconStyle;
                    var tglIconStyle = toggleIconStyle;
                    var resTitleClass = titleClass;
                    
                    
                    if (resDic.GetValue(i).Entity.Properties[12].Value.toString() == "YES")
                    {
                        //this is a coming soon store, mark as such
                        iStyle = "pinStyleComingSoonResults";
                        tglIconStyle = "pinStyleComingSoon";
                        resClass = "comingSoonText";
                        resTitleClass = "comingSoonText";
                        resColor = "#7F7F7F";
                        
                    }

                    //get the map center coords and zoom to send to details page. these will be sent back on click of Back To Search Results
                    var mapcoord = GetUserSearchCriteria() + "|" + map.GetCenter().Latitude + "|" + map.GetCenter().Longitude + "|" + map.GetZoomLevel();

                    if(searchType == "fr")
                    {
                        mapcoord = GetUserSearchCriteria() + "|" + map.GetCenter().Latitude + "|" + map.GetCenter().Longitude + "|" + map.GetZoomLevel() + "|" + routeOriginLat + "|" + routeOriginLon + "|" + routeDestinationLat + "|" + routeDestinationLon; //
                    }

                    resultsHtml += "<tr><td colspan='3' style='height:5px'>&nbsp;</td></tr>";
                    resultsHtml += "<tr><td width='8px'>&nbsp;</td><td valign='top'><div onmouseover='ToggleIcons(event,\"" + pushpinid + "\",1,\"" + ((i + 1) + iconNumberModifier).toString() + "\",\"" + tglIconStyle + "\",\"resultsPin" + resDic.GetValue(i).Entity.ID + "\")'  onmouseout='ToggleIcons(event,\"" + pushpinid + "\",0,\"" + ((i + 1) + iconNumberModifier).toString() + "\",\"" + tglIconStyle + "\",\"resultsPin" + resDic.GetValue(i).Entity.ID + "\")'>";
                    resultsHtml += "<div id='resultsPin" + resDic.GetValue(i).Entity.ID + "' class='" + iStyle + "'><div class='text'>" + ((i + 1) + iconNumberModifier).toString() + "</div></div></div></td><td valign='top'><span onmouseover='ToggleIcons(event,\"" + pushpinid + "\",1,\"" + ((i + 1) + iconNumberModifier).toString() + "\",\"" + tglIconStyle + "\",\"resultsPin" + resDic.GetValue(i).Entity.ID + "\")'  onmouseout='ToggleIcons(event,\"" + pushpinid + "\",0,\"" + ((i + 1) + iconNumberModifier).toString() + "\",\"" + tglIconStyle + "\",\"resultsPin" + resDic.GetValue(i).Entity.ID + "\")'><span class='" + resTitleClass + "'><a class='" + resTitleClass + "' style='text-decoration:none;color:" + resColor + "' href='" + detailsPath + "?sid=" + resDic.GetValue(i).Entity.ID.toString() + "&coords=" + mapcoord + "&" + searchType + "=1'>" + resDic.GetValue(i).Entity.Properties[0].Value.toString().replace("'","`") + "</a></span></span><br />";
                    resultsHtml += "<span class='" + resClass + "'>" + resDic.GetValue(i).Entity.Properties[1].Value.toString().replace("'","`") + "</span><br />";
                    resultsHtml += "<span class='" + resClass + "'>" + resDic.GetValue(i).Entity.Properties[2].Value.toString() + ", " + resDic.GetValue(i).Entity.Properties[3].Value.toString() + " " + resDic.GetValue(i).Entity.Properties[4].Value.toString() + "</span><br />";
                    //phone number, show "coming soon" instead if appropriate.
                    if (resDic.GetValue(i).Entity.Properties[12].Value.toString() == "YES")
                        resultsHtml += "<span class='" + resClass + "'>coming soon</span>";
                    else
                        resultsHtml += "<span class='" + resClass + "'>" + resDic.GetValue(i).Entity.Properties[6].Value.toString() + "</span>";
                        
                    //distance
                    //resultsHtml += "<span class='" + resClass + "'>" + CalculateDistance(resDic.GetValue(i).LatLong.Latitude,resDic.GetValue(i).LatLong.Longitude,"M") + "</span>";

                    resultsHtml += "</td></tr><tr><td colspan='3' style='height:5px;border-bottom:solid 1px #A9A9A9;width:190px'>&nbsp;</td></tr>"; 
               }
            }
            resultsHtml += "</table></div>";
            }
            catch(e)
            {
               ErrorLog.LogError(1,1,"AddResultsTab: " + e.message);
            }
        }
        //close parent div
        resultsHtml += "</div>"
        resultsDiv.innerHTML = resultsHtml;
        
   
    //now show the results tab
    if(searchType == "fe")
        ShowTab("SearchEventsResultsSldr");
    else
        ShowTab("SearchResultsSldr");
        
}


function BringResultInFocus(state, id, type)
{

    if(type == "stores")
        ShowTab("SearchResultsSldr");
    else
        ShowTab("SearchEventsResultsSldr");

    if(document.getElementById("resultsPin" + id).focus())
        document.getElementById("resultsPin" + id).focus();
    else
        document.getElementById("resultsPin" + id).scrollIntoView(true)
        
    //call show popup
     var shapeid = pushPins.Get(id);
     ShowInfoBox(null,shapeid);
    
    return;

    //check for mozilla
    if(document.getElementById("resultsPin" + id).scrollIntoView(true))
        document.getElementById("resultsPin" + id).scrollIntoView(true)
    else
        document.getElementById("resultsPin" + id).focus();
    
    //toggle the icons based on state
    //ToggleIcons(null,shapeid,state,iconNumber,iconStyle,resultsPinID);
}

function TurnOffAllIcons(shapeid, keepActive)
{
    //first, make sure that all of the other icons have successfully toggled back to their start state. we tend to lose the 
    //onmouseout event from the pushpins, so hovering over those icons will leave the icons toggled.
    try
    {   var style = "";
        var oldShape = null;

        for(pinIndex = 0; pinIndex < pushPins.Count(); pinIndex++)
        {
            var elementID = pushPins.GetValue(pinIndex);

            if(keepActive)
            {
               if(shapeid == elementID)
                  continue;   //we don't want to process the active pushpin
            }
               
            var shape = map.GetShapeByID(elementID);
            if(shape == null)
               continue;
               
            var icon = shape.GetCustomIcon();   //this is all of the HTML that comprises the icon, including mouseevents, etc..
            icon = icon.replace('StoreOn','Store');
            icon = icon.replace('EventOn','Event');
            icon = icon.replace('ComingSoonOn','ComingSoon');
           
            shape.SetCustomIcon(icon);
            
           //get the id for the location object and use that to get the id for the icon in the slider
           var locID;
           for(i = 0; i < pushPins.Count(); i++)
           {
                if(elementID.indexOf(pushPins.GetValue(i)) > -1)
                {
                    locID = pushPins.GetKey(i);
                    break;
                }
           }
           
            var ele = document.getElementById("resultsPin" + locID);
            var eleClass = ele.className;
            eleClass = eleClass.replace("ResultsOn","Results");
            ele.className = eleClass;
            
            //toggledIcons.Remove(elementID);
            
            
        }
    }
    catch(e)
    {
        if(e.message != "'null' is null or not an object")
        {
            if(e.message == "shape has no properties")
               ErrorLog.LogError(2,1,"TurnOffAllIcons " + e.message);
            else
               ErrorLog.LogError(1,1,"TurnOffAllIcons " + e.message);
        }
    }
}

//sets pushpins to on state or off state
function ToggleIcons(e,shapeid,state,iconNumber,iconStyle,resultsPinID)
{
    
    try
    {
        
        var shape = map.GetShapeByID(shapeid);
        
        if(state == 1)  //toggle on
        {
            TurnOffAllIcons(shapeid, true);  //turn off all icons, except for the active icon
            
            var icon = shape.GetCustomIcon();
            if(icon.indexOf(iconStyle + "On") > 1)   //if this is getting called before mouseout, which has happened, then bail otherwise our classes get funky.
                return;
                
            icon = icon.replace(iconStyle, iconStyle + "On");
            shape.SetCustomIcon(icon);

            //shape.SetCustomIcon("<div class='" + iconStyle + "On'><div style='text-decoration:none;'  class='text'>" + iconNumber + "</div></div>"); 
            var ele = document.getElementById(resultsPinID);
            ele.className = iconStyle + "ResultsOn";
            
            //RW: we need to call HideInfoBox first or else VE gets confused and forgets to move the popup box.
            map.HideInfoBox();
            
            ShowInfoBox(e,shapeid);
        }
       else            //toggle off
        {
            TurnOffAllIcons(shapeid, false);  //turn off all icons
            
            //class coming in with "On" appended
            var sicon = shape.GetCustomIcon();
            sicon = sicon.replace(iconStyle + "On", iconStyle);
            //icon = icon.replace("EventOn", "Event");
            shape.SetCustomIcon(sicon);
            //shape.SetCustomIcon("<div class='" + iconStyle + "'><div style='text-decoration:none;' class='text'>" + iconNumber + "</div></div>"); 
            var ele = document.getElementById(resultsPinID);
            ele.className = iconStyle + "Results";
            //RW: this is a test
            //HideInfoBox(e,shapeid);
        }
    }
    catch(e)
    {
       ErrorLog.LogError(2,1,"ToggleIcons " + e.message);
    }
}

//hides the info box related to the result
function HideInfoBox(e, shapeid)
{
    map.HideInfoBox();
  
}

var CustomInfoBoxLeftRule = null;
var CustomInfoBoxRightRule = null;

//shows the info box related to result
function ShowInfoBox(e,shapeid)
{
    var shape = map.GetShapeByID(shapeid);
    
    try
    {
        map.ShowInfoBox(shape);
    }
    catch(e)
    {
       ErrorLog.LogError(2,1,"HideInfoBox " + e.message);
    }
    
    
}

//this is called to show the map on store or event details page. type = s for store, e for event
function ShowSingleItem(lat, lng, type, itemName)
{
    var latlng = new VELatLong(lat * 1, lng * 1);
    
    map.LoadMap(
        latlng,        //lat/long of the store or event
        16,                          //zoom level 4
        "r",                        //r = road, a = aerial, h = hybrid, o = oblique (bird's eye)
        false,                      //fixed. if true, user cannot pan and zoom
        VEMapMode.Mode2D,           //map mode for 3D or 2D
        true                       //bool to show the map mode switch
        );

    CreateSinglePin(latlng, type, itemName);

}


function mousemove(e) {
	if (ns4) {var mouseX=e.pageX; var mouseY=e.pageY}
	if (ie4) {var mouseX=event.x; var mouseY=event.y}
	status="x= "+mouseX+", y= "+mouseY;
}


function CreateSinglePin(latlng, type, itemName)
{
    var iconStyle;
    var pinShape;
    
    if(type == 's')
        iconStyle = 'pinStyleStore';
    else
        iconStyle = 'pinStyleEvent';    

    
    var bestMapViewArray = new Array();
    
    try
    {                   
    
        pinShape = new VEShape(VEShapeType.Pushpin,new VELatLong(latlng.Latitude,latlng.Longitude)); 
        pinShape.SetCustomIcon("<div class='" + iconStyle + "'></div>"); 
        pinShape.SetTitle(itemName);
    }
    catch(e)
    {
       ErrorLog.LogError(2,1,"CreateSinglePin (creating shape) " + e.message);
    }
    
    try
    { 
        map.AddShape(pinShape);
    }
    catch(e)
    {
       ErrorLog.LogError(2,1,"CreateSinglePin (add shape to map) " + e.message);
    }


}

var firstTime = true;
var panningAndZooming = false;

function HandleZoomAndPan(e)
{
    //this fires on page load, when we don't need to handle the event
    if(firstResponse == true)
    {
       // firstTime = false;
        return;
    }
        
            //get map centerpoint lat/long
    var latLng = map.GetCenter();
    
    var lat = latLng.Latitude;
    var lng = latLng.Longitude;
    panningAndZooming = true;
    
    //var lat = e.Latitude;
    //var lng = e.Longitude;
    
    //if store search
    if(typeOfSearch == "fs")
    {
        //split the values in the hidden field for disambiguated results and call showstores
        var hiddenField = document.getElementById("StoreDisambigHdn");
        
        if ((typeof hiddenField != "undefined") && (hiddenField != null)){
            var data = hiddenField.value.split("|");
            var address = data[0];
            CleanSlate(typeOfSearch);     
            ShowStores(searchLocation,lat,lng);// RW: replaced address with searchLocation
        }
    }
    
    if(typeOfSearch == "fe")
    {

        //split the values in the hidden field for disambiguated results and call showstores
        var hiddenField = document.getElementById("EventDisambigHdn");
        
        if ((typeof hiddenField != "undefined") && (hiddenField != null)){
            var data = hiddenField.value.split("|");
            var address = data[0];
            CleanSlate(typeOfSearch);  
            ShowEvents(searchLocation,lat,lng);// RW: replaced address with searchLocation
            ShowStores(searchLocation,lat,lng);// RW: replaced address with searchLocation
        }
    }
    
    if(typeOfSearch == "fr")
    {
    
        //split the values in the hidden field for disambiguated results and call showstores
        var hiddenField = document.getElementById("RouteDisambigHdn");
        
        if ((typeof hiddenField != "undefined") && (hiddenField != null)){
            var data = hiddenField.value.split("|");
            var address = data[0];
            CleanSlate(typeOfSearch);    
            
            ShowStoresAlongRoute(latestRoute);

           // ShowStores(address,lat,lng);
        }
    
    }
    
    panningAndZooming = false;

}

var panning = false;
var zooming = false;


//fires on the Map.OnChangeView event, which is any zoom, pan, or style change.
function MapPanOrZoom(e)
{
    //we only want this to fire on the pan and zoom, not when somebody searches.
    if(firstResponse)
        return;
    
    //reset page index
    storePageIndex = 1;
    eventPageIndex = 1;
    
    //reset lat and long
        
    HandleZoomAndPan(e);
    return true;
}

//event fired on map zoom
function StartMapZoom(e)
{
    zooming = true;
}
function EndMapZoom(e)
{
    zooming == false;
}

function StartMapPan(e)
{
    panning = true;
}

function EndMapPan(e)
{
    panning = false;
}

//event fired on map pan
function MapPan(e)
{
    HandleZoomAndPan(e);
    return true;
}
        
    

function EntityDict()
{
    var collection = new Array();
    
    this.Collection = function()
    {
        return collection;
    }
    
    this.Count = function()
    {
        return collection.length;
    }
    
    this.GetIndex = function(key)
    {
        for (var a = 0; a < collection.length; a++)
        {
            if (collection[a].length == 2 && collection[a][0] == key)
            {
                return a;
            }
        }
        return -1;
    }
    
    this.Add = function(key, value)
    {
        var a = this.GetIndex(key);
        if (a != -1)
        {
            this.RemoveAt(a);
        }
        
        var n = new Array();
        n[0] = key;
        n[1] = value;
        
        collection.push(n);
    }
    
    this.Get = function(key)
    {
        var a = this.GetIndex(key);
        if (a != -1)
        {
            return collection[a][1];
        }
        
        return null;
    }
    
    this.GetKey= function(index)
    {
        return collection[index][0];
    }
    
    this.GetValue= function(index)
    {
        return collection[index][1];
    }
    
    this.RemoveAt = function(index)
    {
        collection.splice(index, 1);
    }
    
    this.Remove = function(key)
    {
        var a = this.GetIndex(key);
        if (a != -1)
        {
           this.RemoveAt(a);
        }
    }
    
    this.Clear = function()
    {
        collection = new Array();
    }
}


//this should be browser agnostic
function InitXmlHttp() {
  // Attempt to initialize xmlhttp object
  try
  {
    xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
  }
  catch (e)
  {
    // Try to use different activex object
    try
    {
      xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    catch (E)
    {
      xmlhttp = false;
    }
  }
  // If not initialized, create XMLHttpRequest object
  if (!xmlhttp && typeof XMLHttpRequest!='undefined')
  {
    xmlhttp = new XMLHttpRequest();
  }
  // Define function call for when Request obj state has changed
  xmlhttp.onreadystatechange=SearchHandler;
}

function searchHandler()
{
  if (xmlhttp.readyState==4)
  {
    eval(xmlhttp.responseText);
  }
}

function AddRooftopGeocode(address)
{       
  InitXmlHttp();      
  var msg = "GeoCodingHandler.ashx?addr="+escape(address);
  xmlhttp.open("GET", msg, true);
  xmlhttp.send(null);
}

function remove(s, t) {
  /*
  **  Remove all occurrences of a token in a string
  **    s  string to be processed
  **    t  token to be removed
  **  returns new string
  */
    var r = "";
    
    try
    {
      i = s.indexOf(t);
      if (i == -1) return s;
      r += s.substring(0,i) + remove(s.substring(i + t.length), t);
    }
    catch(e)
    {
       ErrorLog.LogError(1,1,"remove " + e.message);
    }

  return r;
  }