// jQuery Google Maps Plug-In
//
// This plug-in requires the open source
// MarkerManager utility, not the GMarkerManager
// included in the Google Maps API, which still
// lacks some vital features
//
// Kelli Shaver - kelli@enhancesoft.com
//
// vim: expandtab sw=4 ts=4 sts=4:    

(function($) { 
    // only one map per page, please.
    $.fn.jqmap = function(options) { // map defaults 
        var settings = jQuery.extend({
            json_url:               'map_data.php',        
            zoom:                   1,
            maptype:                G_NORMAL_MAP,
            icon:                   'http://www.google.com/mapfiles/marker.png',
            iconshadow:             'http://www.google.com/mapfiles/shadow50.png',
            iconsize:               [20, 34],
            shadowsize:             [37,34],
            iconanchor:             [9, 34],
            infowindowanchor:       [9, 2],
            loadingindicator:       './images/loading.gif',
            loading_width:          32,
            loading_height:         32,
            callback:               null
        }, options);
        
        map_box = this; // the map container... we'll need to apply some CSS and add content.

        // check for compatability, return empty div if incompatible.
        if (!window.GBrowserIsCompatible || !GBrowserIsCompatible()) return this;

        // make our map..
        // why the hell doesn't new GMap2(this) work?
        // i don't care anymore....
        $jqmap = new GMap2(document.getElementById(this.attr('id')));
        $jqmap.setCenter(new GLatLng(0, 0), settings.zoom);
        $jqmap.setMapType(settings.maptype);
        $jqmap.setUIToDefault();
        $jqmap.enableScrollWheelZoom();

        // brand new map! show the loading indicator - messy, but it works.
        $(map_box).append('<img id="loading" src="'+settings.loadingindicator+'" width="'+ settings.loading_width +'" height="'+ settings.loading_height +'" style="position:absolute; top:50%; left:50%; margin:-21px 0 0 -21px; padding:5px; background:#fff; z-index:3000; border:1px solid #000;" />');
    
        // bits of stuff used for things
        var mgr = new MarkerManager($jqmap);
        all_markers = [];
        remaining_markers = [];
        markerBounds = new GLatLngBounds();
        
        // loads a set of markers from an external json file
        $.fn.jqmap.load_marker_set = function(json_url, callback) {
            $('#loading', $(map_box)).show(); // loading exterhanl files may take a while...
            $.getJSON(json_url, function(data) {
                $(data.places).each(function() {
                    $.fn.jqmap.add_marker(this, callback);
                });
                $('#loading', $(map_box)).animate({opacity:1}, 1000).fadeOut('slow'); // all done!
            });
        }

        // adds a single marker from json data passed directly to it when it's
        // called directly, or via the plugin when loading a set of markers
        $.fn.jqmap.add_marker = function(place, callback) {
            // make sure the marker isn't already present.... 
            mrk = all_markers[place.mid];
            if(typeof mrk != 'undefined') mrk.show(); // if it already exists, make sure it's visible
            else { 
                if(place.lat != 0 && place.lng != 0) {
                    // build the map icon.
                    gmap_icon = new GIcon();
                    
                    // icon properties, grab them from json or use the defaults passed when the plugin is called.
                    (place.marker.icon)         ? gmap_icon.image      = place.marker.icon       : gmap_icon.image = settings.icon;
                    (place.marker.iconshadow)   ? gmap_icon.shadow     = place.marker.iconshadow : gmap_icon.shadow = settings.iconshadow;
                    (place.marker.iconSize)     ? gmap_icon.iconSize   = place.marker.iconSize   : ($.isArray(settings.iconsize)) ? new GSize(settings.iconsize[0], settings.iconsize[1]) : settings.iconsize;
                    (place.marker.shadowSize)   ? gmap_icon.shadowSize = place.marker.shadowSize : ($.isArray(settings.shadowsize)) ? new GSize(settings.shadowsize[0], settings.shadowsize[1]) : settings.shadowsize;
                    
                    // and the anchor positions for the info window, which we don't really need to change...
                    gmap_icon.iconAnchor       = ($.isArray(settings.iconanchor)) ? new GPoint(settings.iconanchor[0], settings.iconanchor[1]) : settings.iconanchor;
                    gmap_icon.infoWindowAnchor = ($.isArray(settings.infowindowanchor)) ? new GPoint(settings.infowindowanchor[0], settings.infowindowanchor[1]) : settings.infowindowanchor;
                
                    // make the marker.
                    gmap_marker = new GMarker(new GPoint(place.lng, place.lat), gmap_icon);
                    
                    // attach info...
                    gmap_marker.bindInfoWindowHtml(build_info_window(place.marker.letter, place.title, place.description));
                    
                    // make sure the marker is within the bounding box for visible map area. 
                    point = new GLatLng(place.lat, place.lng);
                    markerBounds.extend(point);
                    
                    // set zoom levels in which marker is visible
                    (place.minZoom)? min_zoom = place.minZoom : min_zoom = 0;
                    (place.maxZoom)? max_zoom = place.maxZoom : max_zoom = 17;
                    
                    // add the zoom level data to the marker object, so we can use it
                    // again later when re-attaching the marker, should it get removed.
                    gmap_marker.min_zoom = min_zoom;
                    gmap_marker.max_zoom = max_zoom;
                    
                    // add to marker manager and our master list of markers.
                    mgr.addMarker(gmap_marker, min_zoom, max_zoom);
                    all_markers[place.mid] = gmap_marker;
                    // all_markers.push(gmap_marker);
        
                    // zoom and center
                    $.fn.jqmap.center_map();
                    
                    // if we have a callback, do it.
		            if(typeof callback == 'function') callback();
		            
		            // returns the mID of the marker so we can find it in the
		            // master array of markers, for easy management later
		            return place.mid;
		        }
		    }
        }
        
        // centers the map and sets zoom level to encomapss all points
        $.fn.jqmap.center_map = function() {
            $jqmap.setCenter(markerBounds.getCenter(), 
            $jqmap.getBoundsZoomLevel(markerBounds));
        }

        // hide all markers - actually removes them (better performance)
        $.fn.jqmap.hide_markers = function() {
            mgr.clearMarkers(); 
        }

        // show all markers - puts them back
        $.fn.jqmap.show_markers = function() {
            // not the most efficient, but MarkerManager:addMarkers()
            // won't work here if the markers have different zoom levels
            for(var index in all_markers) {
                marker = all_markers[index];
                mgr.addMarker(marker,marker.min_zoom, marker.max_zoom);
            }
            mgr.refresh();
            $.fn.jqmap.center_map();
        }

        // hide single marker - this only hides for current zoom level
        // we need to either accept that as a "feature" or extend
        // MarkerManger:hide() to include a fix...
        $.fn.jqmap.hide_marker = function(mid) {
            all_markers[mid].hide();
        }

        // show single marker - and if we fix hide, we'll need to
        // extend show as well
        $.fn.jqmap.show_marker = function(mid) {
            all_markers[mid].show();
        }

        // remove single marker
        $.fn.jqmap.delete_marker = function(mid) {
            all_markers[mid].remove();
            // this is messy
            for(var index in all_markers) {
                if (index != mid) remaining_markers[index] = all_markers[index];
            }
            if(all_markers = remaining_markers) remaining_markers = [];
        }

        // builds the info window for the marker (pass strings from json) - a bit kludgy
        function build_info_window(letter, title, description) {
            (letter) ? letter = letter + '. ' :  letter = '';
            if (undefined == title) title='Untitled';
            if (undefined == description) description = '<em>No description available...</em>';        
            infowindow = '<div class="marker_info"><strong>%letter%%title%</strong><p>%description%</p>';
            return infowindow.replace('%letter%', letter).replace('%title%', title).replace('%description%', description);
        }

        // load the first marker set
        $.fn.jqmap.load_marker_set(settings.json_url);
    }
})(jQuery); // i love javascript, except for when i hate it.

