var loc = document.location.href;
var a = loc.split("//");
var firstChunk = a[1].split(".");
var subDomain = firstChunk[0]; 

jsapi.util.ApplicationContext.set("authenticationToken", "5A2765C3440F03BF8A8B39E3FEA0F99594531FBA");

var infoBubbles = new jsapi.map.component.InfoBubbles();

function getMap(page, lat, lon) {

    document.page = page;

    var components = [
        infoBubbles,
        new jsapi.map.component.Behavior()
    ];
    
    // if we are on the trap map page we need to have Google Street View for the time being
    streetView = new GStreetviewClient();     
    
    if( page == "trapMap" ) {
        components.push(new jsapi.map.component.ZoomBar());
        components.push(new jsapi.map.component.TypeSelector());
    }

    // we are going to figure out the location that map should be set to.
    // this might be the last place the user left the map, or if it's a fresh visit, it might be HTML5 geolocation
    // if we use the HTML5 method, it's a callback.  So we will create the map, after we get the location.
    // so the code that actually creates the map is called in getLocation()
    getLocation(components);

}

function getLocation(components) {

    // let's see if we have saved settings from their last map view
    var zoom = getCookieValue("mapZoomLevel");
    var lat = getCookieValue("mapCenterLat");
    var lon = getCookieValue("mapCenterLon");
    
    // we never want to return to our previous view on the homepage
    if( zoom == "" || document.page == "home") {

        var noLocation = function(){
        
            lat = myLat ? myLat : 0;
            lon = myLon ? myLon : 0;
            zoom = myLat == 0 ? 3 : 12;
        
            var location = {
                lat: lat,
                lon: lon,
                zoom: zoom
            };
            createMap(location, components);
        };
    
        // since we don't have location data in the cookies, let's use the browser to geolocate
        // but first we will load the map so the user's not starting at an empty screen while they try to read the bit about geolocating
        noLocation();    

    }
    else {
        var location = {
            lat: lat,
            lon: lon,
            zoom: zoom
        };
        createMap(location, components);
    }
   
}

function zoomToCurrentLocation() {

    trackIt("TrapMap/findMe/modLevel=" + moderator);

    function noLocation() {
        lat = myLat ? myLat : 0;
        lon = myLon ? myLon : 0;
        zoom = myLat == 0 ? 3 : 12;
    
        var coord = new jsapi.geo.Coordinate(lat, lon);
        MAP.setZoomLevel(zoom);
        MAP.setCenter(coord);
    }

    // Check if browser supports navigator.geolocation (Safari,Chrome,Firefox all should at this point)
    if( navigator && navigator.geolocation ) {
        var foundLocation = function(pos){
            var coord = new jsapi.geo.Coordinate(pos.coords.latitude, pos.coords.longitude);
            MAP.setZoomLevel(12);
            MAP.setCenter(coord);
        };

        navigator.geolocation.getCurrentPosition(foundLocation,noLocation,{enableHighAccuracy:true});
    }
    
}

function saveRouteAB() {
    $("body").attr("directionsA", $("#directionsA").val());
    $("body").attr("directionsB", $("#directionsB").val());    
    
}

function createMap(location, components) {

    MAP = new jsapi.map.Display(document.getElementById("map"), {
        center: new jsapi.geo.Coordinate(location.lat*1, location.lon*1),
        zoomLevel: location.zoom,
        components : components
    });

    var OviTileProvider = new jsapi.map.js.ImgTileProvider({
        width: 256, height: 256, label: "Normal.Day", alt: "", min: 0, max: 20,
        getUrl: function( level, row, col ) {
            //var token= jsapi.util.ApplicationContext.authenticationToken;
            var token = escape("bt8ZVRFEY6wEegIVWA2XMw%3D%3D");
            //console.log(jsapi.util.ApplicationContext.authenticationToken);
            //var appId = jsapi.util.ApplicationContext.appId;
            var appId = "0FaCOMcy7lgYNlLt_b6Q";
            var ret = [
               "http://",
               String.fromCharCode(98 + (row + col) % 10), // b...k
               ".maptile.maps.svc.ovi.com/maptiler/v2/maptile/newest/",
               "normal.day/", level, "/", col, "/", row, "/", 256, "/png8"
              ];
            token && ret.push("?token=", token);
            appId && ret.push("&app_id=", appId);

            return ret.join("");
        },
        getCopyrights: function( bbox, level ) {
            return jsapi.map.js.copyrights.get('BaseMap', bbox, level);
        }
    });
                
    MAP.set("baseMapType", OviTileProvider);

    MAP.addListener("mapviewchangeend", mapViewChanged);

    MAP.addListener("click", function() {
        clearInfoBubbles();
    });

    if( document.page == "trapMap" ) {

        // ***** Add traffic flow to the map *****
        // tile provider
        navteqTraffic = new jsapi.map.js.ImgTileProvider({
            label: "Traffic",
            descr: "Navteq's Traffic Overlay",
            min: 7,
            max: 18,
            opacity: 0.7,
            alpha: true,
            getUrl: function( level, row, col ) {
                var mask,
                    url = ["http://",
                            (row + col) % 3, ".tl.", 
                            "prd.lbsp.navteq.com/",
                            "traffic/",
                            "6.0/quadkeytraffic.jsp?foo="+ +new Date() +"&profile=NTprtls&token=JSLOCAPI_DEV_LBSP_ALL&quadkey="];
                            // "6.0/quadkeytraffic.jsp?profile=NTprtls&token=JSLOCAPI_DEV_LBSP_ALL&quadkey="];
                while (level-- > 0) {
                    mask = 1 << level;
                    url.push(((col & mask) != 0) + ((row & mask) !== 0) * 2);
                }
                return url.join("");
            },
            expires: function(){
                return +new Date() + 20000; // miliseconds
            }
        });

        var ul = $('<ul class="ovi_mp_dropDownMenu" id="trapsterMapButtons" style="margin-right: 30px;"></ul>');
        
        var trafficButtonClass = "ovi_mp_first";
        
        // here we are going to add a button that the user can click to add a trap
        MAP.reportTrap = false;
        if( logged_in ) {
            var addTrapButton = $('<li class="ovi_mp_normal ovi_mp_first" style="width: 99px"><a>Report Trap</a></li>');
            addTrapButton.click(function() {
            
                trackIt("TrapMap/reportTrap/modLevel=" + moderator);
            
                if( !MAP.reportTrap ){
                    MAP.reportTrap = true;

                    clearInfoBubbles();

                    // figure out the middle of the map at the top
                    var mapBounds = MAP.getViewBounds();
                    var longitudeDelta = Math.abs(mapBounds.topLeft.longitude - mapBounds.bottomRight.longitude);
                    var middleLongitude = mapBounds.topLeft.longitude + (longitudeDelta / 2);
                    var markerCoords = {lat: mapBounds.topLeft.latitude, lon: middleLongitude};
                    var markerXY = MAP.geoToPixel( new jsapi.geo.Coordinate( markerCoords.lat, markerCoords.lon) );
                    var icon = "http://" + subDomain + ".trapster.com/images/greenNewTrap.png";
                    var pin = $('<img src="' + icon + '" />');
                    pin.css({position: "absolute", top: markerXY.y, left: markerXY.x});
                    //$("#map > div").append(pin);

                    // animate the pin dropping onto the map
                    /*
                    pin.animate({
                        top: MAP.geoToPixel(MAP.center).y
                    },800, function() {


                    });
                    */

                    //var x = parseInt($(this).css("left"), 10);
                    //var y = parseInt($(this).css("top"), 10);

                    makeTrapSelectionList(pin, 0, 0);
                    
                    // if we already started creating a trap, let's junk the old one
                    if( document.marker ) {
                        MAP.objects.remove( document.marker );
                        document.marker = null;
                    }

                } 
                else {
                    $("#trapSelectionContainer").remove();
                    MAP.reportTrap = false;
                }
            });

            // place the addTrap button on the map.  
            // we aren't using the api because it's a pain in the ass.
            ul.append(addTrapButton);
            
            trafficButtonClass = "";
        }

        // traffic button        
        MAP.traffic = false;
        var trafficButton = $('<li class="ovi_mp_normal ' + trafficButtonClass + '" style="width: 71px"><a>Traffic</a></li>');
        trafficButton.click(function() {
        
            trackIt("TrapMap/getTraffic/modLevel=" + moderator);
        
            if( !MAP.traffic ) {
                MAP.overlays.add( navteqTraffic );
                MAP.traffic = true;
                trafficButton.addClass("ovi_mp_active");
            }
            else {
                MAP.overlays.remove( navteqTraffic );
                MAP.traffic = false;
                trafficButton.removeClass("ovi_mp_active");
            }
        });
        ul.append(trafficButton);

        // directions button 
        MAP.directions = false;
        var directionsButton = $('<li class="ovi_mp_normal ovi_mp_last" style="width: 89px"><a>Directions</a></li>');
        directionsButton.click(function() {
        
            trackIt("TrapMap/startGetDirections/modLevel=" + moderator);
        
            if( $("#routingContainer").size() == 0 && $("#directions").size() == 0 ) { 
                directionsButton.addClass("ovi_mp_active");
                
                saveRouteAB();
                $("#routingContainer").remove();

                var html = [
                    '<div id="routingContainer" style="position: absolute; top: 51px; left:556px; background-color: #fff;padding: 10px 30px 10px 10px">',
                        '<div>A: <input type="text" id="directionsA" value="',$("body").attr("directionsA"),'"></div>',
                        '<div>B: <input type="text" id="directionsB" value="',$("body").attr("directionsB"),'"></div>',
                        '<div style="position: relative; width: 18px; height: 18px; overflow: hidden; float: right; left: 23px; top: -34px;"><img id="directionsSwapAB" style="position: absolute; left: -210px; top: 0px; border-width: 0px; padding: 0px; margin: 0px; width: 233px; height: 34px; cursor: pointer;" src="http://maps.google.com/intl/en_ALL/mapfiles/dlimgs2.png"></div>',
                        '<div><input type="checkbox" id="directionsShowTraps" checked="checked" />Show traps along the route</div>',
                        '<div><input type="button" id="getDirectionsButton" value="Get Directions"></div>',
                    '</div>'
                ];

                var div = $(html.join(""));
                
                div.find("#directionsSwapAB").click( function() {
                    var a = $("#directionsA").val();
                    var b = $("#directionsB").val();
                    $("#directionsA").val(b);
                    $("#directionsB").val(a);
                    
                    trackIt("TrapMap/swapDirections/modLevel=" + moderator);
                    
                });
            
                div.find("#getDirectionsButton").click( function() {

                    // now we have to route
                    var searcher = new jsapi.search.Manager();
                    var locationA = null;
                    var locationB = null;

                    function disambiguate(locations, aOrB, searchString) {
                        var html = $('<div id="disambiguate" style="position: absolute;top: 51px; left: 556px;padding: 10px; background-color: #fff"><h3>We could not find any results for:</h3><p>' + searchString + '</p><p>Please select an alternative from the list:</p><ul></ul></div>');

                        var click = function(location, locString) {
                        
                            if( aOrB == "A" ) {
                                locationA = location.navigationPosition;
                                $("#directionsA").val(locString)
                                // now kick off the second search
                                searcher.geocode($("#directionsB").val());
                            }
                            else {
                                locationB = location.navigationPosition;
                                $("#directionsB").val(locString)
                                route();
                            }

                            $("#disambiguate").remove();
                        }

                        for( var x=0; x<locations.length; x++ ) {

                            var a = locations[x].address;
                            var locString = a.houseNumber + " " + a.street + " " + a.city + " " + a.state + " " + a.postalCode;
                            var li = $("<li style='cursor: pointer;padding: 5px;'>" + locString + "</li>");

                            li.click(click.bind(this, locations[x], locString));

                            html.find("ul").append(li);
                        }

                        $("#map").append(html);

                    }

                    // since the api sucks big time we can't just pass a callback, we have to do this nonsense
                    searcher.addObserver("state", function(observedManager, key, value) {
                        if( value == "finished" ) {
                            if( observedManager.locations.length > 0 ) {
                                if( locationA == null ) {
                                    if( observedManager.locations.length > 1 ) {
                                        disambiguate(observedManager.locations, "A", $("#directionsA").val());
                                    }
                                    else {
                                        locationA = observedManager.locations[0].navigationPosition;
                                        // now kick off the second search
                                        searcher.geocode($("#directionsB").val());
                                    }
                                }
                                else {
                                    if( observedManager.locations.length > 1 ) {
                                        disambiguate(observedManager.locations, "B", $("#directionsB").val());
                                    }
                                    else {
                                        locationB = observedManager.locations[0].navigationPosition;
                                        route();
                                    }
                                }
                            }
                        }

                    });
                
                    function route() {
                    
                        trackIt("TrapMap/finishGetDirections/modLevel=" + moderator);
                    
                        $("#getDirectionsButton").attr("value", "Loading directions . . .").attr("disabled", "disabled");
                    
                        var router = new jsapi.advrouting.Manager();

                        var onRouteCalculated = function(observedRouter, key, value) {
                            if( value == "finished" ) {

                                var routes = observedRouter.getRoutes();

                                document.mapRoute = new jsapi.routing.component.RouteResultSet(routes[0]).container;
                                MAP.objects.add(document.mapRoute);
                                MAP.zoomTo(document.mapRoute.getBoundingBox(), false, "default");
                                
                                // now we need to print out the directions
                                var html = $('<div id="directions" style="position: absolute;top: 51px; left: 556px;padding: 10px; background-color: #fff; overflow: auto; max-height: 420px; max-width: 375px"><ul id="directionsList"></ul></div>');   
                                //var ul = html.find("ul");
                                
                                var route = routes[0];
                                var directions =  route.legs[0].maneuvers;
                                
                                //console.log("route", route);
                                
                                /*
                                // add the starting point
                                ul.append('<li style="background-color: lightgray; border-top: 1px solid black; border-right: 1px solid black; border-left: 1px solid black; padding: 5px;">' + $("#directionsA").val() + '</li>');
                                
                                // add the summary
                                ul.append('<li>' + metersToMiles(route.summary.distance) + ' mi (about ' + secondsToMinutes(route.summary.baseTime) + ' mins)</li>');
                                
                                // add the individual directions
                                for( var x=0;x<directions.length;x++ ) {
                                    ul.append("<li><strong>" + (x * 1 + 1) + ".</strong> " + directions[x].instruction + "</li>");
                                }
                                
                                // add the end point
                                ul.append('<li style="background-color: lightgray; border-right: 1px solid black; border-left: 1px solid black; padding: 5px;">' + $("#directionsB").val() + '</li>');
                                
                                ul.find("li").css("border-bottom", "1px solid black");
                                ul.find("li span.direction").css("font-weight", "bold");
                                ul.find("li span.street").css("font-weight", "bold");
                                */
                                
                                // now let's build the object we need to get the traps built into directions
                                var r = { steps: [] };
                                
                                // add start waypoint
                                r.steps.push({ vertexes: [ { lat: routes[0].waypoints[0].originalPosition.latitude, lng: routes[0].waypoints[0].originalPosition.longitude } ], description: $("#directionsA").val(), distance: 0, duration: 0 });
                                
                                // now push the actual directions
                                for( var x=0;x<directions.length;x++ ) {
                                    
                                    var step = directions[x];
                                    
                                    var s = { vertexes: [] };

                                    // add vertexes 
                                    if( step.shape ) {
                                        for(var k=0; k<=step.shape.internalArray.length;k++) {

                                            if( step.shape ) {

                                                // this loop is weird because lat is first, then lon, then altitude
                                                var lat = step.shape.internalArray[k];
                                                k++;

                                                if(step.shape) {

                                                    var lon = step.shape.internalArray[k];
                                                    k++; // this is altitude.  We don't need that.

                                                    s.vertexes.push({lat: lat, lng: lon});

                                                }
                                            }
                                        }
                                    }
                                    
                                    s.description = step.instruction;
                                    s.distance = {meters:step.length, html: metersToMiles(step.length)+" mi"};//step.length;
                                    s.duration = {seconds: step.travelTime, html: secondsToMinutes(step.travelTime)+" mins"};//step.travelTime;
                                    
                                    r.steps.push(s);
                                }

                                // add end waypoint
                                r.steps.push({ vertexes: [ { lat: routes[0].waypoints[1].originalPosition.latitude, lng: routes[0].waypoints[1].originalPosition.longitude } ], description: $("#directionsB").val(), distance: 0, duration: 0 });
                                var totalDistance = {meters:route.summary.distance, html: metersToMiles(route.summary.distance)+" mi"};
                                var totalDuration = {seconds: route.summary.baseTime, html: secondsToMinutes(route.summary.baseTime)+" mins"};
                                r.distance = totalDistance;
                                r.duration = totalDuration;

                                // we need to flop the points in the bounding box since trapster wants stuff backwards
                                var SW = {lat: route.boundingBox.bottomRight.latitude, lng: route.boundingBox.topLeft.longitude};
                                var NE = {lat: route.boundingBox.topLeft.latitude, lng: route.boundingBox.bottomRight.longitude};

                                var details = { 
                                    routes: [r],
                                    bounds: {
                                        SW: SW,
                                        NE: NE
                                    },
                                    distance: totalDistance,
                                    duration: totalDuration
                                }
                                
                                var gotDirections = function(data) {
                                    saveRouteAB();
                                    $("#routingContainer").remove();
                                    html.append(data);
                                    $("#map").append(html);
                                    
                                    // modify the styles
                                    $(".direction").css("font-weight", "bold");
                                    $(".street").css("font-weight", "bold");
                                    $(".distance-description").css("display", "none");
                                }
                                
                                //console.log("details", details);
                                
                                var showTraps = $("#directionsShowTraps:checked").size() == 0 ? "N" : "Y";
                                
                                $.ajax({
                                    url: "rl/directions.php?traps=" + showTraps,
                                    type: "post",
                                    data: {route: JSON.stringify(details)},
                                    success: gotDirections
                                });
                            }
                        };

                        router.addObserver("state", onRouteCalculated);

                        var pointA = new jsapi.geo.Coordinate(locationA.latitude, locationA.longitude);
                        var pointB = new jsapi.geo.Coordinate(locationB.latitude, locationB.longitude);

                        var routingRequest = {
                            waypoints: [
                                {position: pointA},
                                {position: pointB}
                            ],
                            representationOptions: {
                                language: "en-US",
                                representationMode: "display",
                                routeAttributes: ["all"],
                                legAttributes: ["all"],
                                maneuverAttributes: ["all"],
                                corridorDepth: 2,
                                instructionFormat: "html"
                            },
                            modes: [
                                {type: "fastest",
                                transportModes:["car"],
                                trafficMode: "default"}
                            ]
                        };

                        router.calculateRoute(routingRequest);
                    }

                    // kick off the first geoCode
                    searcher.geocode($("#directionsA").val());
                });
            
                $("#map").append(div);
            }
            else {
                saveRouteAB();
                $("#routingContainer").remove();
                $("#directions").remove();
                directionsButton.removeClass("ovi_mp_active");

                if( document.mapRoute ) {
                    MAP.objects.remove(document.mapRoute);
                }
            }
        }); 
        
        ul.append(directionsButton);
        
        // insert the list into the map's container for menu items
        $("#map .ovi_mp_controlWrapper").prepend(ul);
        
        // style fix for the menu bars
        $(".ovi_mp_dropDownMenu").css("float", "left");        
        
        // if we are trying to load a specific trap, do it here
        if( trap_id != 0 ) {
            loadSpecificTrap();
        }
        
    }
}

function loadSpecificTrap() {
    
    // can't track here because the google code isn't defined until the bottom of the page
    //trackIt("trapmap/loadSpecificTrap_mod=" + moderator);
    
    // center map on the trap
    var coord = new jsapi.geo.Coordinate(trap_lat, trap_lng);
    MAP.setCenter(coord); 
    MAP.setZoomLevel(14);
    
    // open the trap
    var trap = {
        id: trap_id,
        lat: trap_lat,
        lng: trap_lng
    };
    addTrapMapBubble(trap, {}, null, {});
    
}

function metersToMiles(meters) {
    return Math.round(meters * 0.000621371192 * 10) / 10;
}

function secondsToMinutes(seconds) {
    return Math.round(seconds / 60 * 10) / 10;
}

function fixInfoBubbleStyle() {
    $(".ovi_nvt_tooltip_bubble").parent().css("position", "relative");
}

function padNumber(n) {
    if(n < 10) {
        return "0" + n;
    }
    else {
        return n;
    }
}

function makeTrapSelectionList(pin, x, y) {

    $("#trapSelectionContainer").remove();

    var dragMessageBubble = null;

    var drag = function() {
        clearInfoBubbles();
    };
    
    var marker = null;

    var draggingEnd = function(trapType,event) {
        
        var addedTrap = function() {
        
            trackIt("TrapMap/addedTrap/trapType=" + trapType + "/modLevel=" + moderator);
        
            getTraps();
            clearInfoBubbles();
        };
        
        var html = null;
        
        if( event.shiftKey ) {
        
            // check if the trap is a "live" trap, in which case there should be no end date
            var liveTrap = false;
            if( liveTraps.indexOf("|" + trapType + "|") == -1 ) {
                liveTrap = true;
            }
        
            var dt = new Date();
            dt.setHours(dt.getHours()+1);
            var dtstr = dt.getFullYear() + '-' + padNumber((dt.getMonth()+1)) + '-' + padNumber(dt.getDate()) +' ' + padNumber(dt.getHours()) + ':' + padNumber(dt.getMinutes());
            dt.setHours(dt.getHours()+1);
            var dtstr2 = dt.getFullYear() + '-' + padNumber((dt.getMonth()+1)) + '-' + padNumber(dt.getDate()) + ' ' + padNumber(dt.getHours()) + ':' + padNumber(dt.getMinutes());
        
            var expireHTML = "<b>Expire at:</b> <input type='text' id='reportTrapExpireAt' size='16' maxlength='16' value='" + dtstr2 + "' />";
            var andHTML = "and when this trap should expire";
            if( liveTrap ) {
                expireHTML = "";
                andHTML = "";
            }
        
            html = [
                "<div style='white-space: nowrap;'>",
                    "Please enter the date and time you want this trap to be published<br/>",
                    andHTML,
                    " (<em>times are in EST</em>):<br/><br/><b>Publish at:</b> <input type='text' id='reportTrapPublishAt' size='16' maxlength='16' value='",dtstr,"' />",
                    expireHTML,
                    "<br/><br/><input type='button' id='reportTrapConfirm' value='Schedule Trap' /> <input type='button' id='reportTrapCancel' value='Cancel' />",
                "</div>"
            ];
        }
        else {
            html = [
                '<div style="white-space: nowrap;">',
                    '<p style="margin-bottom: 5px; padding: 0px;">To the best of my knowledge there is a valid trap at this location.</p>',
                    '<p style="margin-bottom: 5px; padding: 0px;"><i>I have read and agree to the <a target="_blank" href="terms-conditions.php">Terms And Conditions</a></i></p>',
                    '<input type="button" value="Yes" id="reportTrapConfirm"> <input type="button" value="Cancel" id="reportTrapCancel">',
                '</div>'
            ];        
        }
        
        var coordinate = event.currentTarget.coordinate;

        var bubble = createInfoBubble( {html: html.join(""), coordinate: MAP.pixelToGeo(event.displayX + 25, event.displayY), marker: marker, removeMarkerOnClose: true} );
        
        if( event.shiftKey ) {
        
            $('#reportTrapConfirm').click(function(){
                var publishAt = $('#reportTrapPublishAt').val();
                var expireAt = $('#reportTrapExpireAt').val();

                // validate times
                if(!publishAt.match(/^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]$/)) {
                    alert("Invalid publish date");
                }
                else if(expireAt && !expireAt.match(/^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]$/)) {
                    alert("Invalid expiry date");
                }
                else if(expireAt && publishAt >= expireAt) {
                    alert("Expiry date must be after publish date");
                }
                else {
                    var ep = "&ep=" + expireAt;
                    if( liveTrap ) {
                        ep = "";
                    }
                    $.ajax({url: "http://" + subDomain + ".trapster.com/rl/trapserv.php?map=1&lat=" + coordinate.latitude + "&lng=" + coordinate.longitude + "&obj=" + trapType + "&sched=Y&pb=" + publishAt + ep + "&uid=" + uid, success: addedTrap});
                }
            });
        }
        else {
            $("#reportTrapConfirm").click(function() {
                // add trap here
                document.marker = null;
                $.ajax({url: "http://" + subDomain + ".trapster.com/rl/trapserv.php?map=1&lat=" + coordinate.latitude + "&lng=" + coordinate.longitude + "&obj=" + trapType + "&uid=" + uid, success: addedTrap});
            });
        }
        
        $("#reportTrapCancel").click(function() {
            clearInfoBubbles();
            document.marker = null;
            MAP.objects.remove(marker);
        });
    };
    
    // click on the icon in the trap-type list
    var iconClick = function(icon, trapType) {
        
        var coord = new jsapi.geo.Coordinate(MAP.getViewBounds().getCenter().latitude, MAP.getViewBounds().getCenter().longitude);
        
        marker = new jsapi.map.Marker(
            // Coordinate of the marker.
            //MAP.pixelToGeo( x + 10, y + 35 ), {
            coord,{

            // Make the marker draggable.
            draggable: true,

            icon: icon.image,

            // Add listener
            eventListener: {
                // in the capturing phase of the "drag" event of the marker
                "drag": [drag, true, null],
                // and in the bubbling phase of the "dragend" event of the marker.
                "dragend": [draggingEnd.bind(this, trapType), false, null]
            }
        });
        
        var point = new jsapi.util.Point(icon.iconAnchor.x,icon.iconAnchor.y);
        marker.set("anchor", point);
        
        MAP.objects.add( marker );
        document.marker = marker;
        
        pin.remove();
        $("#trapSelectionContainer").remove();
        MAP.reportTrap = false;
        
        var html = '<p style="white-space: nowrap; padding: 0px; margin-bottom: 0px;">Please drag the trap to its location.</p>';
        
        dragMessageBubble = createInfoBubble( {html: html, coordinate: coord, marker: marker, removeMarkerOnClose: true} );
        
    };

    // now we need to show the trap selection list
    var html = [
        '<div id="trapSelectionContainer">',
            '<span align="center" style="text-align: center; vertical-align: middle; margin-bottom: 5px; font-weight: bold; font-size: 16px">Select Trap Type</span>',
            '<div class="ovi_nvt_tooltip_close" id="closeXBox"></div>',
            '<ul id="trapSelectionList"></ul>',
        '</div>'
    ]; 

    var dom = $(html.join(""));

    dom.find("#closeXBox").click(function() {
        pin.remove();
        $("#trapSelectionContainer").remove();
        MAP.reportTrap = false;
    });
    
    // moderator is set by some other javascript file that is included.
    var trapSequence = [];
    
    var traps = traps_definition;
    
    // we only show certain traps for certain moderator levels
    // build this array of which traps we want to show
    // this code was copied over from the old stuff.  It just works
    for(var i=0;i<traps.length;i++) {
        if(traps[i] && (!traps[i].livetrap || (moderator > 0 || sip_queue)) && (traps[i].reportable || moderator > 0)) {
            if(traps_categories[traps[i].category]) {
                if(!trapSequence[traps_categories[traps[i].category].sequence]) {
                    trapSequence[traps_categories[traps[i].category].sequence] = [];
                }

                trapSequence[traps_categories[traps[i].category].sequence].push(i);
            }
        }
    }

    // now we dynamically load in the trap categories and trap types
    var category = null;
    var trap = null;
    var icon = null;
    var div = null;
    var ul = dom.find("ul");
    for( var i=0; i<trapSequence.length; i++) {
    
        // some might be undefined, so skip them
        if(!trapSequence[i]) {
            continue;
        }
    
        category = traps_categories[traps[trapSequence[i][0]].category];    
        
        if( category ) {

            var li = [    
                '<li style="margin-top: 20px;">',
                    '<span style="font-weight: bold;">',category.name, '</span>',
                    '<ul style="padding: 8px 8px 0; margin-top: 3px;"></ul>',
                '</li>'
            ];

            li = $(li.join(""));

            // using the sequence, grap the traps we want
            for( var j=0; j<trapSequence[i].length;j++) {
                trap = traps[trapSequence[i][j]];
                
                if( trap ) {

                    // we want this trap
                    icon = trap.icons.g;
                    trapLi = [
                        '<li class="trapIcon" style="margin-bottom: 8px">',
                            '<img src="',icon.image,'" style="float:left; margin-right: 7px;" />',
                            '<span>',trap.name,'</span>',
                        '</li>'
                    ];

                    trapLi = $(trapLi.join("")); 
                    trapLi.click( iconClick.bind(this, icon, trapSequence[i][j]) );
                    // trap the double click because some users are stupid
                    trapLi.dblclick( iconClick.bind(this, icon, trapSequence[i][j]) );
                    trapLi.css({lineHeight: "35px"});

                    var trapUl = li.find("ul");
                    trapUl.css({border: "2px solid #555"});
                    trapUl.append(trapLi);
                    
                }
            }

            ul.append(li);
            
        }

    }
    
    dom.css({background: "white", position: "absolute", top: 51, left: 484, height: "400px", overflowY: "auto", overflowX: "hidden", width: "245px", padding: "10px"});
    
    $("#map > div").append(dom);

}

function clearInfoBubbles() {
    $(".ovi_nvt_tooltip_bubble").remove();
}

function mapViewChanged(event) {
    
    getTraps();
    logView();
}

function logView() {
    var zoom = MAP.zoomLevel;
    var centerLat = MAP.center.latitude;
    var centerLon = MAP.center.longitude;
    
    if( document.page != "home" ) {
        createCookie("mapCenterLat", centerLat, 365);
        createCookie("mapCenterLon", centerLon, 365);
        createCookie("mapZoomLevel", zoom, 365);
    }
}

function getTraps(options) {
    if( document.getTraps ) {
        document.getTraps.abort();
    }
    
    var recenter = false;
    if( options && options.recenter ) {
        recenter = true;    
    }
    
    document.getTraps = $.getJSON(getMarkersJSONURL(), gotTraps.bind(this, recenter));
}

// now we have to load the traps
function gotTraps(recenter, data) {
    
    // if we need to recenter, then we need to calculate the bounding box of the traps returned
    if( recenter ) {
    
        var tlLat = -85;
        var tlLon = 180;
        var brLat = 85;
        var brLon = -180;
        
        var trap = null;
        for( var i=0;i<data.markers.length; i++ ) {
            trap = data.markers[i];
            
            if( (trap.lat *1) > tlLat ) {
                tlLat = trap.lat;
            }
            
            if( (trap.lat *1) < brLat ) {
                brLat = trap.lat;
            }
            
            if( (trap.lng *1) < tlLon ) {
                tlLon = trap.lng;
            }
            
            if( (trap.lng *1) > brLon ) {
                brLon = trap.lng;
            }
        }

        if( data.markers.length == 0 ) {
            tlLat = 85;
            tlLon = -80;
            brLat = -85;
            brLon = 180;
        }
        
        // recenter map
        var topLeft = new jsapi.geo.Coordinate(tlLat, tlLon);
        var bottomRight = new jsapi.geo.Coordinate(brLat, brLon);
        var bb = new jsapi.geo.BoundingBox(topLeft, bottomRight);
    
        // after realizing how the search works, it doesn't make any sense to zoom to the bounding box of the user's traps.
        // we are only searching for traps within the viewable map area anyway.  So no need to zoom.
    }   

    // first, let's clear any markers on the map
    data = clearMapMarkers(data);

    if( document.marker ) {
        MAP.objects.add(document.marker);
    }

    var trap = null;
    var html = null;
    var theIcon = null;

    // TODO: I'm sure much of this can be refactored.  This is copied exactly from the old code, although I added some proper formatting.

    for( var i=0;i<data.markers.length; i++ ) {

        trap = data.markers[i];
        
        var numvotes = trap.num;
        var maxlev = trap.maxlev;
        var objtype = parseInt(trap.type, 10);
        var trapid = trap.id;
        var canmove = trap.canmove;
        var status = trap.status;
        var opacity = parseInt(trap.opacity, 10);
        var conf = null;

        if(trap.id == 0) {
            if(trap.maxlev < 2) {
                theIcon = clustericons.g;
            }
            else if(maxlev < 5) {
                theIcon = clustericons.y;
            }
            else {
                theIcon = clustericons.r;
            }

            html = '<span style="font-size:small"><center><b>' + numvotes + ' traps</b><br>There are ' + numvotes + ' traps in this area.<br>Zoom in to see them individually.</center></span>';
        }
        else {
            if(!traps_definition[trap.type]) {
                // invalid type
                continue;
            }

            objtypestr = traps_definition[objtype].name;
            if( numvotes < 1) {
                theIcon = traps_definition[objtype].icons.b;
            }
            else if(status == "N") {
                theIcon = traps_definition[objtype].icons.n;
            }
            else if(status == "Q") {
                theIcon = traps_definition[objtype].icons.k;
            }
            else if(status == "P") {
                theIcon = traps_definition[objtype].icons.p;
            }
            else if(status == "E" && traps_definition[objtype].icons.e) {
                theIcon = traps_definition[objtype].icons.e;
            }
            else if(status == "S") {
                theIcon = traps_definition[objtype].icons.s;
            }
            else if(status == "G" && traps_definition[objtype].icons.ag) {
                theIcon = traps_definition[objtype].icons.ag;
            }
            else {
                if(numvotes < 2) {
                    theIcon = traps_definition[objtype].icons.g;
                }
                else if(numvotes < 5) {
                    theIcon = traps_definition[objtype].icons.y;
                }
                else {
                    theIcon = traps_definition[objtype].icons.r;
                }

                // check levels
                for(var l=0;l<traps_definition[objtype].levels.length;l++) {
                   if(maxlev & (1 << (traps_definition[objtype].levels[l].bit - 1))) {
                       theIcon = traps_definition[objtype].levels[l].icon;
                       conf = traps_definition[objtype].levels[l].name.toLowerCase();
                   }
                }
            }

            // check opacity
            if(objtype == 3 && (status == "A" || status == "G") && numvotes >= 1) {
                if(opacity <= 25) {
                    if(numvotes < 2) {
                        theIcon = traps_definition[objtype].icons.g_25;
                    }
                    else if(numvotes < 5) {
                        theIcon = traps_definition[objtype].icons.o_25;
                    }
                    else {
                        theIcon = traps_definition[objtype].icons.r_25;
                    }
                }
                else if(opacity <= 50) {
                    if(numvotes < 2) {
                        theIcon = traps_definition[objtype].icons.g_50;
                    }
                    else if(numvotes < 5) {
                        theIcon = traps_definition[objtype].icons.o_50;
                    }
                    else {
                        theIcon = traps_definition[objtype].icons.r_50;
                    }
                }
                else if(opacity <= 75) {
                    if (numvotes < 2) {
                        theIcon = traps_definition[objtype].icons.g_80;
                    }
                    else if(numvotes < 5) {
                        theIcon = traps_definition[objtype].icons.o_80;
                    }
                    else {
                        theIcon = traps_definition[objtype].icons.r_80;
                    }
                }
            }

            if(!conf) {
                if(numvotes < 1) {
                    conf = "no confidence";
                }
                else if (numvotes < 2) {
                    conf = "low confidence";
                }
                else if (numvotes < 5) {
                    conf = "medium confidence";
                }
                else {
                    conf = "high confidence";
                }
            }

            if(status == "G") {
                conf = "expired";
            }
            
            html = '<span style="font-size:small"><b>' + objtypestr + '</b> - <i>' + conf + '</i></span><p>Go to <a href="/trap/' + trap.id + '">TrapMap</a> for full details.</p>';

        }
        
        // build the marker for the map
        
        // some traps have the ability to be moved.
        // if the logged-in user created the trap and it has no votes 
        // or if the logged-in user is a moderator
        var draggable = false;
        if( trap.canmove == "Y" ) {
            // set the marker to draggable
            draggable = true;            
        }
        
        var marker = new jsapi.map.Marker([trap.lat, trap.lng], {
            icon : theIcon.image,
            draggable: draggable,
            eventListener: {
                "dragstart": [moveTrapStart, false, null],
                "dragend": [movedTrap.bind(this, trap), false, null],
                
                // major hack to get the mouse pointer to work
                "mouseenter": [function() {
                    document.body.style.cursor = "pointer";
                }, false, null],
                "mouseleave": [function() {
                    document.body.style.cursor = "";
                }, false, null]
            }
        });
        
        // for some reason, some traps don't have anchors.  Let's set one
        if( !theIcon.iconAnchor ) {
            theIcon.iconAnchor = {x:10, y:35}; 
        }

        // now that we have a size for the marker, we need to set the anchor point
        var point = new jsapi.util.Point(theIcon.iconAnchor.x,theIcon.iconAnchor.y);
        marker.set("anchor", point);

        if( document.page == "home" ) {
            //marker.addListener("click", createInfoBubble.bind(this, {html: html, coordinate: new jsapi.geo.Coordinate(trap.lat,trap.lng)} ));
            marker.addListener("click", addTrapMapBubble.bind(this, trap, marker, html)); 
        }
        else if( document.page == "trapMap" ) {
            marker.addListener("click", addTrapMapBubble.bind(this, trap, marker, null)); 
        }

        MAP.objects.add(marker);
    
    }

    if( recenter ) {
        //MAP.zoomTo(bb, true);
    }

}

function moveTrapStart(event) {
    document.originalCoordinate = event.target.coordinate;
}

function movedTrap(trap, event) {
    var coord = new jsapi.geo.Coordinate(event.target.coordinate.latitude, event.target.coordinate.longitude);
    var html = [
        '<p style="padding: 0px;margin-bottom: 5px;">Do you really want to move this trap?</p>',
        '<p style="padding: 0px;margin-bottom: 5px;"><input id="confirmMoveYes" type="button" value="Yes">&nbsp;&nbsp;<input type="button" id="confirmMoveNo" value="No"></p>'
    ];
    
    var closeIt = function() {
        // move the trap back to its original location
        event.target.set("coordinate", document.originalCoordinate);
        clearInfoBubbles();
    };
    
    var bubble = createInfoBubble( {html: html.join(""), coordinate: coord, onClose: closeIt} );
    
    $("#confirmMoveNo").click(function() {
        closeIt();
    });
    
    var movedTrap = function() {
        getTraps();
    };
    
    $("#confirmMoveYes").click(function() {
        // save the trap's new location to the database
        
        trackIt("TrapMap/movedTrap/modLevel=" + moderator);
        
        $.ajax({
            url: "rl/movetrap.php",
            type: "GET",
            data: {
                id: trap.id,
                lat: coord.latitude,
                lng: coord.longitude
            },
            success: movedTrap
        });
        
        clearInfoBubbles();
    });    
}

function addTrapMapBubble(trap, marker, html, event) {

    trackIt("TrapMap/clickedTrap/modLevel=" + moderator);

    // first let's handle the alt+shift click to delete trap
    if( event && event.altKey && event.shiftKey && moderator > 0) {
        // delete trap
        if( moderator >= 3 || (moderator >= 1 && confirm("Are you sure you want to delete this trap?")) ) {
            deleteTrap(trap.id);
            clearInfoBubbles();
        }
    }
    else if( event && event.altKey && moderator >= 3 && (trap.status == "N" || trap.status == "Q" || trap.status == "E")) {
        // approve trap
        if( moderator >= 3 || (moderator >= 2 && confirm("Are you sure you want to approve this trap?")) ) {
            bubble_approve_trap(trap.id)
        }
    }
    else {
    
        var coord = new jsapi.geo.Coordinate(trap.lat,trap.lng);
    
        // it's not a cluster, so show the whole kit and kaboodle
        var location = new GLatLng(trap.lat, trap.lng);

        streetView.getNearestPanorama(location,function (data) {
            var hasView;
            var url;

            if(data.code != 200) {
                hasView = "N";
            }
            else {
                hasView = "Y";
            }

            url = "rl/trapinfo.php?id=" + trap.id + "&o=y&stv=" + hasView;

            if(document.streetViewGet) {
                document.streetViewGet.abort();
            }

            document.streetViewGet = $.ajax({
                url: url, 
                type: 'get',  
                success: function(data) {

                    // the cluster and the homepage traps shouldn't have to be in here, as we know they won't have street view.
                    // but for some reason the jsapi wasn't working unless we call createInfoBubble inside the callback
                    // must be some kind of bug.  Heather and Bryan spent hours trying to figure it out
                    // this worked so we left in the big hack.  What are you gonna do?

                    // maybe this is a cluster trap
                    if( trap.id == 0 ) {
                        var data = "<p>There are " + trap.num + " traps here.  Please zoom in for more information.</p>";
                        hasView = "N";
                    }
                    
                    // homepage trap
                    if( html ) {
                        var data = html;
                        hasView = "N";
                    }

                    var bubble = createInfoBubble( {html: data, coordinate: coord, marker: marker, streetView: hasView} );
                    // assign the marker to the bubble.  There should be a link between the two.  You can't have a bubble without a marker.
                    bubble.marker = marker; 

                    if(hasView == "Y") {

                        var pov;
                        var loc;

                        info = $("#streetViewValues").val().split("|");

                        if(info.length == 5) {
                            pov = new Object();
                            pov.yaw = parseFloat(info[0]);
                            pov.pitch = parseFloat(info[1]);
                            pov.zoom = parseFloat(info[2]);
                            loc = new GLatLng(info[3],info[4]);
                        }
                        else {
                            pov = null;
                            loc = new GLatLng(info[0],info[1]);
                        }

                        var streetViewPano = new GStreetviewPanorama($("#stview_small")[0]);
                        GEvent.addListener(streetViewPano,"error",function (errorCode) {
                            streetViewPano.remove();
                            if(errorCode == 603) {
                                $("#stview_small").text("<br>You need to have flash player installed in order to view street view");
                                $("#stview_small_overlay").hide();
                            }
                        });
                        streetViewPano.setLocationAndPOV(loc,pov);

                    }

                    // get the info bubble content and put it inside a new container so that we can slide the whole thing up
                    var content = $(".ovi_nvt_tooltip_content > div");
                    var container = $('<div id="infoBubbleContainer" style="white-space: nowrap;"><div id="infoBubbleBasicInfo"></div><div id="infoBubbleExtraInfo">Loading . . .</div></div>');
                    container.find("#infoBubbleBasicInfo").append(content);
                    container.appendTo(".ovi_nvt_tooltip_content");
                    container.css("position", "relative");
                    container.find("#infoBubbleExtraInfo").css("display","none");        

                    bubble.DOM = container;
                    
                    // assign click events to the more three main links at the bottom of the info bubble
                    bubble.DOM.find("#commentLink").click( showMoreInformation.bind(this, trap.id, "c", bubble) );
                    bubble.DOM.find("#pmLink").click( showMoreInformation.bind(this, trap.id, "p", bubble) );
                    bubble.DOM.find("#moreInfoLink").click( showMoreInformation.bind(this, trap.id, "v", bubble) );
                    
                    // call this again because we added new content
                    adjustBubblePosition(bubble);

                    $(".ovi_nvt_tooltip_content").css("overflow", "hidden");
                }
            });
        });
    }
}

function approveTrap(trapId) {
    
    if( moderator >= 3 || window.confirm("Are you sure you want to approve this trap?") ) {
        var url = "rl/moderators.php?cmd=approvetrap&trapid="+id;
        jQuery.get(url, function(data) {
            if(data == "OK") {
                if(moderator < 3) {
                    window.alert("Trap successfully approved!");
                }
                
                // let's remove the marker and then the new colored one will draw
                MAP.objects.remove(this.marker);
                getTraps();
                clearInfoBubbles();
                
            }
            else {
                window.alert(data);
            }
        });
    }    
}

function attachListeners(bubble) {
    bubble.DOM.find("#approveTrapButton").click( approveTrap.bind(bubble, trap.id) );
}

function createInfoBubble( options ) {

    // first clear out old info bubbles
    clearInfoBubbles();
    
    var bubble = infoBubbles.addBubble(options.html, options.coordinate);

    var bubbleHandler = function(list, method, element, idx) {
        
        if( method == "remove" ) {
            if( options.marker && options.removeMarkerOnClose ) {
                MAP.objects.remove(options.marker);
                document.marker = null;
            }

            if(options && options.onClose) {
                options.onClose();
            }

        }

    };
        
    // listen for the clicking of the close button
    infoBubbles.openBubbleHandles.removeObserver(bubbleHandler);
    infoBubbles.openBubbleHandles.addObserver(bubbleHandler);
    
    if( options.marker ) {
        document.clickedMarker = options.marker;
    }
    
    adjustBubblePosition(bubble, options.streetView);
    
    fixInfoBubbleStyle();
    
    return bubble;
}

function adjustBubblePosition(bubble, streetView) {
    
    // determine if the bubble is off the map.  If so, slide the map to accommodate it
    var pointerWidth = 44;
    var pointerSpot = MAP.geoToPixel(bubble.coordinate);
    var bubbleWidth = $(".ovi_nvt_tooltip_content").width();
    var bubbleHeight = $(".ovi_nvt_tooltip_content").height();
    
    var bubbleRightPoint = pointerSpot.x + bubbleWidth + pointerWidth;
    var bubbleBottomPoint = pointerSpot.y + bubbleHeight + 15;
    var deltaX = MAP.width - bubbleRightPoint;
    var deltaY = MAP.height - bubbleBottomPoint;
    var buffer = 40;

    var extraX = 0;
    //if( streetView && streetView == "Y" ) {
    //    extraX = 250; 
    //}

    if( deltaX <= 0 || deltaY <= 0) {

        if( deltaX > 0 ) {
            deltaX = 0;
        }
        else {
            deltaX = deltaX * -1 + buffer;
        }

        if( deltaY > 0 ) {
            deltaY = 0;
        }
        else {
            deltaY = deltaY * -1 + buffer;
        }

        MAP.pan(0, 0, deltaX, deltaY, "default");
    }
}

function adjustInfoBubbleExtraInfoHeight() {
    // set the height of the container to be the size of the new content
    $("#infoBubbleContainer").parent().animate({
        height: $("#infoBubbleExtraInfo").height()
    }, 400, function() {
    });
}

function slideBubbleContent( url, bubble ) {

    // first let's start loading in the content
    jQuery.get(url, function(data) {
        $("#infoBubbleExtraInfo").empty().append(data);
        
        var parentPadding =  parseInt($("#infoBubbleBasicInfo").parent().parent().css("paddingTop"), 10);
        
        $("#infoBubbleExtraInfo").css({display:"block", paddingTop: parentPadding});

        $("#infoBubbleContainer").parent().height($("#infoBubbleBasicInfo").height()).css("overflow", "hidden");

        $("#infoBubbleContainer").animate({
            top: -($("#infoBubbleBasicInfo").outerHeight() + parentPadding)
        },800, function() {

            adjustInfoBubbleExtraInfoHeight();

            // add the close button
            var minButton = $('<div id="extraMinButton">-</div>');
            minButton.css({float: "right", border: "1px solid black", padding: "5px", cursor: "pointer"}).click( slideBubbleContentDown );
            $("#infoBubbleExtraInfo").prepend(minButton);

        });        
 
        // set the height of the container to be the size of the new content
        $("#infoBubbleContainer").parent().animate({
                height: $("#infoBubbleExtraInfo").height()
            }, 400, function() {
        });
        
        attachListeners(bubble);
        
        // now check if we need to move the bubble over
 
    });

}

function slideBubbleContentDown() {

    $("#infoBubbleContainer").animate({
        top: 0
    },800, function() {
        $("#infoBubbleExtraInfo").empty();
    });
    
    $("#infoBubbleContainer").parent().animate({
        height: $("#infoBubbleBasicInfo").height()
    }, 400);

}

function clearMapMarkers(newTraps) {

    // if a trap is in the newTraps collection and already on the map
    // then we don't want to add it to the map again and we don't want to remove it from the map
    // so we will remove it from the newTraps collection

    var removedNewTraps = [];
    var neededNewTraps = [];
    
    // get the current markers from the map
    var currentMarkers = [];
    for( var t=0;t<MAP.objects.getLength();t++ ) {
        var marker = MAP.objects.get(t);
        if( marker._type == "marker" ) {
            currentMarkers.push(marker);
        }
    }

    var len = currentMarkers.length;
    for(var i=0;i<len;i++){

        var remove = true;
        var xlen = newTraps.markers.length;
    
        for( var x=0;x<xlen;x++ ) {
            // if the lat/lon of the newTrap matches one already on the map then we don't want to remove it from the map
            // but that also means we aren't adding the trap, so let's remove it from the collection of things to add
            if( newTraps.markers[x] && newTraps.markers[x].lat == currentMarkers[i].coordinate.latitude && newTraps.markers[x].lng == currentMarkers[i].coordinate.longitude ) {
                remove = false;
                removedNewTraps.push(newTraps.markers[x]);
                continue;
            }
        }

        if( remove ) {
            MAP.objects.remove(currentMarkers[i]);
        }
    }
    
    // now we know which traps we don't want to add to the map and so we'll need to remove them from the newTraps array
    var keepIt = null;
    for( var j=0; j<newTraps.markers.length; j++ ) {
        keepIt = true;
        for( var k=0; k<removedNewTraps.length; k++ ) {
            if( newTraps.markers[j] && newTraps.markers[j].lat == removedNewTraps[k].lat && newTraps.markers[j].lng == removedNewTraps[k].lng ) {
                keepIt = false;
            }
        }
    
        if( keepIt ) {
            neededNewTraps.push(newTraps.markers[j]);
        }
    
    }
    
    return {markers: neededNewTraps};
    
}

function getMarkersJSONURL() {

    //var size = MAP._size;
    var zoom = MAP.zoomLevel;
    var width = MAP.width;
    var height = MAP.height;

    var mapView = MAP.getViewBounds();

    var blat = mapView.bottomRight.latitude;
    var blng = mapView.topLeft.longitude;

    var tlat = mapView.topLeft.latitude;
    var tlng = mapView.bottomRight.longitude;
 
    return 'rl/getmarkers.php?jsonOutput=true&f='+filter+'&df='+filter_days+'&af='+filter_action+'&uf='+filter_user+'&tf='+filter_type+'&sf='+filter_state+'&lf='+filter_level+'&w='+width+'&h='+height+'&z='+zoom+'&blat='+blat+'&blng='+blng+'&tlat='+tlat+'&tlng='+tlng+(filter_all?"&all=Y":"");

}

function trapMapGetLatLon() {

    var LAT;
    var LNG;
    var latC = getCookieValue(TrapsterLatCookie);
    var lngC = getCookieValue(TrapsterLngCookie);

    if (latC == "" || lngC == "" ) { 

        LAT = 37;
        LNG = -95;

    } 
    else {

        LAT = parseFloat(latC);
        LNG = parseFloat(lngC);
    }
    
    return {lat: LAT, lon: LNG};

}

function search(event) {

    trackIt("TrapMap/search/modLevel=" + moderator);

    var search = false;
    if( event && event.keyCode == 13 ) {
        search = true;
    }
    else if( !event ) {
        search = true;
    }

    if( !search ) {
        return;
    }

    var searchManager = new jsapi.search.Manager();
    searchManager.addObserver("state", function(observedManager, key, value) {
    
        var createMarker = function(loc) {
        
            // remove the disambiguate div if it is there
            $("#disambiguate").remove();
        
            // drop a marker on the map
            var marker = new jsapi.map.Marker([loc.displayPosition.latitude, loc.displayPosition.longitude], {
                icon : "http://" + subDomain + ".trapster.com/images/greenNewTrap.png",
                draggable: false
            });

            var point = new jsapi.util.Point(10,35);
            marker.set("anchor", point);

            // since the marker would be removed from the map after the map zooms in and centers on the location (because the traps will load and the marker won't match any traps)
            // we are going to have to load the marker after the traps load
            document.marker = marker;

            // create a bubble to show the searched location
            var a = loc.address;
            var html = [
                "<p>", a.houseNumber, " ", a.street, " ", a.city, " ", a.state," ",a.postalCode,"</p>"
            ];
            
            // MAP.objects.add(marker);
            MAP.setZoomLevel(12);

            var coord = new jsapi.geo.Coordinate(loc.displayPosition.latitude, loc.displayPosition.longitude);
            MAP.setCenter(coord);        
            
            var bubble = createInfoBubble( {html: html.join(""), coordinate: coord, marker: marker, removeMarkerOnClose: true} );
            
        };
    
        if(value == "finished") {
            var len = observedManager.locations.length;
            if( len > 0 ) {
                // we have search results
                if( len == 1 ) {
                    // we only have one location, so let's show it
                    var loc = observedManager.locations[0];
                    createMarker(loc);
                }
                else {
                
                    // we have multiple locations, so let's ask the user which one they want
                    var div = $('<div id="disambiguate" style="background-color: white; border: 2px solid black;padding: 10px;"><h2 style="padding-bottom: 10px;">We found more than one match for your address</h2><p style="padding-bottom: 10px;">Please select the one you were searching for:</p><ul></ul></div>');
                    var ul = div.find("ul");
                    for( var i=0;i<len;i++) {
                        var a = observedManager.locations[i].address;
                        var li = $("<li style='cursor: pointer;padding: 5px;'>" + a.houseNumber + " " + a.street + " " + a.city + " " + a.state + " " + a.postalCode + "</li>");
                        li.click(createMarker.bind(this, observedManager.locations[i]));
                        ul.append(li);  
                    }
                    
                    $("body").append(div);
                    
                    var winWidth = $(window).width();
                    var winHeight = $(window).height();
                    div.css("position","absolute").css("left", ((winWidth / 2) - (div.width() / 2)) + "px").css("top", ((winHeight / 2) - (div.height() / 2)) + $(window).scrollTop() + "px");
                    
                }
            }
        }
    });
    
    var searchAddress = $("#searchAddress").val()
    if( searchAddress != "" || searchAddress != "Search Address..." ) {
        searchManager.search(searchAddress);
    }
    
}

function deleteComment(commentId, trapId) {

    if( window.confirm("Are you sure you want to delete this comment?") ) {
        var url = "rl/commentDelete.php?id=" + commentId;
        jQuery.get(url, function(data) {
        
            trackIt("TrapMap/commentDeleted/modLevel=" + moderator);
        
            // reload the trap info
            slideBubbleContent("rl/trapinfo.php?id=" + trapId + "&t=c");
            bubble_select_tab("comments");
            
        });
    }
}

Function.prototype.bind = function() {
    var args = [];

    function concat(completeArgs, toCopy) {

        // using concat with no arguments basically clones it
        var newArgs = completeArgs.concat();

        // create a true array from the psuedo array arguments
        for(var i=0; i<toCopy.length; i++) {
            newArgs.push(toCopy[i]);
        }

        return newArgs;

    }

    args = concat(args, arguments);

    // the scope is the first argument always passed to the bind method
    var scope = args.shift();
    var method = this;
    return function() { return method.apply(scope, concat(args, arguments)); };
};

function getCookieValue(cookieName) {

    var istart = document.cookie.indexOf(cookieName);

    if (istart == -1)
        return "";

    istart += cookieName.length + 1; // for the "="

    var iend = document.cookie.indexOf(";", istart);

    if (iend == -1)
        iend = document.cookie.length; // must be last cookie

    return document.cookie.substring(istart, iend);

}

createCookie = function(name,value,days,domain) {
    if(!domain) {
        domain = "trapster.com";
    }
    var expires = null;
    if(days) {
        var date = new Date();
        date.setTime(date.getTime() + (days*24*60*60*1000));
        expires = "; expires=" + date.toGMTString();
    } 
    else  {
        expires = "";
    }

    document.cookie = name+"="+value+expires+"; domain="+domain+"; path=/";
};

$(document).ready(function() {
    document.directionsA = "";
    document.directionsB = "";
});
