/**
 * jquery.googlemap v1.0.0
 *
 * Copyright David Hong 2009
 * http://davidhong.id.au/jquery/google/maps/
 *
 * Simplified Google Maps API integrated into jQuery
 *
 * Launched: <TBA>
 * Version: v1.0.0 (27/02/2009 15:59 AEDST)
 *
 **/
(function($) {
    function fireEvent(opts, fn, self, arg) {
        if ($.isFunction(fn)) {
            try {
                return fn.call(self, arg);
            } catch (error) {
                if (opts.debug) {
                    alert("Error calling googlemaps." + fn + ": " + error);
                } else {
                    throw error;
                }
                return false;
            }
        }
        return true;
    }
    var current = null;
    function Googlemap(root, conf) {
        var self = this;
        if (!current) {
            current = self;
        }
        var map;
        var geo;
        var bounds;
        var markers;
        var latitude    = conf.latitude;
        var longitude   = conf.longitude;
        var zoom        = conf.zoom;
        var controls    = conf.controls;
        var labels      = conf.labels;
        var html        = conf.html;
        var anchor      = conf.anchor;
        var addresses   = conf.addresses;
        var debug       = conf.debug;
        $.extend(self, {
            getVersion: function() { return [1, 0, 0]; },
            getRoot: function() { return root; },
            getMap: function() { return map; },
            getGeo: function() { return geo; },
            getAddresses: function() { return addresses; },
            getBounds: function() { return bounds; },
            getMarkers: function() { return markers; },
            isBrowserCompatible: function() {
                if ($.isFunction(GBrowserIsCompatible))
                    return GBrowserIsCompatible();
                return false;
            },
            initialise: function() {
                if (self.isBrowserCompatible()) {
                    map         = map || new GMap2(document.getElementById($(root)[0].id));
                    geo         = geo || new GClientGeocoder();
                    bounds      = bounds || new GLatLngBounds();
                    markers     = markers || new Array();
                    GEvent.addListener(map, "load", function() {});
                    map.setCenter(new GLatLng(latitude, longitude), zoom);
                    if (addresses) {
                        if (addresses.length > 0) {
                            var i = 0;
                            while (i < addresses.length) {
                                self.geocode(i++);
                            }
                        }
                    }
                    if (controls) {
                        map.addControl(new GSmallMapControl());
                        map.addControl(new GMapTypeControl());
                    }
                }
            },
            geocode: function(index) {
                geo = (geo == null) ? new GClientGeocoder() : geo;
                if (addresses && index >= 0) {
                    markers = markers || new Array();
                    geo.getLocations(addresses[index], function(response) {
                        var statuscode = response.Status.code;
                        if (statuscode == G_GEO_SUCCESS) {
                            var point = new GLatLng(response.Placemark[0].Point.coordinates[1], response.Placemark[0].Point.coordinates[0], true);
                            bounds = bounds || new GLatLngBounds();
                            bounds.extend(point);
                            var marker = self.createMarker(index, point);
							GEvent.addListener(marker, "click", function() {
								zoom = 15;
								map.setCenter(marker.getLatLng(), zoom);
							});
                            markers[index] = marker;
                            map.addOverlay(marker);
            				if (fireEvent(conf, self.onMarkerLoaded, self, index) === false) {
            					return self;
            				}
                        } else {
                            if (statuscode == G_GEO_TOO_MANY_QUERIES) {
                                var delay = 600;
                                setTimeout(function() {
                                    self.geocode(index);
                                }, delay);
                            } else {
                                marker[index] = null;
                            }
                        }
                    });
                }
            },
            onMarkerLoaded: function(index) {
                return self.optimiseZoomLevel();
            },
            optimiseZoomLevel: function(index) {
                if (bounds && (addresses.length == markers.length)) {
					zoom = map.getBoundsZoomLevel(bounds);
                    map.setZoom(zoom);
                    map.setCenter(bounds.getCenter());
                }
                return true;
            },
            createMarker: function(index, point) {
                var baseIcon = new GIcon(G_DEFAULT_ICON);
                baseIcon.shadow = "http://www.google.com/mapfiles/shadow50.png";
                baseIcon.iconSize = new GSize(20, 34);
                baseIcon.shadowSize = new GSize(37, 34);
                baseIcon.iconAnchor = new GPoint(9, 34);
                baseIcon.infoWindowAnchor = new GPoint(9, 2);
                var range = "Z".charCodeAt(0) - "A".charCodeAt(0) + 1;
                var letter = String.fromCharCode("A".charCodeAt(0) + (index % range));
                var letteredIcon = new GIcon(baseIcon);
                letteredIcon.image = "/static/four/map.marker.png";
                var markerOptions = {
                    icon: letteredIcon,
                    bouncy: true
                };
                var marker = (labels) ? new GMarker(point, markerOptions) : new GMarker(point);
                return marker;
            },
            trace: function() {
                if (!debug) return;
                var caller = arguments.caller || "self";
                for (i = 0; i < arguments.length; i++) {
                    var argument = arguments[i];
                    var line = argument;
                    try {
                        console.debug(line);
                    } catch (error) {
                        alert(line);
                    }
                }
            }
        });
        function load() {
            self.initialise();
            return self;
        }
        load();
    }
	jQuery.prototype.googlemap = function(conf) {
        var api = this.eq(typeof conf == 'number' ? conf : 0).data("googlemap");
        if (api) { return api; }
        var opts = {
            latitude: 51,
            longitude: 0,
            zoom: 4,
            labels: true,
            controls: true,
            html: null,
            anchor: null,
            addresses: null,
            debug: false
        };
        $.extend(opts, conf);
		this.each(function() {
			var el = new Googlemap($(this), opts);
			$(this).data("googlemap", el);
		});
		return this;
    };
})(jQuery);
