/**
 * @author Greg Pasquariello, P5 Technologies 
 * 
 * A simple map wrapper to show points using the given icon at the specified coordinates.  When
 * a point is clicked, calls back to the application to fetch a DIV to be used in the 
 * info window, which it then pops up.
 * 
 * Though the wrapper is simple, it gives a great deal of flexibility to the calling application,
 * and allows for real nice and easy programming of the pain-in-the-ass google maps.
 */


if (typeof p5 == "undefined") var p5 = {};

//
// The map uses the following initializer:
// 	{
//		container: string,
//		latitude: decimal,
//		longitude: decimal,
//		zoomlevel: integer,
//		onFetchInfoWindow:  callback
//	}
//
p5.Map = function(initializer) {
	this.container = initializer.container ? initializer.container : null;
	this.latitude = initializer.latitude ? initializer.latitude : 0;
	this.longitude = initializer.longitude ? initializer.longitude : 0;
	this.zoomlevel = initializer.zoomlevel ? initializer.zoomlevel : 10;
	this.onFetchInfoWindow = initializer.onFetchInfoWindow;
	this.onZoomComplete = initializer.onZoomComplete;
	this.onPanComplete = initializer.onPanComplete;
	
	if (this.container !== null && GBrowserIsCompatible()) {
		this.gmap = new GMap2(this.container);
		this.gmap.object = this;
		
		//GEvent.addListener(this.gmap, "load", this.onMapLoaded);
	
		this.gmap.addControl(new GLargeMapControl());
		this.gmap.addControl(new GMapTypeControl());
		this.gmap.addControl(new GScaleControl());
		this.gmap.addControl(new GOverviewMapControl());

		this.gmap.setCenter(new GLatLng(this.latitude, this.longitude), this.zoomlevel);
		
		GEvent.addListener(this.gmap, "moveend", this.onMapMoveEnd)
		GEvent.addListener(this.gmap, "zoomend", this.onMapZoomEnd)
	}
};

p5.Map.prototype.points;
p5.Map.prototype.onFetchInfoWindow;
p5.Map.prototype.onPanComplete;
p5.Map.prototype.onZoomComplete;

p5.Map.prototype.onMapMoveEnd = function() {
	if (this.object.onPanComplete != null) {
		this.object.onPanComplete();
	}
}

p5.Map.prototype.onMapZoomEnd = function(oldLevel, newLevel) {
	if (this.object.onZoomComplete != null) {
		this.object.onZoomComplete(oldLevel, newLevel);
	}
}

//
// Adds an array of points to the map.  If no icon is specified, 
// no point is displayed.
//
p5.Map.prototype.addPoints = function(points) { 
	if (this.points == null) {
		this.points = [];
	}
	
	for(var idx=0; idx < points.length; idx++) {
		var point = points[idx];
		this.points.push(point);
	    
		if (point.icon != null) {
			//
			// now we create a GIcon for each point based on the icon specs, but this
			// should be cached, perhaps based on a icon name.
			//
			var icon = new GIcon();
		    icon.image = point.icon.image;
		    icon.shadow = point.icon.shadow;
		    icon.iconSize = new GSize(point.icon.imageWidth, point.icon.imageHeight);
		    icon.shadowSize = new GSize(point.icon.shadowWidth, point.icon.shadowHeight);
		    icon.iconAnchor = new GPoint(point.icon.anchorX, point.icon.anchorY);
		    icon.infoWindowAnchor = new GPoint(point.icon.infoWindowAnchorX, point.icon.infoWindowAnchorY);
			
			point.marker = new GMarker(new GLatLng(point.latitude, point.longitude), icon);
					
			//
			// potential memory leak here in IE, so be sure to remove the references on 
			// point.marker.obj and point.marker.point before destroying the pointer/marker.
			//
			point.marker.obj = this;
			point.marker.point = point;
			
			this.gmap.addOverlay(point.marker);
			GEvent.addListener(point.marker, "click", this.onPointMarkerClicked);
		}
	}
}

//
// Invoked when the user clicks on an icon.  The default behavior is
// to display the popup info window, the contents of which are grabbed
// from the point-level onFetchInfoWindow or the object level onFetchInfoWindow.
//
// If no html content is retrieved, no infoWindow is displayed.
//
p5.Map.prototype.onPointMarkerClicked = function() {
	var infoWindowHtml = null;
	
	// 
	// if there is an onFetchInfoWindow for the point, use it, otherwise
	// use the onFetchInfoWindow defined for the object.
	//
	if (this.point.onFetchInfoWindow != null) {
		infoWindowHtml = this.point.onFetchInfoWindow(this.point.appdata);
	}
	else {	
 		if (this.obj.onFetchInfoWindow != null) {
			infoWindowHtml = this.obj.onFetchInfoWindow(this.point.appdata);
		}
	}
	
	if (infoWindowHtml != null) {
		this.obj.showInfoWindow(this, infoWindowHtml);
	}
}

//
// Simply pops the info windows on the given marker with the given
// html.
//
p5.Map.prototype.showInfoWindow = function(marker, html) {
	marker.openInfoWindowHtml(html);
}

//
// Removes the points from both the google map and this.
//
p5.Map.prototype.clearPoints = function() 
{
	this.gmap.closeInfoWindow();
	
	//
	// Set marker.obj and marker.point to null to prevent mem leaks.
	// Then remove the marker from the map.
	//
    for (idx in this.points) {
        if (this.points[idx].marker != null) {
			this.points[idx].marker.obj = null;
			this.points[idx].marker.point = null;
			this.gmap.removeOverlay(this.points[idx].marker);
		}
    }
	
	this.points = null;
}