﻿/*
* The programming and software materials herein are copyright LPS.
* The programming and software materials are owned, held, or licensed by LPS. Personal, educational,
* non-commercial, commercial or any other use of these materials, without the written permission of the
* LPS, is strictly prohibited.
*/
/*
MapSearch.js is the overall js for the control. MapSearch.js handles all the page element bindings, searches, criteria, etc. 
BingMap.js is the map control itself - it's used independently to load the maps within the list detail, and on the driving directions, for exampl. BingMap.js handles map redraws, all the VEMap functions, pins, shapes, etc.
*/

function MapSearch(options) {
    // Private variables
    var _self = this;
    var _map;
    var _submitEnabled = false;
    var _submitTimer = null;
    var _mapTimer = null;
    var _resizeTimer = null;
    var _containers = null;
    var _qs = new Querystring();
    var _activeView = "map";
    var _activeSortID;
    var _searchid = "";
    var _displaySort = true;
    var _lastLocationSubmitted = "";
    var _lastLocationSearchTab = "";
    var _movingToolbar = false;
    var _setMapView = false;
    var _disposed = false;
    var _poiEnabled = false;
    var _clsid = 0;
    var _firstSubmit = true;
    var _submitting = false;
    var _advisoryPositionBottom = false;

    var _pageInfo = {
        resultCount: 0,
        maxCount: 0,
        page: 0,
        resultsPerPage: 10,
        cache: true,
        pageCache: {},
        clear: function() {
            this.page = 0;
            this.pageCache = {};
        }
    };
    
     var _defaultOptions = {
        statuses: {
            active: "1,10",
            pending: "5",
            sold: "2"
        },
        mapExpandDiff: 225,
        resultsPerPage: 10,
        poiEnabled: true,
        showParcelLines: true,
        showMinimap: true,
        getOfficePins: true // This is different from displaying on load, it says whether to get them at all
    };

    /* Private functions */

    function loadNeighborhoods(mapState) {

        var divN = document.getElementById("divNeighborhood");
        var selN = document.getElementById("Neighborhood");

        if (!divN || !selN) {
            return;
        }

        // Clear the drop-down
        selN.length = 0;

        var selVal = $("#selNeighborhood").val();
        $("#selNeighborhood").val("");

        if (mapState.Zoom >= 10 && mapState.Style != VEMapStyle.Birdseye) {
            $(selN).hide();
            $("#NeighborhoodLoading").html("<img src='" + imageBase + "spinner.gif' height='12'/>").show();
            $("#divNeighborhoodInfo").html("Retrieving Neighborhoods in this Area").show();

            $.ajax({
                mode: "abort",
                port: "neighborhoods",
                type: "GET",
                url: "/" + Utils.AppName + "/Include/AJAX/MapSearch/GetLocations.aspx",
                data: {
                    type: "neighborhood",
                    q: "*",
                    nelat: mapState.NELat,
                    nelon: mapState.NELon,
                    swlat: mapState.SWLat,
                    swlon: mapState.SWLon,
                    limit: 5000
                },
                dataType: "json",
                dataFilter: function(data) {
                    if (typeof (JSON) !== 'undefined' && typeof (JSON.parse) === 'function') {
                        return JSON.parse(data);
                    } else {
                        return eval('(' + data + ')');
                    }
                },
                success: function(neighborhoods) {
                    try {
                        if (neighborhoods.length === 0) {
                            $("#divNeighborhoodInfo").html("No Neighborhoods Found");
                            $("#icNeighborhoodInfo").attr("title", "No Neighborhoods Found");
                            $(selN).blur();
                            return;
                        }

                        // Filter the neighborhoods based on any selected city value
                        var city = $(":input[name='Criteria/City']", _containers.criteria).val().toLowerCase();
                        if (city.indexOf(",") > 0) {
                            city = city.substring(0, city.indexOf(","));
                        }
                        var filtered;
                        if (city.length === 0) {
                            filtered = neighborhoods;
                        } else {
                            filtered = [];
                            for (var i = 0, len = neighborhoods.length; i < len; i++) {
                                var n = neighborhoods[i];
                                if (n.City && n.City.length > 0) {
                                    if (n.City.toLowerCase() == city) {
                                        filtered.push(n);
                                    }
                                } else {
                                    filtered.push(n);
                                }
                            }
                        }
                        if (filtered.length > 0) {
                            $("#icNeighborhoodInfo").attr("title", "The list below shows all neighborhoods in the nearby map area. Select a neighborhood to see it outlined on the map or zoom out the map to see more neighborhoods.");
                            $(selN).append("<option value=''>- Select Neighborhood -</option>");
                            for (var j = 0, lenj = filtered.length; j < lenj; j++) {
                                var neighborhood = filtered[j];
                                var opt = document.createElement('option');
                                opt.text = neighborhood.Name;
                                opt.value = neighborhood.BoundaryID;
                                if (neighborhood.BoundaryID == selVal) {
                                    opt.selected = "selected";
                                }
                                addOption(selN, opt);
                            }
                            $("#divNeighborhoodInfo").hide();
                            $(selN).show();
                        }
                        else {
                            $("#divNeighborhoodInfo").html("No Neighborhoods Found");
                            $("#icNeighborhoodInfo").attr("title", "No Neighborhoods Found");
                        }
                        $(selN).blur();
                    } catch (err) {
                        Utils.Logger.warn("Error loading neighborhoods: " + err.message);
                    } finally {
                        $("#NeighborhoodLoading").hide();
                    }
                }
            });
        } else {
            $(selN).hide();
            $("#divNeighborhoodInfo").html("Zoom in to view Neighborhoods").show();
            $("#icNeighborhoodInfo").attr("title", "Zoom in to view Neighborhoods").show();
        }
    }

    function getSearchTabSelector(childSelector) {
        var selector;
        var searchTab = $("#SearchTab").val();
        if (searchTab == "basicSearch" || searchTab == "advancedSearch") {
            selector = "#basicSearch " + childSelector + ",#advancedSearch " + childSelector;
        } else {
            selector = "#" + searchTab + " " + childSelector;
        }
        return selector;
    }

    function getFormData(mapState) {
        var data = {};

        $(getSearchTabSelector(":input"), _containers.criteria).each(function() {
            // If no ele name then continue, some form elements may not be needed, we take only those with a name
            if (!this.name) {
                return true;
            }

            // If the value is empty, don't include (to cut down on space)
            if (this.value.length === 0) {
                return true;
            }

            // Skip the element if its type radio or checkbox and is not "checked"
            if ((this.type == "radio" || this.type == "checkbox") && !this.checked) {
                return true;
            }

            // Skip disabled elements
            if (this.disabled) {
                return true;
            }

            // Skip polygon type from legacy forms
            if (this.name == "PolygonType") {
                return true;
            }

            var elValue = this.value;

            // Some special handling for the City
            if (this.name == 'Criteria/City' && elValue != '') {
                if (elValue.indexOf(",") > -1) {
                    var citystate = elValue.split(",");
                    elValue = citystate[0];
                    if (data["Criteria/StateOrProvinceCode"]) {
                        data["Criteria/StateOrProvinceCode"].push(citystate[1]);
                    } else {
                        data["Criteria/StateOrProvinceCode"] = [citystate[1]];
                    }
                }
            }

            // Special handling for the statuses
            if (this.name == 'Criteria/Status') {
                if (elValue == '1') { elValue = options.statuses.active; }
                else if (elValue == '2') { elValue = options.statuses.sold; }
                else if (elValue == '5') { elValue = options.statuses.pending; }
            }

            // If this is a location box, and the name isn't Location, then add the Location and LocationType
            // The original names stay there for use in repopulating the form on reload
            if ($(this).is(".location") && this.name != "Criteria/Location") {
                var supportedTypes = $(this).attr("locationType");
                var locType;
                var selector = "input[type='hidden'][rel='" + $(this).attr("id") + "']";
                var $hiddenType = $(selector, _containers.criteria);
                if ($hiddenType.length > 0) {
                    locType = $hiddenType.val();
                    if (locType.length === 0) {
                        var matches = elValue.match(/\((.*?)\)/);
                        var validType = (matches && matches.length > 0 && (supportedTypes == "" || supportedTypes.toLowerCase().indexOf(matches[matches.length - 1].toLowerCase()) != -1));
                        if (validType) {
                            locType = matches[matches.length - 1];
                        }
                    }
                } else {
                    locType = supportedTypes;
                }
                if (data["Criteria/Location"]) {
                    data["Criteria/Location"] += "|" + elValue;
                    data["Criteria/LocationType"] += "|" + locType;
                } else {
                    data["Criteria/Location"] = elValue;
                    data["Criteria/LocationType"] = locType;
                }
            }

            // Store them as arrays to account for the checkboxes
            // The ajax post will convert them correctly
            if (data[this.name]) {
                data[this.name].push(elValue);
            } else {
                data[this.name] = [elValue];
            }
        });

        // If we didn't get a status, set one
        if (!data["Criteria/Status"]) {
            if ($(getSearchTabSelector("input[name=Criteria/Status]")).length > 0) {
                data["Criteria/Status"] = -1;
            } else {
                data["Criteria/Status"] = 1;
            }
        }

        // Add the map state
        data["Criteria/SearchMapNELat"] = mapState.NELat;
        data["Criteria/SearchMapNELong"] = mapState.NELon;
        data["Criteria/SearchMapSWLat"] = mapState.SWLat;
        data["Criteria/SearchMapSWLong"] = mapState.SWLon;
        data["Criteria/Zoom"] = mapState.Zoom;
        var polygonType = mapState.PolygonType;
        data["PolygonType"] = polygonType;
        if (polygonType != "city" && polygonType != "zip" && mapState.PolyPoints) {
            data["Criteria/PolyPoints"] = mapState.PolyPoints;
        }
        data["IgnoreMap"] = _setMapView;

        // Some other search state
        if (!_activeSortID || _activeSortID < 1) {
            _activeSortID = $("#mapsearch-sort-list").val();
        }
        data["ListingSortID"] = _activeSortID;
        data["view"] = _activeView;
        data["Criteria/SearchType"] = "map";
        data["SearchTab"] = $("#SearchTab").val();
        data["GetOfficePins"] = options.getOfficePins;
        data["ExpandMap"] = $("#mapsearch-toolbar-expand-input").val();
        data["CLSID"] = $("#mapsearch-commingling-list").val() || 0;
        data["ResultsPerPage"] = _pageInfo.resultsPerPage;
        if (_qs.contains('LayoutID')) {
            data["LayoutID"] = _qs.get("LayoutID");
            data["LayoutVersion"] = _qs.get("LayoutVersion");
        }

        return data;
    }

    function setCount(results) {
        var totalCount, displayedCount;
        if (results) {
            totalCount = results.count;
            displayedCount = totalCount;
            if (results.lst) {
                displayedCount = results.lst.length;
            }
            _pageInfo.resultCount = displayedCount;
            _pageInfo.maxCount = results.maxcount;
        } else {
            totalCount = -1;
            displayedCount = -1;
        }
        var msg = "";
        if (isNaN(totalCount) || totalCount == -1) {
            msg = "An error has occurred retrieving your results.  Please try again.";
        } else if (totalCount == 1) {
            msg = "1 Property Found";
        } else {
            msg = Utils.Format.addCommas(totalCount) + " Properties Found";
        }
        setCountText(msg);
        if (displayedCount != totalCount) {
            $(".mapsearch-count-displayed", _containers.count).html(" (" + Utils.Format.addCommas(displayedCount) + " displayed in results)").show();
            $("#mapsearch-commingling-info").show();
        } else {
            $("#mapsearch-commingling-info").hide();
            $(".mapsearch-count-displayed", _containers.count).hide();
        }
        try {
            $(_containers.count).animate({ backgroundColor: "transparent" }, 1000);
        }
        catch (ex) {
            $(_containers.count).css({ backgroundColor: "transparent" });
        }
    }

    function setCountText(msg) {
        $(".mapsearch-count-total", _containers.count).html(msg);
    }


    function unbindListingGrid() {
        var grid = document.getElementById("mapsearch-results-body");
        $("div[mapconfig]", grid).each(function() {
            var map = $(this).data("map");
            if (map) {
                map.dispose();
            }
        });
        $("a.smallMapRoad", grid).unbind("click");
        $("a.smallMapAerial", grid).unbind("click");
        $("a.smallMapHybrid", grid).unbind("click");
        $("div[lid]", grid).unbind("mouseenter").unbind("mouseleave");
    }

    function getPageLinks(cursor, pagesPerRange, totalPages) {
        var p = [];
        var start = pagesPerRange * (Math.floor(cursor / pagesPerRange));

        if ((start + pagesPerRange) > totalPages) {
            start -= (start + pagesPerRange) - totalPages;
        }
        if (start < 0) { start = 0; }

        for (var i = start; i < (start + pagesPerRange) && (i < totalPages); i++) {
            if (i == cursor) {
                p.push(i + 1);
                continue;
            }
            p.push("<a href='JavaScript:Search.gotoPage(" + (i + 1) + ");'>" + (i + 1) + "</a>");
        }

        return p.join(' | ');
    }

    function setPager(results) {
        results.resultsPerPage = _pageInfo.resultsPerPage;
        var count = results.count;
        if (results.lst) {
            count = results.lst.length;
        }
        var totalPages = Math.ceil(count / results.resultsPerPage);
        var first = (results.page * results.resultsPerPage);
        $("#mapsearch-results-paging-properties").html("Property " + (first + 1) + "-" + (first + results.pageCount) + " of " + count);

        var pageLinks = [];
        pageLinks.push("Page " + getPageLinks(_pageInfo.page, 5, totalPages) + " ");
        pageLinks.push(" of " + totalPages + "&nbsp;&nbsp;&nbsp;&nbsp;");

        if (_pageInfo.page === 0) {
            pageLinks.push("<span>Prev</span> | ");
        } else {
            pageLinks.push("<a href='JavaScript:Search.prevPage();'>Prev</a> | ");
        }

        if (_pageInfo.page == totalPages - 1) {
            pageLinks.push("<span>Next</span>");
        } else {
            pageLinks.push("<a href='JavaScript:Search.nextPage();'>Next</a>");
        }

        $("#mapsearch-results-paging-pages").html(pageLinks.join(''));
    }

    function positionAdvisory(toggleTop) {
        if (_movingToolbar) {
            return;
        }
        _movingToolbar = true;
        var $advisory = $("#mapsearch-advisory-box");
        
        var containerHeight;
        if (_activeView == "map") {
            containerHeight = $("#mapsearch-mainmap").height();
        } else {
            containerHeight = $("#mapsearch-mainmap-results").height();
            toggleTop = false;
        }

        var positionLeft = ($("#mapsearch-mainmap-results").width() - $advisory.width()) / 2;
        if ($.browser.msie && parseInt($.browser.version.substring(0, 1)) < 7) {
            positionLeft = positionLeft / 2;
        }
        var middleTop = (containerHeight - $advisory.height()) / 2;
        var bottomTop = $("#mapsearch-maptoolbar").position().top - $advisory.height() * 2;
        var advisoryTop = $advisory.position().top;
        var positionTop;
        if (_activeView == "map") {
            if (toggleTop && _advisoryPositionBottom) {
                positionTop = middleTop;
            } else if (toggleTop && !_advisoryPositionBottom) {
                positionTop = bottomTop;
            } else if (!toggleTop && _advisoryPositionBottom) {
                positionTop = bottomTop;
            } else {
                positionTop = middleTop;
            }
            _advisoryPositionBottom = (positionTop == bottomTop);
        } else {
            positionTop = 0;
        }
        
        $advisory.animate(
            { top: positionTop, left: positionLeft },
            "slow",
            "swing",
            function() { _movingToolbar = false; }
        );
    }

    function showAdvisory() {
        var msg = "";
        // If there is no reason to display the advisory, hide it
        if (_pageInfo.maxCount > 0 && _pageInfo.resultCount > 0 && _pageInfo.resultCount <= _pageInfo.maxCount) {
            hideAdvisory();
        } else if (isNaN(_pageInfo.resultCount) || _pageInfo.resultCount == -1) {
            setAdvisoryText("An error has occurred retrieving your results.", " Please try again.");
        } else if (_pageInfo.resultCount == 1) {
            setAdvisoryText("1 Property Found");
        } else if (_pageInfo.resultCount == 0) {
            setAdvisoryText("0 Properties Found", 'Adjust the map or refine your criteria to find properies in the area.');
        } else {
            setAdvisoryText(Utils.Format.addCommas(_pageInfo.resultCount) + " Properties Found" + ' - Too Many to Display', 'Adjust the map or refine your criteria to narrow the results to less than ' + _pageInfo.maxCount + '.')
        }
    }

    function showCalculating() {
        // Hide the commgling related messages
        $("#mapsearch-commingling-info").hide();
        $(".mapsearch-count-displayed", _containers.count).hide();
        
        setCountText("Calculating...");
        setAdvisoryText("Calculating...", "In a moment we'll show you the matching properties.");
    }

    function hideAdvisory() {
        if ($.browser.msie && parseInt($.browser.version.substring(0, 1), 10) < 7) {
            $("#mapsearch-advisory-box").hide();
        } else {
            $("#mapsearch-advisory-box").fadeTo('slow', 0.0).hide();
        }
    }

    function setAdvisoryText(msg1, msg2) {
        positionAdvisory();
        // msg1 is the bigger text at the top; msg2 is the smaller text underneath msg1
        $("#mapsearch-advisory-box-total").html(msg1);
        $("#mapsearch-advisory-box-count").html(msg2);
        var $box = $("#mapsearch-advisory-box");
        if ($.browser.msie && parseInt($.browser.version.substring(0, 1), 10) < 7) {
            $("#mapsearch-advisory-box").show();
        } else {
            $("#mapsearch-advisory-box").show().fadeTo('slow', 0.9);
        }
    }

    function showListingGrid(results) {

        // Unbind events from the previous grid before reloading to avoid
        // memory leaks
        unbindListingGrid();

        $("#mapsearch-results-body").html(results.listingsHtml).pngFix().unblock();

        // If you add any bindings here, also add them to unbindListingGrid
        if (_activeView == "map") {
            $("#mapsearch-results-header").show();
            $("#mapsearch-results-body div[lid]").hover(function() {
                _map.showListingBubble("1_" + $(this).attr("lid"));
            }, function() {
                _map.hideListingBubble();
            });
        } else {
            $("#mapsearch-results-header").hide();
            $("#mapsearch-results-body div.lsrcExtendedInfoBoxHead h5").click(function() {
                var listingid = $(this).attr("lid");
                var $box = $("#mapsearch-results-body .lsrEIB_" + listingid);
                if ($box.is(":visible")) {
                    $("span.arrow", this).removeClass("arrow-down").addClass("arrow-left");
                    $box.hide("slow");
                } else {
                    $("span.arrow", this).removeClass("arrow-left").addClass("arrow-down");
                    // When showing the extended info, create the map if we need to
                    $box.show("slow", function() {
                        var $mapBox = $("div[mapconfig]", this);
                        if ($mapBox.length > 0 && !$mapBox.data("map")) {
                            var $parent = $mapBox.parent();
                            var config = eval("(" + $mapBox.attr("mapconfig") + ")");
                            var centerPin = (typeof config.centerPin == "undefined" || config.centerPin);
                            var map = new BingMap({
                                startingMidLat: config.lat,
                                startingMidLong: config.lon,
                                startingZoom: config.zoom || 17,
                                mapView: config.view || VEMapStyle.Hybrid,
                                centerPin: centerPin,
                                showBubble: false,
                                container: $mapBox.attr("id")
                            });
                            map.load();
                            map.hideControls();
                            // Save the map in the element's data for later disposal
                            $mapBox.data("map", map);
                            // Add actions to the view buttons
                            $("a.smallMapRoad", $parent).click(function() { map.setView("r"); });
                            $("a.smallMapAerial", $parent).click(function() { map.setView("a"); });
                            $("a.smallMapHybrid", $parent).click(function() { map.setView("h"); });
                        }
                    });
                }
            });
        }
        setPager(results);
    }

    function updateListingCountError(xmlRequest, textStatus, errorThrown) {
        _submitting = false;
        if (textStatus && textStatus.length > 0) {
            Utils.Logger.warn("Error getting results: " + textStatus);
        }
        if (errorThrown && errorThrown.message.length > 0) {
            Utils.Logger.warn("Error getting results: " + errorThrown.message);
        }
        setCount(null);
        hideAdvisory();
        $("#mapsearch-results-body").unblock();
    }


    function updateListingCount(results) {
        _submitting = false;
        setCount(results);
        _pageInfo.clear();

        var setMapView = _setMapView;
        _setMapView = false;

        // If there are pins, add them to the map
        if (results.lst && results.lst.length > 0) {
            _map.startAddingPins("listing");
            // Add the pins to a new layer
            for (var i = 0, len = results.lst.length; i < len; i++) {
                var lst = results.lst[i];
                if (lst.lat && !isNaN(lst.lat)) {
                    _map.addPin("listing", "1_" + lst.lid, lst.lat, lst.lon, lst.ptid, "Listing", lst.bub);
                }
            }
            _map.endAddingPins("listing", setMapView);
            // Load the grid.
            showListingGrid(results);
            // Add the commingling boards
            var commingling = document.getElementById("mapsearch-commingling");
            var newCLSID = results.board[0].clsid;
            if (commingling) {
                var boardLen = results.board.length;
                var selBoard = document.getElementById("mapsearch-commingling-list");
                if (boardLen > 1 && selBoard) {
                    var oldval = $(selBoard).val();
                    // Remove any existing options
                    selBoard.length = 0;
                    $.each(results.board, function() {
                        var newOpt = new Option(this.clsname, this.clsid);
                        if (this.clsid == oldval) {
                            newOpt.selected = true;
                            newCLSID = oldval;
                        }
                        selBoard.options[selBoard.options.length] = newOpt;
                    });
                    commingling.style.display = 'inline';
                } else {
                    commingling.style.display = 'none';
                }
            } else {
                commingling.style.display = 'none';
            }
            _clsid = newCLSID;
            hideAdvisory();
            // Show the disclaimers
            if (results.disclaimer) {
                $("#mapsearch-disclaimers").html(results.disclaimer);
            } else {
                $("#mapsearch-disclaimers").html("");
            }
            $("#mapsearch-results").show();
            $("#mapsearch-results-paging").show();
        } else { // No listing bubbles, toggle the message
            _map.deleteAllPins("listing");
            if ((results.maxcount > 0 && results.count > results.maxcount) || results.count == 0) {
                showAdvisory();
            } else {
                hideAdvisory();
            }
            $("#mapsearch-disclaimers").html("");
            $("#mapsearch-results").hide();
            $("#mapsearch-results-paging").hide();
        }
        // Add office pins to the map
        if (results.office && results.office.length > 0) {
            // Add the pins to a new layer
            _map.startAddingPins("office");
            for (var j = 0, officelen = results.office.length; j < officelen; j++) {
                var office = results.office[j];
                if (office.latitude && office.latitude != "" && !isNaN(office.latitude)) {
                    _map.addPin("office", "3_" + office.officeid, office.latitude, office.longitude, 3, "Office");
                }
            }
            _map.endAddingPins("office");
        } else {
            _map.deleteAllPins("office");
        }
    }
    
    // Main submit method
    function submit(setMapView, mapState) {
        if (_submitTimer !== null) {
            clearTimeout(_submitTimer);
        }
        if (_submitEnabled && _map.isLoaded()) {
            // Set this so hitting the submit button won't interrupt an onchange in progress
            _submitting = true;
            // Make sure that even if all else fails we re-enable it at some point
            // If it happens to re-enable in the middle of submitting ... well so be it
            setTimeout(function() { _submitting = false; }, 15000);
            // If this is the first time through, see if we need to do an initial location search
            if (_firstSubmit && (!options.startingPolyValue || options.startingPolyValue == "")) {
                _firstSubmit = false;
                var $location = $(getSearchTabSelector(".location"));
                var locationVal = $location.val();
                var locationType;
                if (locationVal && locationVal.length > 0) {
                    // This is the hidden form element that stores the location types for this element
                    // The "rel" attribute says which location element in this tab we're dealing with
                    var $hiddenType = $("input[type=hidden][rel=" + $location.attr("id") + "]", _containers.criteria);
                    // Get the types that we'll be supporting
                    var locationType = $location.attr("locationType");
                    if (typeof (locationType) == "undefined") {
                        locationType = "";
                    }
                    // Get a type embedded in the location
                    var type = extractLocationType(locationVal, locationType);
                    // If no embedded type, use a default type
                    if (type.length === 0) {
                        // If no accepted location types configured, default to address
                        if (!locationType || locationType == "") {
                            type = "Address";
                        } else { // Otherwise default to the first one in the list
                            type = locationType.split(",")[0];
                        }
                    }
                    locationType = type;
                } else {
                    locationVal = $(getSearchTabSelector("input[name=Criteria/ListingNumber]")).val();
                    locationType = "ListingNumber";
                }
                if (locationVal && locationVal.length > 0) {
                    if (locationType.toLowerCase() == "city") {
                        if (locationVal.indexOf(",") == -1 && defaultState && defaultState.length > 0) {
                            locationVal += "," + defaultState;
                        }
                        gotoBoundary("city", locationVal);
                    } else if (locationType.toLowerCase() == "zip code") {
                        gotoBoundary("zip", locationVal);
                    } else {
                        gotoLocation(locationVal, locationType);
                    }
                    return;
                }
            }
            
            // See if we need to fit the map to match the results
            _setMapView = setMapView || false;
            mapState = mapState || _map.getMapState();
            // Remove any special pins
            var searchTab = $("#SearchTab").val();
            if (searchTab != "addressSearch" && searchTab != "mapsearch-criteria-addresssearch") {
                _map.deleteAllPins("address");
            }
            // If there's a polygon on the map, update the Draw toolbar
            if (mapState.PolygonType && mapState.PolygonType.length > 0 && mapState.PolyPoints && mapState.PolyPoints.length > 0) {
                $("#mapsearch-maptoolbar-draw").removeClass("drawing").addClass("clear").html("Clear Search Area");
            }

            // Change the background color of the count div to yellow
            try {
                $(_containers.count).animate({ backgroundColor: "#ffd73b" }, 1000);
            }
            catch (ex) {
                $(_containers.count).css({ backgroundColor: "#ffd73b" });
            }
            // Set the results to gray to indicate they're in process
            $("#mapsearch-results-body").block({ message: null });
            
            // Change the messages to tell the user we're calculating...
            showCalculating();
            
            // Kick off the search ...
            $.ajax({
                // try to leverage ajaxQueue plugin to abort previous requests
                mode: "abort",
                port: "mapsearch",
                type: "POST",
                url: "/" + Utils.AppName + "/Include/AJAX/MapSearch/GetListingPins.aspx",
                data: getFormData(mapState),
                cache: false,
                dataType: "json",
                success: updateListingCount,
                error: updateListingCountError,
                dataFilter: function(data) {
                    if (typeof (JSON) !== 'undefined' && typeof (JSON.parse) === 'function') {
                        return JSON.parse(data);
                    } else {
                        return eval('(' + data + ')');
                    }
                }
            });
            $(document).trigger("criteriaitemchange", [{}]);
            return;
        }
        _submitTimer = setTimeout(function() { submit(setMapView, mapState); }, 100);
    }

    function onMapChange() {
        if (_mapTimer !== null) {
            clearTimeout(_mapTimer);
        }
        if (_submitEnabled && _map.isLoaded()) {
            var mapState = _map.getMapState();
            loadNeighborhoods(mapState);
            submit(false, mapState);
            return;
        }
        _mapTimer = setTimeout(onMapChange, 100);
    }

    function togglePOIIcon(icon, toggleDisplay) {
        var alt, imgUrl;

        if (toggleDisplay) {
            icon.display = !icon.display;
        }

        if (!_poiEnabled) {
            alt = "Points of Interest disabled. Please zoom in to enable.";
            imgUrl = icon.ImageDisabled;
        } else if (icon.display) {
            alt = "Remove " + icon.DisplayName + " Icons from Map";
            imgUrl = icon.ImageOn;
        } else {
            alt = "Display " + icon.DisplayName + " Icons on Map";
            imgUrl = icon.ImageOff;
        }
        
        var $img = $("#poi-icon-" + icon.ShortName);
        if ($img.length > 0) {
            $img.attr({
                alt: alt,
                title: alt,
                src: POIImagePath + "POI/" + imgUrl
            });
        } else {
        $("<img id='poi-icon-" + icon.ShortName + "' style='border: 0; padding: 4px; cursor: pointer;' alt='" + alt + "' title='" + alt + "' src='" + POIImagePath + "POI/" + imgUrl + "' \\>")
            .appendTo("#mapsearch-poi-icons")
            .click(function() {
                togglePOIIcon(icon, true);
                if (icon.display) {
                    _map.showPOI(icon.PinType);
                } else {
                    _map.hidePOI(icon.PinType);
                }
            });
        }
    }

    function showOrClearPOI(show) {
        for (var i = 5; i < 22; i++) {
            BingMap.PinInfo[i].display = show;
            togglePOIIcon(BingMap.PinInfo[i]);
        }
        if (show) {
            _map.showAllPOI();
        } else {
            _map.hideAllPOI();
        }
    }

    function onPOIChange(e) {
        _poiEnabled = e.poiEnabled;
        for (var i = 5; i < 22; i++) {
            togglePOIIcon(BingMap.PinInfo[i]);
        }
    }

    function setListingOfficePOIIcon($span, selected, toggle, click) {
        var pin = $span.data("pin");
        if (toggle) {
            pin.selected = !pin.selected;
        } else {
            pin.selected = selected;
        }
        
        var alt, imgUrl;
        if (pin.selected) {
            alt = "Remove " + pin.name + "s from the Map";
            imgUrl = POIImagePath + "POI/" + pin.pinInfo.ImageOn;
        } else {
            alt = "Add " + pin.name + "s to the Map";
            imgUrl = POIImagePath + "POI/" + pin.pinInfo.ImageOff;
        }
        
        var $img = $("img", $span);
        if ($img.length > 0) {
            $img.attr({
                alt: alt,
                title: alt,
                src: imgUrl
            });
        } else {
            $span.append("<img border='0' style='float: left; margin-right: 3px;' alt='" + alt + "' title='" + alt + "' src='" + imgUrl + "' \\>" + pin.name);
        }
        if (click && pin.onclick && typeof pin.onclick == "function") {
            pin.onclick(pin.selected);
        }
        $span.data("pin", pin);
    }

    function setListingOfficePOIIcons() {
        var pins = [];
        // We look for a collection of checkboxes for statuses - traditional selects are not supported
        $(getSearchTabSelector("input[name='Criteria/Status'][type='checkbox']"), _containers.criteria).each(function() {
            var self = this;
            var statusVal = this.value;
            var statusText = $("label[for='" + this.id + "']", _containers.criteria).text();
            var pinInfo;
            if (!statusText || statusText == "") {
                var next = this.nextSibling;
                while (next) {
                    var v = $.trim(next.nodeType != 1 ? next.nodeValue : $(next).text());
                    if (v != "") {
                        statusText = v;
                        break;
                    }
                    next = next.nextSibling;
                }
            }
            if (statusVal == "1") {
                pinInfo = BingMap.PinInfo[BingMap.PinType.ListingActive];
                if (!statusText || statusText == "") {
                    statusText = "Active";
                }
            } else if (statusVal == "2") {
                pinInfo = BingMap.PinInfo[BingMap.PinType.ListingSold];
                if (!statusText || statusText == "") {
                    statusText = "Sold";
                }
            } else if (statusVal == "5") {
                pinInfo = BingMap.PinInfo[BingMap.PinType.ListingPending];
                if (!statusText || statusText == "") {
                    statusText = "Pending";
                }
            }
            pins.push({
                val: statusVal,
                name: statusText,
                pinInfo: pinInfo,
                selected: this.checked,
                onclick: function(isActive) {
                    self.checked = isActive;
                    submit();
                }
            });
        });
        // If we don't have anything from there, always include an active icon
        if (pins.length === 0) {
            pins.push({
                val: 1,
                name: "Listing",
                pinInfo: BingMap.PinInfo[BingMap.PinType.ListingActive],
                selected: _map.pinsAreVisible("listing"),
                onclick: function(isActive) {
                    if (isActive) {
                        _map.showPins("listing");
                    } else {
                        _map.hidePins("listing");
                    }
                }
            });
        }
        // Include an office icon if we're getting them from the server
        if (options.getOfficePins) {
            pins.push({
                val: 0,
                name: "Office",
                pinInfo: BingMap.PinInfo[BingMap.PinType.Office],
                selected: _map.pinsAreVisible("office"),
                onclick: function(isActive) {
                    if (isActive) {
                        _map.showPins("office");
                    } else {
                        _map.hidePins("office");
                    }
                }
            });
        }

        // Loop through our statuses and add the icons to the list
        $("#mapsearch-poi-listingoffice").html("");
        for (var i = 0; i < pins.length; i++) {
            var pin = pins[i];
            var $span = $("<span id='poi-icon-status-" + pin.val + "' style='float: left; padding: 4px; cursor: pointer;'></span>")
                .data("pin", pin)
                .click(function() { setListingOfficePOIIcon($(this), false, true, true); })
                .appendTo("#mapsearch-poi-listingoffice");
            setListingOfficePOIIcon($span, pin.selected);
        }
    }
    
    function updateSortIcons() {
        $("#mapsearch-results-header a[sort]").each(function() {
            var $this = $(this);
            var sorts = eval($this.attr("sort"));
            // Remove any current indicators
            $this.text($this.text().replace("\u25b2", "").replace("\u25bc", ""));
            // Add an indicator to the currently sorted column
            if (_activeSortID == sorts[0][0]) {
                $this.text($this.text() + "\u25b2");
            } else if (_activeSortID == sorts[1][0]) {
                $this.text($this.text() + "\u25bc");
            }
        });
    }

    function updateListingStatusMessage() {
        var statusHtml = "";
        $(":input[name='Criteria/Status'][checked]", _containers.criteria).each(function() {
            if (this.value == "1") {
                statusHtml += "Active,";
            } else if (this.value == "5") {
                statusHtml += "Pending,";
            } else if (this.value == "2") {
                statusHtml += "Sold,";
            }
        });
        if (statusHtml.length > 0) {
            statusHtml = statusHtml.substring(0, statusHtml.length - 1);
            $("#selectedStatus").html(statusHtml).attr("title", statusHtml);
        }
    }

    function getListingHtml(first) {
        $("#mapsearch-results-body").block({ message: null });

        var data = {
            searchid: _searchid,
            view: _activeView,
            first: first || 0,
            count: 10,
            clsid: _clsid,
            ListingSortID: _activeSortID
        };
        // Special layout overrides for preview functionality
        if (_qs.contains("LayoutID")) {
            data.LayoutID = _qs.get("LayoutID");
            data.LayoutVersion = _qs.get("LayoutVersion");
        }

        $.ajax({
            mode: "abort",
            port: "listingshtml",
            type: "POST",
            url: "/" + Utils.AppName + "/Include/AJAX/MapSearch/GetListings.aspx",
            data: data,
            cache: false,
            dataType: "json",
            dataFilter: function(data) {
                if (typeof (JSON) !== 'undefined' && typeof (JSON.parse) === 'function') {
                    return JSON.parse(data);
                } else {
                    return eval('(' + data + ')');
                }
            },
            error: updateListingCountError,
            success: function(results) {
                results.count = _pageInfo.resultCount;
                results.page = _pageInfo.page;
                showListingGrid(results);
            }
        });
    }

    function clearCriteria() {
        _submitEnabled = false;

        $(":input", _containers.criteria).each(function() {
            var type = this.type, tag = this.tagName.toLowerCase(), name = this.name;
            if (type == 'text' || type == 'password' || tag == 'textarea' || name == 'Criteria/LocationType') {
                this.value = '';
            } else if (type == 'checkbox') {
                this.checked = false;
            } else if (type == 'radio' && name.indexOf('Groups') == -1) {
                this.checked = false;
            } else if (tag == 'select') {
                this.selectedIndex = 0;
                if (name == "Criteria/ListingTypeID") {
                    _self.toggleListingType(this);
                }
                if (name == "dd_Features") {
                    _self.toggleFeature(this);
                }
            }
        });

        // Make sure we have at least one status enabled
        if ($(":input[name='Criteria/Status']", _containers.criteria).length > 0) {
            if ($(":input[name='Criteria/Status'][checked]", _containers.criteria).length === 0) {
                $(":input[name='Criteria/Status'][value='1']", _containers.criteria).attr("checked", true);
                $(":input[name='Criteria/Status'][id='mapsearch-criteria-status-active']", _containers.criteria).attr("checked", true);
                updateListingStatusMessage();
            }
        }
        
        // Remove any shapes
        _map.clearPolygons();

        // Clear the last submitted
        _lastLocationSubmitted = "";

        _submitEnabled = true;

        // Let listeners know we're done (such as the search summary)
        $(document).trigger("criteriachange", [{ activeTab: $("#SearchTab").val()}]);

        // Go to the default map coordinates.  This will submit the search.
        _map.setCenterAndZoom(options.defaultMidLat, options.defaultMidLong, options.defaultZoom);
    }

    function closeBirdseye() {
        $("#mapsearch-birdseye").hide();
        _map.showControls();
        var map = $("#mapsearch-birdseye").data("map");
        if (map) {
            map.dispose();
            map = null;
        }
        $("#mapsearch-birdseye-map").unbind("birdseyeavailable").unbind("mapviewnotsupported");
    }

    function toggleOpenHouse() {
        var checked = $("input[name=HardCodedCriterion][value=349]:checked", _containers.criteria).length > 0;
        $("input[name*=OpenHouse]").each(function() { this.disabled = !checked; });
    }

    function addControlEvents() {
        // Add any sort options from the header that are missing from the select
        var sortList = document.getElementById("mapsearch-sort-list");
        _activeSortID = $(sortList).val();
        $(sortList).change(function() {
            _activeSortID = $(this).val();
            updateSortIcons();
            submit();
        });
        $("#mapsearch-results-header a[sort]").each(function() {
            var $this = $(this);
            var sorts = eval($this.attr("sort"));
            // Add any missing sort options to the dropdown
            if ($("option[value=" + sorts[0][0] + "]", sortList).length === 0) {
                sortList.options[sortList.options.length] = new Option(sorts[0][1], sorts[0][0]);
            }
            if ($("option[value=" + sorts[1][0] + "]", sortList).length === 0) {
                sortList.options[sortList.options.length] = new Option(sorts[1][1], sorts[1][0]);
            }
            // Set the pointer
            $this.css("cursor", "pointer");
            // Add the click handler
            $this.click(function() {
                if (_activeSortID == sorts[0][0]) {
                    _activeSortID = sorts[1][0];
                } else {
                    _activeSortID = sorts[0][0];
                }
                $(sortList).val(_activeSortID);
                updateSortIcons();
                submit();
            });
        });
        // Add an indicator to the currently sorted column
        updateSortIcons();

        // Set the button actions
        $("#mapsearch-commingling-list").change(function() {
            _clsid = $(this).val();
            submit(false);
        });

        $("div", _containers.viewTabs).click(function() {
            var $this = $(this);
            var oldView = _activeView;
            _activeView = $this.attr("id").replace("mapsearch-viewtab-", "");
            $(".ms_tab_on", _containers.viewTabs).removeClass("ms_tab_on").addClass("ms_tab_off");
            $this.removeClass("ms_tab_off").addClass("ms_tab_on");
            getListingHtml(_pageInfo.page * _pageInfo.resultsPerPage);
            if (oldView == "map" || _activeView == "map") {
                $("#mapsearch-mainmap-toolbar,#mapsearch-results-header").toggle();
            }
            showAdvisory();
        });

        $("#mapsearch-birdseye-close").click(closeBirdseye);

        $("#mapsearch-advisory-box").mouseover(function() {
            positionAdvisory(true);
        });

        // Toolbar events
        $("#mapsearch-maptoolbar-expand").click(function() {
            var expand = ($("#mapsearch-toolbar-expand-input").val() == "true");
            var expandText;
            var height = $("#mapsearch-mainmap").height();
            if (expand) {
                expandText = "Expand Map";
                height -= options.mapExpandDiff;
            } else {
                height += options.mapExpandDiff;
                expandText = "Contract Map";
            }
            _map.resize($("#mapsearch-maptoolbar").width(), height);
            $("#mapsearch-toolbar-expand-text").text(expandText);
            $("#mapsearch-toolbar-expand-input").val(!expand);
        });
        $("#mapsearch-maptoolbar-display input").click(function() {
            if (this.checked) {
                _map.showAllPins();
            } else {
                _map.hideAllPins();
            }
        });
        $("#mapsearch-maptoolbar-draw").click(function() {
            if ($(this).is(".drawing")) {
                _self.endDrawing(true);
            } else if ($(this).is(".clear")) {
                _self.clearDrawing();
            } else {
                _self.startDrawing();
            }
        });
        $("#mapsearch-maptoolbar-poi").click(function() {
            $("#mapsearch-poi").toggle("slow");
        });
        $("#mapsearch-poi-close").click(function() {
            $("#mapsearch-poi").hide("slow");
        });
        $("#mapsearch-poi-show").click(function(event) {
            event.preventDefault();

            showOrClearPOI(true);
        });
        $("#mapsearch-poi-clear").click(function(event) {
            event.preventDefault();
            showOrClearPOI(false);
        });
        $("#mapsearch-mainmap").bind("polypointchange", function(e) {
            if (e.tipID == 1) {
                setAdvisoryText("You are in Drawing mode.", "Click on the starting point of your search area to start drawing.");
            } else if (e.tipID == 2) {
                setAdvisoryText("Click on the next point.", "You can click on \"Cancel Drawing\" at any time to come out of drawing mode.");
            } else if (e.tipID == 3) {
                setAdvisoryText("Now continue drawing your search area ...", "OR <a href='javascript:;' onclick='Search.endDrawing()'>click here</a> to end drawing.");
            }
        });
    }
    
    function gotoLocation(loc, locType) {
        if (!loc) {
            loc = "";
        }

        // Clear out any boundary searches
        _map.clearPolygons();

        // Find out if we've changed search tabs since the last time we changed locations
        // If it has, then we're going to change to the best view no matter what
        var searchTab = $("#SearchTab").val();
        var searchTabChanged = (searchTab != _lastLocationSearchTab);
        _lastLocationSearchTab = searchTab;

        if (loc == "") {
            _lastLocationSubmitted = "";
            submit(searchTabChanged);
            return;
        }
        if (_lastLocationSubmitted == loc.toLowerCase() && !searchTabChanged) {
            return;
        }
        _lastLocationSubmitted = loc.toLowerCase();
        // The search tab has changed, or the location has changed, so we're going to submit and fit the results
        if (locType.toLowerCase() == "address") {
            if ($("#" + searchTab + " :input[name=Criteria/FilterByAddress]").val() == "1") {
                submit(true);
            } else {
                _map.addAddressPin(loc);
            }
        } else {
            submit(true);
        }
    }

    function gotoBoundary(boundaryType, boundaryVal) {
        if (!boundaryVal) {
            boundaryVal == "";
        }
        boundaryVal = boundaryVal.toString().trim();
        if (boundaryVal == "") {
            if (_map.getMapState().PolygonType == boundaryType) {
                _map.clearPolygons();
            }
            // If we're clearing the zip and we have a city value, then go there (legacy fields)
            var city = $("input[name=Criteria/City]", _containers.criteria).val() || "";
            if (boundaryType == "zip" && city.length > 0) {
                boundaryType = "city";
                boundaryVal = city;
            } else {
                // Clear all location types
                _lastLocationSubmitted = "";
                submit(false);
                return;
            }
        }
        // BOET10402
        if (boundaryVal.toLowerCase() == _lastLocationSubmitted) {
            return;
        }
        _lastLocationSubmitted = boundaryVal.toLowerCase();
        // We have a hierarchy of boundaries - City -> Neighborhood -> Zip
        var neighborhood = $("#selNeighborhood").val() || "";
        var zip = $("input[name=Criteria/ZipCodeAdvanced]", _containers.criteria).val() || "";
        if ((boundaryType == "city" && (neighborhood.length > 0 || zip.length > 0)) || (boundaryType == "neighborhood" && zip.length > 0)) {
            submit(false);
        } else {
            _map.gotoPoly(boundaryType, boundaryVal);
        }
    }
    
    function formatLocationItem(data, includeType) {
        var item = "";
        if (data) {
            item = data.Name;
            if (data.City && data.City.length > 0) {
                item += ", " + data.City;
            }
            if (data.State && data.State.length > 0) {
                item += ", " + data.State;
            }
            if (includeType) {
                item += " (" + data.Type + ")";
            }
        }

        return item;
    }

    function extractLocationType(location, acceptedLocationTypes) {
        var matches = location.match(/\((.*?)\)/);
        var match = "";
        // If we got matches, take the last one.
        // This accounts for locations like Los Angeles (County) (School District)
        if (matches && matches.length > 0) {
            match = matches[matches.length - 1];
        }
        if (!acceptedLocationTypes || acceptedLocationTypes.length === 0 || acceptedLocationTypes.toLowerCase().indexOf(match.toLowerCase()) != -1) {
            return match;
        } else {
            return "";
        }
    }

    function criteriaOnLoad() {
        _displaySort = !(document.getElementById("SearchVendor") && document.getElementById("SearchVendor").value.length > 0);
        if (_displaySort) {
            $("#mapsearch-sort").show();
        } else {
            $("#mapsearch-sort").hide();
        }

        // Dynamically add in another set of clear & submit buttons above the MORE SEARCH OPTIONS link; Uses the same base HTML as exists in SearchContainer.ascx for the same buttons.
        $(".toggleadvanced").before("<div id='mapsearch-criteria-actions-2-container' style='display: none;'><div id='mapsearch-criteria-actions-2'><div class='button-clear'>Clear Criteria</div><div class='button-submit ms_button1'><span class='mapsearch-button-tab-icon'></span>Search</div><div class='clearfloats'></div></div><div class='mapsearch-criteria-spacer'></div></div>");

        // Attach the events to the clear & submit buttons
        $(".button-clear", _containers.criteriaForm).click(clearCriteria);
        $(".button-submit", _containers.criteriaForm).click(function() {
            if (!_submitting) {
                submit(false);
            }
        });

        // If there's a search tab in the layout (legacy) remove it, we already have one in the main control
        $("input[name=SearchTab]", _containers.criteria).remove();
        _self.toggleCriteria();

        // Toggle the advanced search criteria
        $(".toggleadvanced").click(function() {
            toggleAdvancedCriteria();
        });

        // Make sure the property types are set correctly
        $("select[name=Criteria/ListingTypeID]", _containers.criteria).each(function() {
            _self.toggleListingType(this);
        });

        // OK to submit before attaching events
        _submitEnabled = true;

        // Fix any background images
        $(_containers.criteria).pngFix();

        // Add onchange events to form elements, allowing for layout-defined overrides
        $(":input[name]", _containers.criteria).each(function() {
            // ListingNumber is not a 'location' but it does the best map view thing,
            // so we use the gotoLocation method to take care of this
            if (this.name == "Criteria/ListingNumber") {
                $(this).unbind("change");
                $(this).change(function() { gotoLocation(this.value, "ListingNumber"); });
            } else if (this.type == "checkbox" && !this.onclick) {
                $(this).click(function() { _self.onChangeSubmit(this); });
            } else if (this.type != "checkbox" && !this.onchange && !$(this).is(".location")) {
                $(this).change(function() { _self.onChangeSubmit(this); });
            }
            $(this).focus(function() { if (this.select) { this.select(); } });
        });

        $("select.featuresdd[not(onchange)]", _containers.criteria).change(function() {
            var $featureList = $("#" + $(this).val(), _containers.criteria);
            $featureList.prevAll().hide();
            $featureList.nextAll().hide();
            $featureList.show();
        });

        // Location autocomplete
        $(".location", _containers.criteria).each(function() {
            var $el = $(this);
            // This is the hidden form element that stores the location types for this element
            // The "rel" attribute says which location element in this tab we're dealing with
            var $hiddenType = $("input[type=hidden][rel=" + $el.attr("id") + "]", _containers.criteria);
            // Get the types that we'll be supporting
            var locationType = $el.attr("locationType");
            if (typeof (locationType) == "undefined") {
                locationType = "";
            }
            // We show the location type in the textbox if we're supporting more than one type ("" = all types)
            var showType = (locationType == "" || locationType.indexOf(",") != -1);
            // If so, populate the initial textbox with the type, if we know it and it's not already there
            if (showType) {
                var initialLocationType = $hiddenType.val();
                if (initialLocationType && initialLocationType.length > 0 && $el.val().indexOf("(" + initialLocationType + ")") == -1) {
                    $el.val($el.val() + " (" + initialLocationType + ")");
                }
            }
            // Setup the autocomplete
            $el.autocomplete("/" + Utils.AppName + "/Include/AJAX/MapSearch/GetLocations.aspx", {
                dataType: "json",
                minChars: 2,
                width: "auto",
                extraParams: { type: locationType },
                max: 50,
                matchSubset: false,
                parse: function(data) {
                    var parsed = [];
                    // Add the json results
                    var lastCity = -1;
                    for (var i = 0, len = data.length; i < len; i++) {
                        var d = data[i];
                        if (d.Type.toLowerCase() == "city") {
                            lastCity = i;
                        }
                        parsed.push({
                            data: d,
                            value: d.Name,
                            result: formatLocationItem(d, showType)
                        });
                    }
                    // Always put an Address location type in the results, if we're supporting addresses,
                    // and there's not already a supported embedded type in the textbox
                    if (locationType == "" || (locationType.indexOf(",") != -1 && locationType.toLowerCase().indexOf("address") != -1)) {
                        var val = $el.val().trim();
                        if (val.length > 0) {
                            var embeddedType = extractLocationType(val, locationType);
                            if (embeddedType.length === 0) {
                                var addressData = { Name: val, Type: "Address" };
                                parsed.splice(lastCity + 1, 0, { data: addressData, value: addressData.Name, result: formatLocationItem(addressData, showType) });
                            }
                        }
                    }
                    return parsed;
                },
                formatItem: function(data) { return "<nobr>" + formatLocationItem(data, showType) + "</nobr>"; }
            })
        .result(function(event, data, formatted) {
            // If there's no data that means we got here onblur,
            // and we need to add a type for disambiguation
            var embeddedZip = "";
            if (!data) {
                var val = $el.val().trim();
                if (val.length > 0) {
                    // Get a type embedded in the location
                    var type = extractLocationType(val, locationType);
                    // If no embedded type, use a default type
                    if (type.length === 0) {
                        // If no accepted location types configured, try to figure out a type
                        var regexZip = /^\d{5}$/;
                        var valWords = val.replace(",", " ").trim().replace(/\s+/g, " ").split(" ");
                        if (valWords.length == 1) {
                            if (regexZip.test(val)) {
                                type = "Zip Code";
                            } else {
                                type = "Address";
                            }
                        } else {
                            // The last word is a zip
                            var lastWord = valWords[valWords.length - 1];
                            if (regexZip.test(lastWord)) {
                                // If there's no comma before the zip, add one, to make it easier for the address parser
                                if (val.indexOf(",") == -1) {
                                    valWords.splice(valWords.length - 1, 0, ",");
                                    val = valWords.join(" ").replace(" , ", ", ");
                                }
                                type = "Address";
                                embeddedZip = lastWord;
                            } else if (lastWord.length == 2 && $.inArray(lastWord.toUpperCase(), Utils.Lookups.stateCodes) != -1) { // The last word is a state?
                                // If there's no comma before the state, add one, to make it easier for the address parser
                                if (val.indexOf(",") == -1) {
                                    valWords.splice(valWords.length - 1, 0, ",");
                                    val = valWords.join(" ").replace(" , ", ", ");
                                }
                                // If there's only one comma, assume it's a city
                                if (val.split(",").length == 2) {
                                    type = "City";
                                } else {
                                    type = "Address";
                                }
                            } else {
                                type = "Address";
                            }
                        }
                        // Make sure our new default is in the list of acceptable types
                        if (locationType && locationType != "") {
                            var acceptable = false;
                            var locationTypes = locationType.split(",");
                            for (var i = 0; i < locationTypes.length; i++) {
                                if (type.toLowerCase() == locationTypes[i].toLowerCase()) {
                                    acceptable = true;
                                    break;
                                }
                            }
                            if (!acceptable) {
                                type = locationType.split(",")[0];
                            }
                        }
                        // If more than one type is acceptable, embed it in the location
                        if (locationType == "" || locationType.indexOf(",") != -1) {
                            $el.val(val + " (" + type + ")");
                        }
                    }
                    data = { Name: val, Type: type };
                }
            }
            if (data && data.Type) {
                // Set the hidden location type
                $hiddenType.val(data.Type);
                // Set the cursor to before the type
                var last = $el.val().lastIndexOf("(");
                if (last != -1 && this.setSelectionRange) {
                    this.setSelectionRange(last - 1, last - 1);
                }

                // Take the proper action - the first ones are for showing boundaries, the last one will set the map view to fit
                var gotoZip = false;
                if (embeddedZip.length > 0) {
                    gotoZip = true;
                } else {
                    embeddedZip = data.Name;
                }
                if (data.Type.toLowerCase() == "city") {
                    var city = data.Name;
                    if (data.State && data.State.length > 0) {
                        city += "," + data.State;
                    }
                    gotoBoundary("city", city);
                } else if (gotoZip || data.Type.toLowerCase() == "zip code") {
                    gotoBoundary("zip", embeddedZip);
                } else if (data.Type.toLowerCase() == "neighborhood") {
                    gotoBoundary("neighborhood", data.BID);
                } else if (data.BID && data.BID > 0) {
                    gotoBoundary("boundary", data.BID);
                } else {
                    var name = data.Name;
                    if (data.State && data.State.length > 0) {
                        name += "," + data.State;
                    }
                    gotoLocation(name, data.Type);
                }
            }
        })
        .keydown(function(event) {
            // Alphanumeric
            if (event.keyCode > 47 && event.keyCode < 91) {
                // Clear the type when new stuff is entered
                $hiddenType.val("");
                var val = $el.val();
                if (val && val.length > 0) {
                    var lastIndex = val.lastIndexOf("(");
                    if (lastIndex != -1) {
                        $el.val(val.substring(0, lastIndex).trim());
                    }
                }
            }
        })
        .focus(function() {
            // Clear the type when new stuff is entered
            $hiddenType.val("");
            var val = $el.val();
            if (val && val.length > 0) {
                var lastIndex = val.lastIndexOf("(");
                if (lastIndex != -1) {
                    $el.val(val.substring(0, lastIndex).trim());
                }
            }
            this.select();
        })
        .blur(function() {
            $el.search();
        });
        });
        // MinPrice/MaxPrice autocompletes
        $(":input[name*=Price]", _containers.criteria).each(function() {
            if (this.value != "") {
                this.value = "$" + Utils.Format.addCommas(this.value);
            }
            $(this).autocomplete("numeric", {
                maxChars: 8,
                formatResult: function(row) { return "$" + Utils.Format.addCommas(row); },
                formatItem: function(row) { return "$" + Utils.Format.addCommas(row); },
                highlight: false,
                selectFirst: false
            })
        .result(function(event, data, formatted) {
            $(this).change();
        });
        });
        // MinSqFt/MaxSqFt autocompletes
        $(":input[name*=SquareFootage]", _containers.criteria).each(function() {
            this.value = Utils.Format.addCommas(this.value);
            $(this).autocomplete("numeric", {
                maxChars: 5,
                formatResult: function(row) { return Utils.Format.addCommas(row); },
                formatItem: function(row) { return Utils.Format.addCommas(row); },
                highlight: false,
                selectFirst: false
            })
        .result(function(event, data, formatted) {
            $(this).change();
        });
        });
        // MinLotSize/MaxLotSize autocompletes
        $(":input[name*=Acreage]", _containers.criteria).each(function() {
            this.value = Utils.Format.addCommas(this.value);
            $(this).autocomplete("numeric", {
                maxChars: 7,
                formatResult: function(row) { return Utils.Format.addCommas(row); },
                formatItem: function(row) { return Utils.Format.addCommas(row); },
                highlight: false,
                selectFirst: false
            })
        .result(function(event, data, formatted) {
            $(this).change();
        });
        });
        // City autocomplete
        $(":input[name='Criteria/City']", _containers.criteria)
        .autocomplete("/" + Utils.AppName + "/Include/AJAX/MapSearch/GetLocations.aspx", {
            dataType: "json",
            extraParams: { type: "City" },
            minChars: 2,
            max: 50,
            width: "auto",
            cacheLength: 50,
            parse: function(data) {
                var parsed = [];
                for (var i = 0, len = data.length; i < len; i++) {
                    var d = data[i];
                    parsed[parsed.length] = {
                        data: d,
                        value: d.Name,
                        result: formatLocationItem(d, false)
                    };
                }
                return parsed;
            },
            formatItem: function(data) { return "<nobr>" + formatLocationItem(data, false) + "</nobr>"; },
            delay: 100
        })
        .result(function(event, data, formatted) {
            if (!data) {
                var val = $(this).val();
                if (val && val.length > 0) {
                    var state = defaultState;
                    var comma = val.lastIndexOf(",");
                    if (comma != -1) {
                        state = val.substring(comma + 1);
                        val = val.substring(0, comma);
                    }
                    data = { Name: val, Type: "City", State: state };
                    $(this).val(val + ", " + state);
                } else {
                    data = { Name: "" };
                }
            }
            var city = data.Name;
            if (data.State && data.State.length > 0) {
                city += "," + data.State;
            }
            gotoBoundary("city", city);
        })
        .blur(function() {
            $(this).search();
        });

        // Open house date pickers
        $("input[name=HardCodedCriterion][value=349]", _containers.criteria).click(toggleOpenHouse);
        $("input[name*=OpenHouse]", _containers.criteria).datepicker();
        toggleOpenHouse();
        
        // Status pseudo-dropdown
        updateListingStatusMessage();

        // Status checkboxes
        $("input[name=Criteria/Status][type=checkbox]", _containers.criteria).click(function() {
            var $span = $("#poi-icon-status-" + this.value.toLowerCase());
            if ($span.length > 0) {
                setListingOfficePOIIcon($span, this.checked);
            }
        });

        // If we have any advanced criteria populated, expand the div
        $(".advanced :input").each(function() {
            // If no ele name then continue, some form elements may not be needed, we take only those with a name
            if (!this.name) {
                return true;
            }

            if (this.type == "hidden") {
                return true;
            }

            // If the value is empty, don't include (to cut down on space)
            if (this.value.length === 0) {
                return true;
            }

            // Skip the element if its type radio or checkbox and is not "checked"
            if ((this.type == "radio" || this.type == "checkbox") && !this.checked) {
                return true;
            }

            // Skip disabled elements
            if (this.disabled) {
                return true;
            }

            // Skip radio buttons that used for matching rules
            if (this.type == "radio" && this.name.indexOf("Groups") === 0) {
                return true;
            }

            // Skip status if only active is selected
            if (this.name == "Criteria/Status" && this.value.indexOf("2") == -1 && this.value.indexOf("5") == -1) {
                return true;
            }


            // If we got here, we have some data, expand it
            showAdvancedCriteria();
            /*
            $(this).closest(".advanced").show();
            $(this).closest(".searchTab").find(".toggleadvanced span.arrow").removeClass("arrow-left").addClass("arrow-down");
            */
            return false;
        });

        // Let listeners know we're done (such as the search summary)
        $(document).trigger("criteriachange", [{ activeTab: $("#SearchTab").val()}]);

        // ... and expand the accordion
        var $accordion = $('#mapsearch-left-accordion');
        if ($accordion.length > 0) {
            $accordion.accordion('option', 'collapsible', false);
            $accordion.accordion('activate', 0);
        }
    }

    function dispose() {
        if (!_disposed) {
            _map.dispose();
            _map = null;
            options = null;
            unbindListingGrid();
            var birdseyeMap = $("#mapsearch-birdseye").data("map");
            if (birdseyeMap) {
                birdseyeMap.dispose();
                birdseyeMap = null;
            }
            _disposed = true;
        }
    }

    function toggleAdvancedCriteria() {
        var $advanced = $(".advanced", _containers.criteriaForm);
        if ($advanced.is(":visible")) {
            hideAdvancedCriteria();
        } else {
            showAdvancedCriteria();
        }
    }

    function showAdvancedCriteria() {
        var $advanced = $(".advanced", _containers.criteriaForm);
        $advanced.show();
        $("span.arrow", _containers.criteriaForm).removeClass("arrow-left").addClass("arrow-down");
        $("#mapsearch-criteria-actions-2-container").show();
    }

    function hideAdvancedCriteria() {
        var $advanced = $(".advanced", _containers.criteriaForm);
        $advanced.hide();
        $("span.arrow", _containers.criteriaForm).removeClass("arrow-down").addClass("arrow-left");
        $("#mapsearch-criteria-actions-2-container").hide();
    }
    
    // Public functions
    this.load = function() {
        // Make sure the defaults are set if this is the first time through
        options = $.extend({}, _defaultOptions, options);

        // Don't submit while loading
        _submitEnabled = false;

        // Subscribe to the map change event and poi change events
        $("#mapsearch-mainmap").bind("mapchange", onMapChange);
        $("#mapsearch-mainmap").bind("poichange", onPOIChange);

        // Create the map
        _map = new BingMap(options);
        _map.load();

        // Setup the initial state of the POI icons
        for (var i = 5; i < 22; i++) {
            togglePOIIcon(BingMap.PinInfo[i]);
        }
        $(document).bind("criteriachange", function(e, eventData) {
            setListingOfficePOIIcons(eventData.activeTab);
        });

        // Store some references to containers for faster lookups
        _containers = {
            criteria: document.getElementById("mapsearch-criteria-layout"),
            criteriaForm: document.getElementById("mapsearch-criteria"),
            count: document.getElementById("mapsearch-count"),
            viewTabs: document.getElementById("mapsearch-viewtabs")
        };

        // Add non-criteria events
        addControlEvents();

        // Window events
        // The submission to resize the map is delayed
        // to account for firing multiple resize events along the way
        $(window).resize(function() {
            if (_resizeTimer) {
                clearTimeout(_resizeTimer);
            }

            _resizeTimer = setTimeout(function() {
                if (_map) {
                    _map.resize($("#mapsearch-maptoolbar").width());
                }
                positionAdvisory();
                _resizeTimer = null;
            }, 100);
        });
        $(window).unload(dispose);

        // Bind after the criteria loads so that RECos can use the info-hover in their criteria
        $(document).bind("criteriachange", function() {
            $("#mapsearch-container .info-hover").hoverinfo();
        });
        $("#mapsearch-directions :input[title]").titlelabel();

        // Setup the request for the criteria
        var url = '/' + Utils.AppName + '/include/ajax/mapsearch/getsearchcriteria.aspx';
        var qs = [];
        // Special layout overrides for preview functionality
        if (_qs.contains('LayoutID')) {
            qs.push("LayoutID=" + _qs.get("LayoutID"));
            qs.push("LayoutVersion=" + _qs.get("LayoutVersion"));
        }
        // Send the current ListingSearchID along if there is one
        if (_qs.contains('ListingSearchID')) {
            qs.push("ListingSearchID=" + _qs.get("ListingSearchID"));
        }
        // Send the current search parameter along if there is one
        if (_qs.contains('search')) {
            qs.push("search=" + _qs.get("search"));
        }
        if (qs.length > 0) {
            url += "?" + qs.join("&");
        }
        // Load the criteria and attach the events to the elements
        $(_containers.criteria).load(url, qs, criteriaOnLoad);
    };
    
    // Allows updating the search options after initialization, such as in the criteria
    this.setOptions = function(opts) {
        // Extend the existing options with the incoming options
        if (opts) {
            options = $.extend({}, options, opts);
            _map.setOptions(options);
            _pageInfo.resultsPerPage = options.resultsPerPage || _pageInfo.resultsPerPage;
        }
    };

    this.startDrawing = function() {
        $("#mapsearch-maptoolbar-draw").addClass("drawing").html("Cancel Drawing");
        // Clear out legacy neighborhood selection
        if (document.getElementById('selNeighborhood')) {
            document.getElementById('selNeighborhood').value = "";
            document.getElementById('Neighborhood').selectedIndex = 0;
        }
        // Clear location box
        $(getSearchTabSelector(".location")).val("");
        $(getSearchTabSelector("input[rel][type=hidden]")).val("");
        _map.startDrawing();
    };

    this.endDrawing = function(cancel) {
        if (cancel) {
            $("#mapsearch-maptoolbar-draw").removeClass("drawing").html("Draw Search Area");
        } else {
            $("#mapsearch-maptoolbar-draw").removeClass("drawing").addClass("clear").html("Clear Search Area");
        }
        _map.endDrawing(cancel);
    };

    this.clearDrawing = function() {
        $("#mapsearch-maptoolbar-draw").removeClass("clear").html("Draw Search Area");
        _map.clearPolygons(true);
        // If this is a neighborhood search, clear the location box so it doesn't get submitted
        $(getSearchTabSelector("input[rel][type=hidden]")).each(function() {
            var type = $(this).val();
            if (type.toLowerCase() == "neighborhood") {
                $("#" + $(this).attr("rel")).val("");
                _lastLocationSubmitted = "";
            }
        });
    }
    
    this.toggleFeature = function(obj) {
        if (obj) {
            for (var i = 0, len = obj.length; i < len; i++) { // hide all
                $("#feature_" + i).hide();
            }
            $("#feature_" + obj.selectedIndex).show(); // display selected
        }
    };

    this.toggleListingType = function(obj, dontSubmit) {
        if (obj) {
            var inputs, name, i, len;
            for (i = 0, len = obj.length; i < len; i++) {// hide all
                // Set the checkboxes to an invalid name so they're not used
                // Setting them to disabled doesn't seem to work
                inputs = document.getElementById('propertyType_' + i).getElementsByTagName('input');
                for (var j = 0, lenj = inputs.length; j < lenj; j++) {
                    name = inputs[j].getAttribute('name');
                    if (name.toLowerCase() == 'criteria/propertytypeid') {
                        inputs[j].setAttribute('name', 'Criteria/PropertyTypeID_X');
                    }
                    if (name.toLowerCase() == 'criteria/defaultpropertytypeid') {
                        inputs[j].setAttribute('name', 'Criteria/DefaultPropertyTypeID_X');
                    }
                }
                hide('propertyType_' + i);
            }
            // Set the checkboxes back to a valid name
            inputs = document.getElementById('propertyType_' + obj.selectedIndex).getElementsByTagName('input');
            for (i = 0, len = inputs.length; i < len; i++) {
                name = inputs[i].getAttribute('name');
                if (name.toLowerCase() == 'criteria/propertytypeid_x') {
                    inputs[i].setAttribute('name', 'Criteria/PropertyTypeID');
                }
                if (name.toLowerCase() == 'criteria/defaultpropertytypeid_x') {
                    inputs[i].setAttribute('name', 'Criteria/DefaultPropertyTypeID');
                }
            }
            $("input[name='Criteria/PropertyTypeID']").blur();
            display('propertyType_' + obj.selectedIndex); // display selected
            // Submit the change
            if (typeof (dontSubmit) == 'undefined' || !dontSubmit) {
                submit();
            }
        }
    };

    this.setListingStatus = function(obj) {
        // Update the status message
        updateListingStatusMessage();

        // And submit the search
        submit();
    };

    this.toggleCriteria = function(activeTab) {
        var passedInActiveTab = activeTab;
        var $searchTab = $("#SearchTab");
        if ($searchTab.length === 0) {
            return;
        }

        var isLegacyCriteria = ($("#basicSearch").length > 0);
        var newBasicSearch = $(".searchtab", _containers.criteria).eq(0).attr("id");
        var expandAdvanced = false;

        // have to deal with legacy search tab values, such as in simple search
        if (!activeTab) {
            var searchTabVal = $searchTab.val();
            if (searchTabVal == "2" || searchTabVal == "advanced" || searchTabVal == "advancedSearch") {
                if (isLegacyCriteria) {
                    activeTab = "advancedSearch";
                } else {
                    activeTab = newBasicSearch;
                    expandAdvanced = true;
                }
            } else if (searchTabVal == "3" || searchTabVal == "mlsID" || searchTabVal == "mlsIDSearch") {
                if (isLegacyCriteria) {
                    activeTab = "mlsIDSearch";
                } else {
                    activeTab = $(".searchtab:has(input[name=Criteria/ListingNumber])", _containers.criteria).eq(0).attr("id");
                }
            } else if (searchTabVal == "4" || searchTabVal == "address" || searchTabVal == "addressSearch") {
                if (isLegacyCriteria) {
                    activeTab = "addressSearch";
                } else {
                    activeTab = $(".searchtab:has(input[name=Criteria/FullAddress])", _containers.criteria).eq(0).attr("id");
                }
            } else if (searchTabVal == "5" || searchTabVal == "school" || searchTabVal == "schoolSearch") {
                if (isLegacyCriteria) {
                    activeTab = "schoolSearch";
                } else {
                    activeTab = $(".searchtab:has(input[name=Criteria/School])", _containers.criteria).eq(0).attr("id");
                }
            } else if (searchTabVal == "6") {
                // I don't think we'll ever get a searchtabval of 6 for the new criteria
                activeTab = "foreclosureSearch";
            } else if (searchTabVal == "1" || searchTabVal == "basic" || searchTabVal == "basicSearch") {
                if (isLegacyCriteria) {
                    activeTab = "basicSearch";
                } else {
                    activeTab = newBasicSearch;
                }
            } else if (searchTabVal != "") {
                activeTab = searchTabVal;
            }
            // If it's still undefined, use the default
            if (!activeTab) {
                if (isLegacyCriteria) {
                    activeTab = "basicSearch";
                } else {
                    activeTab = newBasicSearch;
                }
            }
        } else if (isLegacyCriteria && activeTab.indexOf("Search") == -1) {
            activeTab += "Search";
        }

        if (activeTab && activeTab.length > 0) {
            var $el = $("#" + activeTab);
            if ($el.length > 0) {
                // Not legacy criteria
                if (!isLegacyCriteria) {
                    $(".searchtab", _containers.criteria).removeClass("active");
                    $el.addClass("active");
                    if (expandAdvanced) {
                        showAdvancedCriteria();
                    }
                } else {
                    // Legacy criteria
                    if (activeTab == 'basicSearch') {
                        $("#advancedSearch,#mlsIDSearch,#addressSearch,#schoolSearch,#foreclosureSearch,#tab_adv_on,#tab_basic_off").hide();
                        $("#tab_adv_off,#tab_basic_on,#basicSearch").show();
                    } else if (activeTab == 'advancedSearch') {
                        $("#basicSearch,#mlsIDSearch,#addressSearch,#schoolSearch,#foreclosureSearch,#tab_basic_on,#tab_adv_off").hide();
                        $("#tab_basic_off,#tab_adv_on,#advancedSearch").show();
                    } else if (activeTab == 'mlsIDSearch') {
                        $("#basicSearch,#advancedSearch,#addressSearch,#schoolSearch,#foreclosureSearch").hide();
                        $("#mlsIDSearch").show();
                    } else if (activeTab == 'addressSearch') {
                        $("#basicSearch,#advancedSearch,#mlsIDSearch,#schoolSearch,#foreclosureSearch,").hide();
                        $("#addressSearch").show();
                    } else if (activeTab == 'foreclosureSearch') {
                        $("#basicSearch,#advancedSearch,#mlsIDSearch,#schoolSearch").hide();
                        $("#foreclosureSearch").show();
                    } else if (activeTab == 'schoolSearch') {
                        $("#basicSearch,#advancedSearch,#mlsIDSearch,#addressSearch,#foreclosureSearch").hide();
                        $("#schoolSearch").show();
                    }
                }
                var leftOffset = $("#mapsearch-left").offset().top;
                if (leftOffset < $(window).scrollTop()) {
                    $("body,html").animate({ scrollTop: leftOffset }, 1000);
                }
                $searchTab.val(activeTab);
                // Let listeners know we're done (such as the search summary)
                if (passedInActiveTab) {
                    $(document).trigger("criteriachange", [{ activeTab: activeTab}]);
                }
            }
        }
    };

    this.onChangeSubmit = function(obj, validation) {

        // Hack to force money validation for price fields, even if marked numeric
        if (obj && obj.name && obj.name.toLowerCase().indexOf('price') > -1) {
            validation = 'money';
        }
        // Updated validation name
        if (validation == "mmddyyyy") {
            validation = "date";
        }

        if (!validation || validation.length === 0) {
            if ($(obj).is(".numeric")) {
                validation = "numeric";
            } else if ($(obj).is(".money")) {
                validation = "money";
            } else if ($(obj).is(".date")) {
                validation = "date";
            } else if ($(obj).is(".year")) {
                validation = "year";
            }
        }

        var objVal = null;
        if (obj) {
            // Some initial formatting
            if (obj.value.length > 0) {
                if (validation == "numeric") {
                    obj.value = Utils.Format.addCommas(obj.value);
                } else if (validation == "money") {
                    obj.value = "$" + Utils.Format.addCommas(obj.value);
                }
            }
            objVal = obj.value;
        } else {
            return;
        }

        // Changing from switch to if statements for perf reasons, per IE perf team
        var isValid = false;
        if (obj.value.length > 0) {
            if (validation == 'numeric') {
                isValid = IsNumeric(objVal);
            } else if (validation == 'money') {
                isValid = IsMoney(objVal);
            } else if (validation == 'date') {
                isValid = IsDate(objVal);
            } else if (validation == "year") {
                isValid = (IsNumeric(objVal) && objVal.length == 4 && new Date().getYear() >= objVal);
            } else {
                isValid = true;
            }
        } else {
            isValid = true;
        }

        if (isValid) {
            submit();
        } else {
            alert('Invalid entry. Please enter a ' + validation + ' value.');
            setTimeout(function() { obj.focus(); obj.select(); }, 25);
        }
    };

    this.GotoZip = function(zip) {
        gotoBoundary("zip", zip);
    };
    this.GotoCity = function(city) {
        gotoBoundary("city", city);
    };
    this.GotoNeighborhood = function(nid) {
        // Legacy criteria
        $("#selNeighborhood").val(nid);
        gotoBoundary("neighborhood", nid);
    };
    // For legacy criteria
    this.addressGoto = function(prefix) {
        // Consolidated from removed mapGoto() method
        if (prefix === null || prefix == '') {
            var searchTab = $("#SearchTab").val();
            if (searchTab == '5' || searchTab == "subdivisionSearch") {
                prefix = 'SS';
            } else if (searchTab == '4' || searchTab == "addressSearch") {
                prefix = 'AS';
            } else {
                return; // Just a normal search, get out
            }
        }
        prefix = "#" + prefix;

        var street = $(prefix + "_StreetName").val();
        var city = $(prefix + "_City").val();
        var state = $(prefix + "_State").val();
        var zip = $(prefix + "_ZipCode").val();

        // Need at least city or city+state or zip to zoom
        var address = '';
        if (city.length > 0) {
            address = city;
        }

        if (state.length > 0) {
            address += ',' + state;
        }

        if (address.length > 0) {
            address += ',usa';
        }

        if (address.length === 0 && zip.length > 0) {
            address = zip;
        }

        if (address.length === 0) {
            return;
        }

        // If we have a street name, add that to the address
        if (street.length > 0) {
            address = street + ',' + address;
        }

        // Zoom to the address
        if (street.length > 0) { // Add address pin if we're on a single address, after waiting for the map to move
            gotoLocation(address, "Address");
        }
    };

    this.prevPage = function() {
        getListingHtml(--_pageInfo.page * _pageInfo.resultsPerPage);
    };

    this.nextPage = function() {
        getListingHtml(++_pageInfo.page * _pageInfo.resultsPerPage);
    };

    this.gotoPage = function(page) {
        page = page <= 0 ? 1 : page;
        _pageInfo.page = page - 1;
        getListingHtml(_pageInfo.page * _pageInfo.resultsPerPage);
    };

    this.togglePinBubble = function(newID, currID) {
        $("#pin_" + newID).show();
        $("#pin_" + currID).hide();
    };

    this.openBirdseye = function(listingid, latitude, longitude) {
        $("#mapsearch-birdseye .ms_panel_text").html("Bird's Eye View");
        $("#mapsearch-birdseye").show();
        var map = new BingMap({
            startingMidLat: latitude,
            startingMidLong: longitude,
            startingZoom: 19,
            mapView: VEMapStyle.Birdseye,
            fireOnChange: false,
            showParcelLines: options.showParceLines,
            container: "mapsearch-birdseye-map"
        });
        $("#mapsearch-birdseye-map")
           .bind("birdseyeavailable", function() {
               //try {
               map.startAddingPins("birdseye");
               map.addPin("birdseye", "1_" + listingid, latitude, longitude, 1, "Listing", "{FROM_BIRDSEYE}");
               map.endAddingPins("birdseye");
               map.showPins("birdseye");
               //} catch (e) { Utils.Logger.warn("Error adding birdseye pin to map: " + e.message); }
           })
           .bind("mapviewnotsupported", function() {
               $("#mapsearch-birdseye .ms_panel_text").html("Bird's Eye View - Not Supported Here");
           });
        map.load();
        $("#mapsearch-birdseye").data("map", map);
        _map.hideControls();
    };

}


// Legacy map criteria methods
function toggling(divName) {
    if (document.getElementById(divName)) {
        if (document.getElementById(divName).style.display == '') {
            document.getElementById(divName).style.display = 'none';
        } else {
            document.getElementById(divName).style.display = '';
        }
    }
}
function toggleOpenHouseRange() {
    if (document.getElementById('OpenHouses').checked) {
        document.getElementById('OpenHouseStartDtm').disabled = false;
        document.getElementById('OpenHouseStopDtm').disabled = false;
    } else {
        document.getElementById('OpenHouseStartDtm').disabled = true;
        document.getElementById('OpenHouseStopDtm').disabled = true;
    }
}
function lcs() {
    // Old datepicker
    return true;
}
