if (typeof BP == "undefined") { 
    var BP = {}
}

runOnLoad(function() {
    $('.js-map').each(function(){
        BP.Map($(this))
   });
});

BP.debug = function(){
    return;
}

// A function to install handle a submit blocker for a text field for handling
// the enter key.
BP.SubmitBlocker = function(form, field, action) {

    if (!form.length) {
        return;
    }

    field.bind('focus', function() {
        form.bind('submit', action);
    }).bind('blur', function() {
        form.unbind('submit', action);
    });
}

BP.CreateMarker = function(lonlat) {
    var lonlatClone = lonlat.clone().transform(new OpenLayers.Projection('EPSG:4326'), new OpenLayers.Projection('EPSG:900913'));
    var marker = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(lonlatClone.lon, lonlatClone.lat));
    return marker;
};

BP.Map = function(jObj) {
    
    // Verify JS support
    if ((typeof(GBrowserIsCompatible) == 'undefined' || (!GBrowserIsCompatible()))){
        BP.debug("Map: Google Map API not loaded or unsupported browser");
        return;
    }

    // Get required elements
    var mapdiv = jObj.show();
    
    if (!mapdiv.length) {
        BP.debug("Map: Could not find map div");
        return;
    } 

    // If we have a parent form, we'll put in a submit blocker when the text control has focus, and add some inputs.
    var parent_form = mapdiv.parents('form');

    // Look for an existing latitude/longitude pair.
    var input_latitude = $('#' + mapdiv.get(0).id + '-latitude');
    var input_longitude = $('#' + mapdiv.get(0).id + '-longitude');
    var input_highlight = $('#' + mapdiv.get(0).id + '-highlight');

    // If we have only one coordinate, we can't properly proceed
    if ((input_latitude.length && !input_longitude.length) || (input_longitude.length && !input_latitude.length)) {
        BP.debug("Map: Missing " + (input_latitude.length ? 'longitude' : 'latitude') + ' coordinate');
        return;
    }

    // If we have a form, we need to hook up our UI.
    if (parent_form.length) {
        // If we don't have the coordinate inputs, we will create them.  If we do have elements
        // with inputs, we'll make sure they're elements we can use as inputs.
        if (!input_latitude.length) {
            jQuery.each(['latitude', 'longitude'], function() {
                var prop = mapdiv.get(0).id + '-' + this;
                $('<input type="hidden" />').attr('id', prop).attr('name', prop).insertBefore(mapdiv);
                eval('input_' + this + ' = $("#' + prop + '");');
            });
    
        } else if (('input' != input_latitude.get(0).tagName.toLowerCase()) || ('input' != input_longitude.get(0).tagName.toLowerCase()) ||
            !(input_latitude.get(0).type in {hidden:'', text:'', textarea:''}) ||
            !(input_latitude.get(0).type in {hidden:'', text:'', textarea:''})) {
    
            // The elements wre either not input fields, or input fields that can't hold our
            // latitude and longitude values.
            BP.debug("Map: Bad initialization coordinates");
            return;
        }

        // Create the controls used to update the map
        var control_button = mapdiv.before('<input class="indented-submit" type="button" value="Find this address" />').prev();
        var control_error = mapdiv.before('<div style="text-align:center" class="error-message" />').prev();
        var control_info = mapdiv.before('<div style="text-align:center" class="info-message" />').prev();
    
        // Function that takes a geocoder response and adjusts the map accordingly
        var updateMap = function(response) {
          if (!response || response.Status.code != 200) {
              control_error.text("Sorry, we were unable to find that address on the map");
              control_info.text("");
          } else {
              eventsLayer.removeFeatures(eventsLayer.features); // TODO: maybe just move marker?
              control_error.text('');
              control_info.text('Click and drag the marker on the map to adjust the party location');
              var place = response.Placemark[0];
              var lonlat = new OpenLayers.LonLat(place.Point.coordinates[0],
                                  place.Point.coordinates[1]);
              input_latitude.get(0).value = lonlat.lat;
              input_longitude.get(0).value = lonlat.lon;
              var marker = BP.CreateMarker(lonlat);
              eventsLayer.addFeatures([marker]);

              lonlat.transform(new OpenLayers.Projection('EPSG:4326'), map.getProjectionObject());
              map.setCenter(lonlat, 15);
          }
        }
    
        // We need a function that will take the desired text input, and submit it to Google
        // Maps.  Once we have it, we will set it up so that a click of the button or hitting
        // enter will perform the work.  In order to handle pressing enter, whenever the text
        // area has focus, we install a new submit handler for the parent form which cancels the
        // submit and instead performs the geocoding.  We remove this handler whenever the
        // text control loses focus.
        control_button.geocode = function() {
            var address = [ $('#address').val() , $('#city').val(), $('#state').val(), $('#zip_code').val()].join(',')
            geocoder.getLocations(address, updateMap);
            return false;
        }
        // Install click handler for the button
        control_button.bind('click', control_button.geocode);

        // Install onfocus and onblur handlers for the text control to handle the enter key.
        BP.SubmitBlocker.call(this, parent_form, $('.submit-block'), control_button.geocode);
    
    } else {
	    BP.debug("no parent form, must be a map just for viewing");
    }

    var bounds = new OpenLayers.Bounds(
        -2.003750834E7,-2.003750834E7,
        2.003750834E7,2.003750834E7
    );
    var options = {
        projection: new OpenLayers.Projection('EPSG:900913'),
        maxExtent: bounds
    };
    var map = new OpenLayers.Map(mapdiv.get(0).id, options);
    var streetLayer = new OpenLayers.Layer.Google('Google Streets', {numZoomLevels: 20, sphericalMercator: true});
    map.addLayer(streetLayer);
    var layerOptions = {
        projection: 'EPSG:4326',
        styleMap: new OpenLayers.StyleMap({
            externalGraphic: "/icons/yellow_flower.png",
            backgroundGraphic: "/icons/flower_shadow.png",
            graphicWidth: 46,
            graphicHeight: 47,
            graphicYOffset: -48,
            backgroundXOffset: -12,
            backgroundYOffset: -48,
            graphicZIndex: 11,
            backgroundGraphicZIndex: 10
        }),
        rendererOptions: {yOrdering: true}
    };
    var eventsLayer = new OpenLayers.Layer.Vector("Events", layerOptions);
    map.addLayer(eventsLayer);

    // Try to get initialization coordinates
    var lat = input_latitude.length ? input_latitude.val() : '';
    var lon = input_longitude.length ? input_longitude.val(): '';
    var highlight = input_highlight.length ? input_highlight.val().toLowerCase(): '';

    if ((0 == lat.length) || (0 == lon.length)) {
        // Lat/Lon of TOPP
        var center = new OpenLayers.LonLat(-74.006952, 40.738067);
    } else {
        // We have preexisting coordinates, so we'll make a marker.
        var center = new OpenLayers.LonLat(lon, lat);
        var marker = this.CreateMarker(center); 
        eventsLayer.addFeatures([marker]);
    }

    // Enable dragging if we're on a page with a form
    if (parent_form.length) {
        var dropHandler = function(marker, pixel) {
            var lonlat = marker.geometry.getBounds().getCenterLonLat();
            lonlat.transform(new OpenLayers.Projection('EPSG:900913'), new OpenLayers.Projection('EPSG:4326'));
            input_latitude.get(0).value = lonlat.lat;
            input_longitude.get(0).value = lonlat.lon;
        };
        var dragFeature = new OpenLayers.Control.DragFeature(eventsLayer, {onComplete: dropHandler});
        map.addControl(dragFeature);
        dragFeature.activate();
    }
    
    center.transform(new OpenLayers.Projection('EPSG:4326'), map.getProjectionObject());
    map.setCenter(center, 13);

    var geocoder = new GClientGeocoder();
};


