﻿//NOTE:  Due to the global stuff, you can only have ONE BHGMap of mode 0 (search) on a page.  You can have multiples of other modes

var parseData = null; //must be a global for timer
var initialPositionSet = false; //must be a global for timer
var parseCallback = null; //must be global for timer
var timer = null;
var mapMoveCallback = null;
var mapMoveTimer = null;
var moveData = null;
var amenityTimer = null;
var amenityFunction = null;

function WaitForMap()
{
    if (initialPositionSet)
    {
        clearInterval(timer);
        parseCallback(parseData); 
    }
}

function SendMapCallback()
{
    clearTimeout(mapMoveTimer);
    mapMoveTimer = null;
    mapMoveCallback(moveData);
}

function HandleAmenities()
{
    clearTimeout(amenityTimer);
    amenityTimer = null;
    amenityFunction();
}

function BHGMap()
{
    var thisMap = null;
    var map = null;
    var mapService = null;
    var pushpins = null;
    var pushpinArray;
    var pushpinClickCallback = null;
    
    var pushpinHoverCallback = null;
    var mapMoveEatCount = 0;
    var displayListings = null;
    var selectedIndex = -1;
    var selectedID = null;
    var showSchools = false;
    var showRestaurants = false;
    var showHealth = false;
    var showShopping = false;
    var homesShapeLayer = null;
    var schoolsShapeLayer = null;
    var healthShapeLayer = null;
    var shoppingShapeLayer = null;
    var restaurantsShapeLayer = null;
    var boundaryShapeLayer = null;
    var followMeMode = false;
    var boundaryMinX = null;
    var boundaryMinY = null;
    var boundaryMaxX = null;
    var boundaryMayY = null;
    var haveBoundary = false;
    var mapMode = null;
    var duplicatePinMap = null
    var currentClickCount = 0;
    var lastView = null;
    var lastViewStyle = null;
    var controls = new Array();
    var weAreIE6 = false;
    var name = null;
    var amenityControl = null;
    var showAmenityControl = null;
    var amenityBounds = null;
    var amenitiesLoaded = 0;
    var originalSearchString = null
    
    //zIndex constants
    var zIndexHome = 997;
    var zIndexAnchor = 998;
    var zIndexSelected = 999;
    var zIndexRollover = 1000;
    var zIndexSchool = 903;
    var zIndexHealth = 902;
    var zIndexShopping = 901;
    var zIndexRestaurant = 900;
    
    //amenity zoom level
    var amenityZoomLevel = 14;
    
    var thottleInMilliseconds = 1500;
    
    this.Initialize = function(mapDiv, mode, mapName) 
    {
        //modes:
        //0 = search
        //1 = compare
        //2 = details
        thisMap = this;
        mapMode = mode;
        name = mapName;
        var fixed = false;

        map = new VEMap(mapDiv);
        map.LoadMap();
        map.AttachEvent("onclick", this.OnClick);
        map.AttachEvent("onchangeview", this.OnChangeView);
        map.AttachEvent("onmouseover", this.OnMouseOver);
        map.AttachEvent("onmouseout", this.OnMouseOut);
        map.AttachEvent("onstartcontinuouspan", this.OnMapMove);
        map.AttachEvent("onstartzoom", this.OnMapMove);
        map.ClearInfoBoxStyles();
        map.SetShapesAccuracy(VEShapeAccuracy.All);
        if (mode == 2)
        {
            map.HideDashboard();
        }     
        followMeMode = false;
        this.DetectIE6();
    }     
    
    this.OnClick = function(element)
    { 
        if (element.elementID != null)
        {
            if (element.leftMouseButton)
            {
                var shape = map.GetShapeByID(element.elementID);
                if (shape != null)
                {
                    var index = thisMap.GetPushpinIndex(shape.iid);
                    if (index != null)
                    {
                        var ID = thisMap.GetPushpinIDFromIndex(index);
                        if (ID != null)
                        {
                            //don't call this if it is the anchor address for the compare or details page page
                            if ((thisMap.GetMapMode() != 1 && thisMap.GetMapMode() != 2)  || index != 0)
                            {
                                if (thisMap.GetSelectedIndex() == index)
                                {
                                    //user is clicking same pin again
                                    var clickCount = thisMap.AdvanceCurrentClickCount();
                                    var pins = thisMap.GetPushpinData();
                                    index = pins[index].GetIndex(clickCount);
                                    ID = thisMap.GetPushpinIDFromIndex(index);  
                                }
                                else
                                {
                                    thisMap.ClearCurrentClickCount();
                                    thisMap.SetSelectedIndex(index);
                                } 
                               
                                if (pushpinClickCallback != null)
                                {
                                    pushpinClickCallback(ID);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    
    this.OnChangeView = function(args)
    {
        if (mapMoveEatCount <= 0 && thisMap.GetMapMode() == 0)
        {
            var mapStyle = thisMap.GetStyle();
            if (mapStyle != "o" && mapStyle != "b") //o = oblique = birdseye, b = new hybird birdseye in 6.1
            {
                //only do these checks if we aren't in birdseye.
                thisMap.SetLastViewStyle(mapStyle);
                var mapView = null;
                //check to see if we are outside of a boundary
                if (!followMeMode && haveBoundary == true)
                {   
                    mapView = map.GetMapView();
                    if (mapView.BottomRightLatLong.Latitude >  boundaryMaxY ||
                        mapView.TopLeftLatLong.Latitude < boundaryMinY ||
                        mapView.TopLeftLatLong.Longitude > boundaryMaxX ||
                        mapView.BottomRightLatLong.Longitude < boundaryMinX)
                    {
                        //we have moved outside of the boundary range
                        followMeMode = true;
                        boundaryShapeLayer.DeleteAllShapes();
                        haveBoundary = false;
                    }
                }

                if (mapMoveCallback)
                {
                    if (mapView == null)
                    {
                         mapView = map.GetMapView();
                    }
                  
                    var suppressCallback = false;
                    var lastView = thisMap.GetLastView();
                    if (lastView != null)
                    {
                        if (lastView.TopLeftLatLong.Latitude == mapView.TopLeftLatLong.Latitude && 
                            lastView.TopLeftLatLong.Longitude == mapView.TopLeftLatLong.Longitude &&
                            lastView.BottomRightLatLong.Latitude == mapView.BottomRightLatLong.Latitude &&
                            lastView.BottomRightLatLong.Longitude == mapView.BottomRightLatLong.Longitude)
                        {
                            suppressCallback = true;
                        }
                    } 
                    
                    if (!suppressCallback)
                    { 
                        moveData = new MoveReturnData();
                        moveData.topLeftLatLong = mapView.TopLeftLatLong;
                        moveData.bottomRightLatLong = mapView.BottomRightLatLong;
                        moveData.beyondInitialBoundary = followMeMode;
                        moveData.centerPoint = map.GetCenter();
                        thisMap.SetLastView(mapView);
                        mapMoveTimer = setTimeout("SendMapCallback();",thottleInMilliseconds);
                    }
                }         
            }
            else
            {
                //we are in  birdseye.  See if we are changing to it, and if so, if something is selected, center on it.
                var lastStyle = thisMap.GetLastViewStyle();
                thisMap.SetLastViewStyle(mapStyle);
                if (lastStyle != "o" && lastStyle != "b")
                {
                    var index = thisMap.GetSelectedIndex();
                    if (index != -1)
                    {
                        thisMap.SetSelectedIndex(index);
                    }
                }
            }
            //handle amenities box show/hide
            thisMap.ShowAmenityControl(true); 
        }
        else
        {
            mapMoveEatCount--;
            if (mapMoveEatCount == 1)
            {  
                map.SetZoomLevel(map.GetZoomLevel() + 1); 
            }
            else if (mapMoveEatCount == 0)
            {
                var mapView = map.GetMapView();
                parseData.topLeftLatLong = mapView.TopLeftLatLong;
                parseData.bottomRightLatLong = mapView.BottomRightLatLong;
                parseData.centerPoint = map.GetCenter();
                thisMap.SetLastView(mapView);
                thisMap.ShowAmenityControl(false);
                initialPositionSet = true;
                if (thisMap.GetMapMode() == 0)
                {
                    //do boundary stuff
                    PageMethods.GetBoundary(parseData.city, parseData.state, parseData.zip, parseData.neighborhood, thisMap.SetBoundary);
                    // do amenities stuff
                    thisMap.ShowAmenityControl(false);
                }
            }
            
        }
    }
    
    this.OnMouseOver = function(args)
    {  
        if (args != null)
        {
            if (args.elementID != null)
            {
                var shape = map.GetShapeByID(args.elementID);
                if (shape != null)
                {
                    var index = thisMap.GetPushpinIndex(shape.iid);
                    if (index != null && index != thisMap.GetSelectedIndex())
                    {
                        //don't do anything if we are on an anchor pin
                        if ((thisMap.GetMapMode() != 1 && thisMap.GetMapMode() != 2)  || index != 0)
                        {
                            thisMap.SetPinOnOff(index, true); 
                            //set z-index
                            thisMap.SetZIndexCustom(shape, zIndexRollover);
                            
                            var ID = thisMap.GetPushpinIDFromIndex(index);
                            if (ID != null)
                            {
                                if (pushpinHoverCallback != null)
                                {
                                    pushpinHoverCallback(ID, true);
                                }
                            }          
                        }
                    }
                }
            }
        } 
        return false;
    }   

    this.OnMouseOut = function(args)
    {
        if (args != null)
        {
            if (args.elementID != null)
            {
                var shape = map.GetShapeByID(args.elementID);
                if (shape != null)
                {
                    var index = thisMap.GetPushpinIndex(shape.iid);
                    if (index != null && index != thisMap.GetSelectedIndex())
                    {
                        //don't do anything if we are on an anchor pin
                        if ((thisMap.GetMapMode() != 1 && thisMap.GetMapMode() != 2)  || index != 0)
                        {
                            thisMap.SetPinOnOff(index, false);
                            //set z-index
                            thisMap.SetZIndexCustom(shape, zIndexHome);
                            
                            var ID = thisMap.GetPushpinIDFromIndex(index);
                            if (ID != null)
                            {
                                if (pushpinHoverCallback != null)
                                {
                                    pushpinHoverCallback(ID, false);
                                }
                            } 
                        }    
                    }
                }
            }
        } 
        return false;
    }
    
    this.OnMapMove = function(args)
    {
        if (mapMoveTimer != null)
        {
            clearTimeout(mapMoveTimer);
            mapMoveTimer = null;
            clearTimeout(amenityTimer);
            amenityTimer = null;
        }    
    }
    
    
    //SetZIndexCustom is a workaround because Shape.SetZIndex doesn't always work and it corrupts
    //mouse events (specifically (OnMouseOut) so that highlighting on mouseover is impossible/
    //note that in future version of virutal Earth we should hopefully be able to go back to using
    //the Shape.SetZIndex function if Microsoft ever fixes it.
    this.SetZIndexCustom = function(shape, index)
    {
        if (shape && shape.GetPrimitive && index && index != -1)
        {
            var shapeElem = document.getElementById(shape.GetPrimitive(0).iid);
            if (shapeElem && shapeElem.style)
            {
                shapeElem.style.zIndex = index;
            }
        }
    }

    this.SetZoomLevel = function(zoomLevel)
    {
        map.SetZoomLevel(zoomLevel);
    }
    
    this.SetStyle = function(style)
    {
        map.SetMapStyle(style);
    }
    
    this.SetView = function(neCorner, swCorner)
    {
        var viewArray = new Array();
        viewArray.push(neCorner);
        viewArray.push(swCorner);
        map.SetMapView(viewArray);
    } 
    
    this.SetCenter = function(center)
    {
        map.SetCenter(center);
    }
    
    this.GetMapBounds = function()
    {
        var mapView;
        var mapStyle = this.GetStyle();
        if (mapStyle != "o" && mapStyle != "b") //o = oblique = birdseye, b = new hybird birdseye in 6.1
        {
            mapView = map.GetMapView();
        }
        else
        {
            mapView = this.GetLastView();
        }
        var bounds = new Array();
        bounds.push(mapView.TopLeftLatLong);
        bounds.push(mapView.BottomRightLatLong);
        return bounds;
    }  
    
    this.AddPushpins = function(pushpins, type)
    {
        var pinArray = new Array();
        var locationArray = new Array();
        var hiddenHomeIndexes = new Array();
        var mapViewArray = new Array();
        var anchorShape = null;
        var zIndex = -1;
        
        for (var i = 0; i < pushpins.length; i++)
        {
            var mode = 0;
            var anchor = false;
            if (i == 0 && (mapMode == 1 || mapMode == 2) && type == 0)
            {
                mode = 2;
                anchor = true; 
            }
            if (pushpins[i] != null)
            {
                var shape = this.ShapeFromPushpinData(pushpins[i], i);
                this.SetIcon(shape, type, mode, i);
                pinArray.push(shape);
                //var location = new VELatLong(parseFloat(pushpins[i].location.latitude), parseFloat(pushpins[i].location.longitude));
                mapViewArray.push(pushpins[i].location);
                if (anchor == true)
                {
                    //don't check for a duplicate location if it is at the same location as the anchor point.  
                    anchorShape = shape;
                }
                else
                { 
                    locationArray.push(pushpins[i].location);
                }
            }
            else
            {
                  hiddenHomeIndexes.push(i);
            }
        }
        
        var layer = null;
        switch(type)
        {
            case 0:
                layer = homesShapeLayer;  
                zIndex = zIndexHome;
                break;
            case 1: 
                layer = schoolsShapeLayer;
                zIndex = zIndexSchool;
                break;
            case 2:
                layer = restaurantsShapeLayer;
                zIndex = zIndexRestaurant;
                break;
            case 3: 
                layer = healthShapeLayer;
                zIndex = zIndexHealth;
                break;
            case 4:
                layer = shoppingShapeLayer;
                zIndex = zIndexShopping;
                break;
        }
        
        if (layer != null)
        {
            layer.DeleteAllShapes();
        }
        else
        {
            layer = new VEShapeLayer();
            switch(type)
            {
                case 0:
                    homesShapeLayer = layer;
                    break;
                case 1: 
                    schoolsShapeLayer = layer;
                    break;
                case 2:
                    restaurantsShapeLayer = layer;
                    break;
                case 3:
                    healthShapeLayer = layer;
                    break;
                case 4:
                    shoppingShapeLayer = layer;
                    break;      
            }
            map.AddShapeLayer(layer);
           
            if ((mapMode == 1 || mapMode == 2) && type == 0)
            {
                //details map, fit to pushpins
                map.SetMapView(mapViewArray)
            }
        }
       
        
        layer.AddShape(pinArray); 
        
        for (var i = 0; i < pinArray.length; i++)
        { 
        
            //gotta use the hack for the home pins since they support rollover
            this.SetZIndexCustom(pinArray[i], zIndex);
        }
        
        if (anchorShape != null)
        {
            //this puts the anchor icon on top in the z-order
            this.SetZIndexCustom(anchorShape, zIndexAnchor);
        } 
        if (type == 0)
        {
            //homes--record the Virtual Earth ID which is only created AFTER adding the pin to the map
            pushpinArray = new Array();
            var index = 0;
            var hiddenIndex = 0;
            for (var i = 0; index < pinArray.length; i++)
            {
                if (hiddenIndex < hiddenHomeIndexes.length && i == hiddenHomeIndexes[hiddenIndex])
                {
                    hiddenIndex++;
                    pushpinArray.push(null);
                } 
                else
                {
                    pushpinArray.push(pinArray[index].GetID()); 
                    index++; 
                }   
            }
        }
    }
    
    this.ShapeFromPushpinData = function(pushpinData, index)
    { 
        var shape = new VEShape(VEShapeType.Pushpin, pushpinData.location);   
        //this.SetIcon(shape, pushpinData.type);
        var html;
        if (pushpinData.type == 0)
        {
            //home
            var count = pushpinData.GetCount();
            if (count == 0)
            {
                var switchValue = thisMap.GetMapMode();
                if (switchValue == 2 && index == 0)
                {
                    //for base pin on details page, use the compare page rollover.
                    switchValue = 1;
                }
                switch(switchValue)
                {
                    case 0:
                    case 2:
                        html="<div class=\"address\"><u>"+pushpinData.GetAddress()+"</u></div><div class=\"price\">"+pushpinData.GetPriceText() + "</div>";
                        var beds = pushpinData.GetBedrooms();
                        var baths = pushpinData.GetBathrooms();
                        
                        if (beds != null || baths != null)
                        {
                            html += "<div class=\"bedbath\">";

                            if (beds != null)
                            {
                                var bedText = "Beds";
                                if (beds == 1)
                                {
                                    bedText = "Bed";
                                }
                                
                                html += beds + " " + bedText+ " ";
                            }
                            
                            if (baths != null)
                            {
                                if (beds != null)
                                {
                                    html += "<img src=\"../../Images/bullet_results_blue.gif\" class=\"mapbullet\"> ";
                                }
                                
                                var bathText = "Baths";
                                if (baths == 1)
                                {
                                    bathText = "Bath";
                                }
                                
                                html += baths +" " + bathText;
                            }

                            html += "</div>";
                        }
                        break;
                    case 1:
                        html = "<div class=\"address\"><u>"+pushpinData.GetAddress()+"</u></div><div class=\"price\"><span>"+pushpinData.GetPriceText();
                        var beds = pushpinData.GetBedrooms();
                        var baths = pushpinData.GetBathrooms();
                        
                        if (beds != null || baths != null)
                        {
                            html += " <img src=\"../../Images/bullet_results_blue.gif\" class=\"mapbullet\"> </span>";
                            
                            if (beds != null)
                            {
                                var bedText = "Beds";
                                if (beds == 1)
                                {
                                    bedText = "Bed";
                                }
                                
                                html += "<span class=\"bedbath\">"+beds+" " + bedText + " ";
                            }
                            
                            if (baths != null)
                            {
                                if (beds != null)
                                {
                                    html += "<img src=\"../../Images/bullet_results_blue.gif\" class=\"mapbullet\"> ";
                                }
                                
                                var bathText = "Baths";
                                if (baths == 1)
                                {
                                    bathText = "Bath";
                                }
                                
                                html += baths + " " + bathText;
                            }
                        }
                            
                        html += "</span></div>";
                                
                        break;
                }
            }
            else
            {
                displayCount = count + 1;
                html="<div class=\"multiplelistings\">"+displayCount+" Listings</div><div class=\"bedbath\">Click pin repeatedly<br> to cycle through listings</div>"; 
            }  
        }
        else
        {
            html="<div class=\"amenities\">"+pushpinData.GetName()+"</div>";   
        }
        
        shape.SetDescription(html);
        return shape;
    }
    
    this.GetPushpinIndex = function(VEID)
    {
        if (pushpinArray != null)
        {
            for (var i = 0;i < pushpinArray.length; i++)
            {
                if (pushpinArray[i] != null && pushpinArray[i] == VEID)  
                {
                    return i; //pushpinArray[i].ID;
                }
            }
        }
        return null;
    } 
    
    this.GetPushpinIDFromIndex = function(index)
    {
        var ID = null;
        if (displayListings[index] != null)
        {
            ID = displayListings[index].ListingId;
        }
        return ID;
    }
    
    this.SetIcon = function(shape, type, mode, index)
    {
        //mode for properties
        //0 = normal
        //1 = selected
        //2 = main entry for compare
        var iconURL = "";
        var xOffset = 0;
        var yOffset = 0;
        switch(type)
        {
            //property
            case 0:
                //these are the offsets that *SHOULD* move the icon so that the point of it is in the right place
                //**HOWEVER** it doesn't seem to be right, plus it causes a weird mouse hotspot, so I am pulling
                //the offset for now.
                //xOffset = -14 
                //yOffset = -6
                if (mode == 0)
                {
                    iconURL = "/images/map/home";
                }
                else if (mode == 1)
                {
                    iconURL = "/images/map/home_selected";
                } 
                else if (mode == 2)
                {
                    iconURL = "/images/map/home_anchor";
                }
                break;
            //school
            case 1:
                iconURL = "/images/map/school";
                break;
            case 2:
                iconURL = "/images/map/restaurant";
                break;
            //health clinics
            case 3:
                iconURL = "/images/map/health";
                break;
            //shopping
            case 4:
                iconURL = "/images/map/shopping";
                break;
        }
        
        if (this.weAreIE6 == true)
        {
            //gotta show gifs for IE6 because it can't do transparent pngs.
            iconURL += ".gif";    
        }
        else
        {
            iconURL += ".png";
        }
        
        if (type == 0)
        {
            var ID = name + "Icon" + index;
            var iconHTML = "<div style=\'position:relative;top:"+yOffset+"px;left:"+xOffset+"px;\'><img id='"+ID+"' src='" + iconURL +"'></div>";
        }
        else
        {
            var iconHTML = "<div style=\'position:relative;top:"+yOffset+"px;left:"+xOffset+"px;\'><img src='" + iconURL +"'></div>";
        }
        shape.SetCustomIcon(iconHTML);
    }
    
    this.RegisterPushpinClickCallback = function(callbackFunction)
    {
        pushpinClickCallback = callbackFunction;
    }    
    
    this.RegisterMapMoveCallback = function(callbackFunction)
    {
        mapMoveCallback = callbackFunction;
    }  
    
    this.UnRegisterMapMoveCallback = function(callbackFunction)
    {
        mapMoveCallback = null;
    }  
    
    this.RegisterParseCallback = function(callbackFunction)
    {
        parseCallback = callbackFunction;
    }
    
    this.RegisterPushpinHoverCallback = function(callbackFunction)
    {
        pushpinHoverCallback = callbackFunction;
    }    
    
    this.SetSelectedIndex = function(index)
    {
        if (index < 0)
        {
            index = -1;
        } 
        else
        {
            index = this.UpdateIndexFromDuplicatePinMap(index);
        }
        
        if (index < 0 || index >= pushpinArray.length || pushpinArray[index] == null)
        {
            index = -1;
        }
        
        
        var validIndex = false;
        if (index != -1)
        {
            selectedID = displayListings[index].ListingId;
            
            var shape = null;
            if (pushpinArray[index] != null)
            {
                shape = map.GetShapeByID(pushpinArray[index]);
            }
            
            validIndex = this.SetPinOnOff(index, true, true);
            
            if (shape != null && validIndex != null)
            {
                this.SetZIndexCustom(shape, zIndexSelected);
            }
            
            var mapStyle = this.GetStyle();
            if (mapStyle == "o" || mapStyle == "b") //o = oblique = birdseye, b = new hybird birdseye in 6.1  
            {
                //center the map on the pin
                if (shape != null)
                {
                    map.SetCenter(shape.GetPoints()[0]);
                }
            }
        }
        else
        {
            selectedID = null;
        }
        
        if (selectedIndex >= 0 && selectedIndex != index)
        {
            this.SetPinOnOff(selectedIndex, false, true); 
            var shape = null;
            if (pushpinArray[selectedIndex] != null)
            {
                shape = map.GetShapeByID(pushpinArray[selectedIndex]);
                if (shape != null)
                {
                    this.SetZIndexCustom(shape, zIndexHome);
                }
            }   
        }
        
        selectedIndex = index;
    }
    
    this.SetHoverIndex = function(index, on)
    {
        if (index >= 0 && index < pushpinArray.length && pushpinArray[index] != null)
        {
            index = this.UpdateIndexFromDuplicatePinMap(index);
     
            if (index != this.GetSelectedIndex())
            {
                this.SetPinOnOff(index, on);
            }
        }
    }
    
    this.SetPinOnOff = function(index, pinOn, overrideSelected)
    {
        var pinSet = false;
        //only do this if it is NOT the selected pin
        if (index != this.GetSelectedIndex() || overrideSelected)
        {
            var ID = name + "Icon" + index;
            var shapeElem = document.getElementById(ID);
            if (shapeElem)
            {
                var src;
                if (pinOn == true)
                {
                    src = "/images/map/home_selected";
                }
                else
                {
                    src = "/images/map/home";
                }
                
                if (this.weAreIE6 == true)
                {
                    //gotta show gifs for IE6 because it can't do transparent pngs.
                    src += ".gif";
                }
                else
                {
                    src += ".png";
                }
                shapeElem.src = src;
                pinSet = true;
            }
        }
        return pinSet;
    }
    
    this.GetSelectedIndex = function(index)
    {
        return selectedIndex;
    }
    
    this.GetPushpinData = function()
    {
        return pushpins;
    }
    
    this.DisplayPushpins = function(records)
    {
        pushpins = new Array();
        duplicatePinMap = new Array();
        var setSelected = -1;
        displayListings = records;//search.Context.Records; //getting global variable
            
        for (var i = 0;i < displayListings.length;i++)
        {       
            if (!displayListings[i].DoNotDisplayAddress && displayListings[i].Latitude != null && displayListings[i].Longitude != null)    
            {    
                var sameLocationListing = null;
                //check to see if we already have this lat long
                for (var j = 0; j < pushpins.length && sameLocationListing == null; j++)
                {
                    if (pushpins[j] != null && displayListings[i].Latitude == pushpins[j].location.latitude && displayListings[i].Longitude == pushpins[j].location.longitude)
                    {
                        pushpins[j].AddIndex(i);
                        sameLocationListing = j;
                        var dpm = new DuplicatePinMap(i, j);
                        duplicatePinMap.push(dpm);
                        pushpins.push(null);
                    }
                }
                if (sameLocationListing == null)
                {
                    var pushpinData = new PushpinData(i, new VELatLong(parseFloat(displayListings[i].Latitude), parseFloat(displayListings[i].Longitude)));
                    var street = displayListings[i].Street1;
                    if (displayListings[i].Street2 != null && displayListings[i].Street2.length > 0)
                    {
                        street = street + " " + displayListings[i].Street2;
                    }
                    pushpinData.SetPropertyInfo(street, displayListings[i].ListPrice, displayListings[i].Bedrooms, displayListings[i].TotalBathrooms); 
                    pushpins.push(pushpinData); 
                }
                
                if (selectedID != null && displayListings[i].ListingId == selectedID)
                {
                    if (sameLocationListing == null)
                    {
                        setSelected = i;
                    }
                    else
                    {
                        setSelected = sameLocationListing;
                    }
                }
            }
            else
            {
                pushpins.push(null);
            }
        }
        this.AddPushpins(pushpins, 0);
        
        if (setSelected > -1)
        {
            this.SetSelectedIndex(setSelected);
        }
        else
        {
            selectedIndex = -1;
            selectedID = null;
        } 
    }
    
    this.LoadAmenities = function()
    {
        var type = 0;
        
        if (showSchools)
        {
            if (!(amenitiesLoaded & 1))
            {
                type |= 1;
                amenitiesLoaded |= 1;
            }
        }
        if (showRestaurants)
        {
            if (!(amenitiesLoaded & 2))
            {
                type |= 2;
                amenitiesLoaded |= 2;
            }
        }
        if (showHealth)
        {
            if (!(amenitiesLoaded & 4))
            {
                type |= 4;
                amenitiesLoaded |= 4;
            }
        }
        if (showShopping)
        {
            if (!(amenitiesLoaded & 8))
            {
                type |= 8;
                amenitiesLoaded |= 8;
            }
        }
        
        if (type != 0)
        {
            var bounds = amenityBounds;
            if (bounds == null)
            {
                bounds = this.GetMapBounds();
                amenityBounds = bounds;
            }
            
            PageMethods.GetAmenitiesByLatLong(type, bounds[0].Latitude, bounds[0].Longitude, bounds[1].Latitude, bounds[1].Longitude, this.Amenities_Load);
        } 
    }

    this.Amenities_Load = function(amenities)
    {
        var schools = new Array();
        var restaurants = new Array();
        var health = new Array();
        var shopping = new Array();
       
        for (var i=0; i < amenities.length; i++)
        {
            var array = null;
            switch (amenities[i].Type)
            {
                case 1:
                    array = schools;
                    break;
                case 2:
                    array = restaurants;
                    break;
                case 4:
                    array = health;
                    break;
                case 8:
                    array = shopping;
                    break;
                default:
                    foundType = false;
                    break;
            }

            var pushpinData = new PushpinData(0, new VELatLong(parseFloat(amenities[i].Latitude), parseFloat(amenities[i].Longitude)));
            pushpinData.SetAmenityInfo(amenities[i].Type, amenities[i].Name);
            array.push(pushpinData);
        }
        
        if (schools.length > 0)
        {
            thisMap.AddPushpins(schools, 1);
        }
        
        if (restaurants.length > 0)
        {
            thisMap.AddPushpins(restaurants, 2);
        }
        
        if (health.length > 0)
        {  
            thisMap.AddPushpins(health, 3);
        }
        
        if (shopping.length > 0)
        {  
            thisMap.AddPushpins(shopping, 4);
        }   
    }

    this.SetAmenities = function(schools, restaurants, health, shopping)
    {
        var makeAmenitiesCall = false;
        
        for (var i = 1; i < 5; i++)
        {
            var currentValue;
            var newValue;
            var type = 0;
            switch (i)
            {
                case 1:
                    currentValue = showSchools;   
                    newValue = schools;
                    type = 1;
                    break;
                case 2:
                    currentValue = showRestaurants;
                    newValue = restaurants;
                    type = 2;
                    break;
                case 3:
                    currentValue = showHealth;
                    newValue = health;
                    type = 4;
                    break;
                case 4:
                    currentValue = showShopping;
                    newValue = shopping;
                    type = 8;
                    break;
            }
            
            if (currentValue && !newValue)
            {
                this.HideAmenityLayer(i);
            }
            else if (!currentValue && newValue)
            {
                if (amenitiesLoaded & type)
                {
                    //amenity is already loaded, just show it
                    this.ShowAmenityLayer(i, true);
                }
                else
                {
                    makeAmenitiesCall = true;
                }
            }          
        }

        showSchools = schools;
        showRestaurants = restaurants;
        showHealth = health;
        showShopping = shopping;
        
        if (makeAmenitiesCall)
        {
            this.LoadAmenities();  
        }    
    }
    
    this.ClearAllAmenities = function()
    {
        for (var i = 1; i < 5; i++)
        {
            this.ClearAmenities(i);
        }
    }
    
    this.ClearAllHomes = function()
    {
        if (homesShapeLayer != null)
        {
            homesShapeLayer.DeleteAllShapes();
        }
    }
    
    this.ClearAmenities = function(type)
    {
        var layer = null;
        switch(type)
        {
            case 1: 
                layer = schoolsShapeLayer;
                amenitiesLoaded &= 14; //0x1110
                break;
            case 2: 
                layer = restaurantsShapeLayer;
                amenitiesLoaded &= 13; //0x1101
                break;
            case 3: 
                layer = healthShapeLayer;
                amenitiesLoaded &= 11; //0x1011    
                break;
            case 4:
                layer = shoppingShapeLayer;
                amenitiesLoaded &= 7; //0x0111   
        }
            
        if (layer != null)
        {
            layer.DeleteAllShapes();
        }
    }
    
    this.HideAmenityLayer = function(type)
    {
        var layer = null;
        switch(type)
        {
            case 1: 
                layer = schoolsShapeLayer;
                break;
            case 2:
                layer = restaurantsShapeLayer;
                break;
            case 3: 
                layer = healthShapeLayer;
                break;
            case 4:
                layer = shoppingShapeLayer;
                break;
        }
        if (layer != null)
        {  
            layer.Hide();        
        }
    }
    
    this.ShowAmenityLayer = function(type, forceZ)
    {
        var layer = null;
        var array = null;
        var zIndex = -1;
        switch(type)
        {
            case 1: 
                layer = schoolsShapeLayer;
                zIndex = zIndexSchool;
                break;
            case 2:
                layer = restaurantsShapeLayer;
                zIndex = zIndexRestaurant;
                break;
            case 3: 
                layer = healthShapeLayer;
                zIndex = zIndexHealth;
                break;
            case 4:
                layer = shoppingShapeLayer;
                zIndex = zIndexShopping;
                break;
        }    
        if (layer != null)
        {       
            layer.Show();
            var count = layer.GetShapeCount();
            if (forceZ == true)
            {
                for (var i = 0; i < count; i ++)
                {
                    var shape = layer.GetShapeByIndex(i);
                    this.SetZIndexCustom(shape, zIndex);
                }
            }     
        }
    }
    
    this.ShowAmenityControl = function(delayLoad)
    {
        var show;
        var forceZ = false;
        var mapStyle = thisMap.GetStyle();
        if (map.GetZoomLevel() >= amenityZoomLevel || mapStyle == "o" || mapStyle == "b")
        {
            show = true;
            
        }
        else
        {
            show = false;
        }
        
        if ((showAmenityControl == null || showAmenityControl != show) && amenityControl != null)
        {
            forceZ = true; 
            if (show == true)
            {
                amenityControl.control.style.top = amenityControl.top;
                amenityControl.control.style.left = amenityControl.left;
                map.AddControl(amenityControl.control, null);
                amenityControl.control.style.display = "block";       
            }
            else
            {
                map.DeleteControl(amenityControl.control); 
                for (var i = 1; i < 5; i++)
                {
                    thisMap.HideAmenityLayer(i);
                }   
            }
            showAmenityControl = show;
        }   
        
        
        if (show == true)
        {
            //turn on anyone that is supposed to be on
            //force it everytime because otherwise things disappear in weird cases.
            for (var i = 1; i < 5; i++)
            {
                var showLayer = false;
                switch (i)
                {
                    case 1:
                        showLayer = showSchools;
                        break;
                    case 2:
                        showLayer = showRestaurants;
                        break;
                    case 3:
                        showLayer = showHealth;
                        break;
                    case 4:
                        showLayer = showShopping;
                        break;
                }
                
                if (showLayer)
                {
                    thisMap.ShowAmenityLayer(i, forceZ);
                }
            }
            
            if (!delayLoad)
            {
                //determine if we need to reload amenities
                if (amenityBounds != null)
                {
                    mapView = thisMap.GetMapBounds();
                    {
                        //check mapview to see if we have moved outside of amenity bounds
                        if (mapView[0].Latitude > amenityBounds[0].Latitude ||
                            mapView[0].Longitude < amenityBounds[0].Longitude ||
                            mapView[1].Latitude < amenityBounds[1].Latitude ||
                            mapView[1].Longitude > amenityBounds[1].Longitude)
                        {
                            //thisMap.ClearAllAmenities();
                            amenitiesLoaded = 0;
                            amenityBounds = null;
                        }
                    }
                }
                
                thisMap.LoadAmenities(); 
            }
            else
            {
                amenityFunction = thisMap.ShowAmenityControl;
                amenityTimer = setTimeout("HandleAmenities();",thottleInMilliseconds);
            }
        }    
    } 
    
    this.SetBoundary = function(boundary)
    {
        if (boundary != null)
        {
            if (boundaryShapeLayer == null)
            {
                boundaryShapeLayer = new VEShapeLayer(); 
                map.AddShapeLayer(boundaryShapeLayer); 
            }
            else
            {
                 boundaryShapeLayer.DeleteAllShapes();
            }
        
            boundaryMinX = boundary[0].Minimum.X;
            boundaryMinY = boundary[0].Minimum.Y;
            boundaryMaxX = boundary[0].Maximum.X;
            boundaryMaxY = boundary[0].Maximum.Y;
            
             //plot the boundary
            for (var x = 0; x < boundary.length; x++)
            {   
                var points = new Array();
                for (i = 0; i < boundary[x].Points.length; i++)
                {
                    points.push(new VELatLong(parseFloat(boundary[x].Points[i].Y), parseFloat(boundary[x].Points[i].X)));
                }    
                
                var shape = new VEShape(VEShapeType.Polygon, points);
                var lineColor = new VEColor(105,186,215,1);
                shape.SetLineColor(lineColor);
                var color = new VEColor(105,186,215,.2); 
                shape.SetFillColor(color);
                shape.HideIcon();
                boundaryShapeLayer.AddShape(shape);
               
            }  
            haveBoundary = true;
            //this causes the map to resize to a best fit of the boundary
            //var tl = new VELatLong(boundary[0].Maximum.Y,  boundary[0].Minimum.X);
            //var br = new VELatLong(boundary[0].Minimum.Y,  boundary[0].Maximum.X);
            //var tr = new VELatLong(boundary[0].Maximum.Y,  boundary[0].Maximum.X);
            //var bl = new VELatLong(boundary[0].Minimum.Y,  boundary[0].Minimum.X);
            //var viewRect  = new VELatLongRectangle(tl, br, tr, bl);
            //map.internalMap.SetMapView(viewRect);
        }
        else
        {
            //no boundary
            followMeMode = true;
        }
    }
        
    
    this.CleanCityName = function(name)
    {
        var returnName = name;
        var start = returnName.indexOf("[");
        if (start != -1)  
        {
            returnName = returnName.substring(0, start-1);
        }
        return returnName;
    }

    this.ParseAddress = function(address) 
    {
        this.PrepareNewSearch();
        var findInput = address;
        var parsedAddress = processAddressInput(address);
        if (parsedAddress.postalCode != null) 
        {
            findInput = parsedAddress.postalCode;
        }
        originalSearchString = findInput;
        LocationXhr.startRequest(findInput, this.MapLocation);
    }
    
    this.GoToAddress = function(address)
    {
        map.Find(null, address, null, null, 0, 5, false, false, false, true);
    }

    this.MapLocation = function(location)
    {
        var ableToMap = false;
        if (location != null && parseCallback != null)
        {
            parseData = new ParseData();
            if (location.State !== null && (location.Neighborhood !== null || location.City !== null || location.Zipcode !== null))
            {
                parseData.neighborhood = location.Neighborhood;
                parseData.city = location.City;
                parseData.state = (location.State != null) ? location.State.Code : null;
                parseData.zip = location.ZipCode;
                ableToMap = true;
            }
        }
        if (ableToMap === true)
        {
            var searchstring = "";
            searchstring += (parseData.neighborhood != null) ? parseData.neighborhood + ", " : "";
            searchstring += (parseData.city != null) ? parseData.city + ", " : "";
            searchstring += (parseData.state != null) ? parseData.state + " " : "";
            searchstring += (parseData.zip != null) ? parseData.zip : "";

            map.Find(null, searchstring, null, null, 0, 5, false, false, false, true, thisMap.FindCallback);

        }
        else
        {
            //no acceptable guesses.  We don't know what they put in.  Pass back null
            if (mapMode == 0 && parseCallback != null) //search mode
            {
                parseCallback(null);
            }
        }
    }

    this.FindCallback = function(shapeLayer, results, places, more, error) 
    {
        if (mapMode == 0) //search mode
        {
            timer = setInterval("WaitForMap();", 100);
        }
    }
    
    this.ClearCurrentClickCount = function()
    {
        this.currentClickCount = 0;
    }
    
    this.AdvanceCurrentClickCount = function()
    {
        this.currentClickCount++;
        return this.currentClickCount;
    }
    
    this.GetMapMode = function()
    {
        return mapMode;
    }
    
    this.GetStyle = function()
    {
        //Note, Realogy app GetMapStyle is broken, use internalMap object.
        return map.GetMapStyle();
    }
    
    this.SetLastView = function(view)
    {
        lastView = view;
    }
    
    this.GetLastView = function()
    {
        return lastView;
    }
    
    this.SetLastViewStyle = function(viewStyle)
    {
        lastViewStyle = viewStyle;
    }
    
    this.GetLastViewStyle = function()
    {
        return lastViewStyle;
    }
        
    this.PrepareNewSearch = function()
    {
        followMeMode = false;
        initialPositionSet = false;
        mapMoveEatCount = 2;
        haveBoundary = false;
        parseData = null;
        amenityBounds = null;
        originalSearchString = null;
        this.ClearAllHomes();
        this.ClearAllAmenities();
        amenitiesLoaded = 0;
        
        if (boundaryShapeLayer != null)
        {
            boundaryShapeLayer.DeleteAllShapes();
        }
        clearTimeout(timer);
        
        var mapStyle = this.GetStyle();
        if (mapStyle == "o" || mapStyle == "b") //o = oblique = birdseye, b = new hybird birdseye in 6.1
        {
            mapMoveEatCount = 3;  //we have to eat the extra map move we incur from changing map modes
            map.SetMapStyle("r");//move map mode back to road
        }      
    }
    
    this.AddControl = function(control)
    {
        cd = new ControlData(control, control.style.top, control.style.left);
        controls.push(cd);
        map.AddControl(control, null);
    }
    
    this.AddAmenityControl = function(control)
    {
        cd = new ControlData(control, control.style.top, control.style.left);
        amenityControl = cd;
    }
    
    this.HideControls = function()
    {
        for (var i = 0; i < controls.length; i++)
        {
            map.DeleteControl(controls[i].control);
        } 
        
        if (amenityControl != null && showAmenityControl == true)
        {
            map.DeleteControl(amenityControl.control);
            showAmenityControl = false;
        }
    }
    
    this.ShowControls = function()
    {
        for (var i = 0; i < controls.length; i++)
        {
            controls[i].control.style.top = controls[i].top;
            controls[i].control.style.left = controls[i].left;
            map.AddControl(controls[i].control, null);
        } 
        
        this.ShowAmenityControl();
    }
    
    this.UpdateIndexFromDuplicatePinMap = function(index)
    {
        //check duplicate pin map
        var found = false;
        for (var i = 0; i < duplicatePinMap.length && !found; i++)
        {
            if (duplicatePinMap[i].index == index)
            {
                index = duplicatePinMap[i].sourceIndex;
                found = true;
            }
        }
        return index;
    }
    
    this.DetectIE6 = function()
    {
        this.weAreIE6 = false;
        if (navigator.appName == "Microsoft Internet Explorer")
        {
            var temp=navigator.appVersion.split('MSIE');
            var ver=parseInt(temp[1]);
            if (ver < 7)
            {
                this.weAreIE6 = true;
            }
        }
    } 

}

function PushpinData(index, location)  //price, bedrooms, bathrooms) 
{
    //type:
    //0 = property
    //1 = school
    this.index = index;
    this.location = location;
    this.type = null;
    this.ID = null;
    this.additionalIndexList = new Array();
    var price = null;
    var bedrooms = null;
    var bathrooms = null;
    var name = null;
    var address = null;

    this.SetID = function(ID)
    {
        this.ID = ID;
    }
    
    this.SetPropertyInfo = function(address, price, bedrooms, bathrooms)
    {
        this.address = address;
        this.type = 0;
        this.price = price;
        this.bedrooms = bedrooms;
        this.bathrooms = bathrooms;
    }
    
    this.SetAmenityInfo = function(type, name)
    {
        this.type = type;
        this.name = name;
    }
    
    this.GetName = function()
    {
        return this.name;
    }
    
    this.GetPriceText = function()
    {
        return this.ConvertToMoney(this.price);
    }
    
    this.GetBedrooms = function()
    {
        return this.bedrooms;
    }
    
    this.GetBathrooms = function()
    {
        return this.bathrooms;
    }
    
    this.GetAddress = function()
    {
        return this.address;
    }
    
    
    this.AddIndex = function(index)
    {
        this.additionalIndexList.push(index);
    }
    
    this.GetCount = function(index)
    {
        return this.additionalIndexList.length;
    }
 
    this.GetIndex = function(clickCount)
    {
        var returnIndex = -1;
        var tempIndex = 0;
        var count = this.GetCount();
        if (count == 0 || clickCount == 0)
        {
            returnIndex = this.index;
        }
        else
        {
           tempIndex = (clickCount % (count + 1));
        }
        
        if (tempIndex == 0)
        {
            returnIndex = this.index;
        }
        else
        {
            returnIndex = this.additionalIndexList[tempIndex - 1];
            
        }
        return returnIndex;
    }

    this.ConvertToMoney =  function(price)
    {
        var priceNumber = "" + price;
        var priceText="$";
        for (var i = 0 ; i < priceNumber.length; i++)
        {
            priceText += priceNumber.charAt(i);
            var checkValue = priceNumber.length - i - 1;
            if (checkValue != 0 && checkValue % 3 == 0)
            {
                priceText += ",";
            }
        }
        return priceText;
    }       
}

function ParseData()
{
    this.city = null;
    this.state = null;
    this.zip = null;
    this.neighborhood = null;
    this.street = null;
    this.topLeftLatLong = null;
    this.bottomRightLatLong= null;
    this.centerPoint = null;
} 

function MoveReturnData()
{
    this.topLeftLatLong = null;
    this.bottomRightLatLong = null;   
    this.beyondInitialBoundary = false;
    this.centerPoint = null;
}

function DuplicatePinMap(index, sourceIndex)
{
    this.sourceIndex = sourceIndex;
    this.index = index;
}

function ControlData(control, top, left)
{
    this.control = control;
    this.top = top;
    this.left = left;
}

function TrimString(str)
{
    return str.replace(/^\s+|\s+$/g, '');
}    