function Map(id, defaultCoords, defaultZoom)
{
	this.IsEnabled = typeof GBrowserIsCompatible != 'undefined';

	if (!this.IsEnabled)
	{
		var div = $get(id);
		div.innerHTML = "<img src='" + g_BaseURL + "Images/map-noconnection.png" + "'/>";
		return;
	}
	
	// init
	if (GBrowserIsCompatible()) 
		this.map = new GMap2($get(id));		
	else
		return;
	
	$addHandler(document.body, 'unload', function() { GUnload(); alert('unloading'); });
	
	this.SetCenter(37, -95, 4);
	
	var mapControl = new GHierarchicalMapTypeControl();
	mapControl.clearRelationships();
	mapControl.addRelationship(G_SATELLITE_MAP, G_HYBRID_MAP, "Labels", false);
	
	this.map.addControl(mapControl);
	this.map.addControl(new GLargeMapControl());
	
	this.markerManager = new MarkerManager(this.map, {trackMarkers:true});	
	this.geocoder = new GClientGeocoder();
	
	this.map.enableScrollWheelZoom();
		
	this.SetCenter(defaultCoords.Lat, defaultCoords.Lng, defaultZoom);
		
	// handlers
	var instance = this;
	
	// move handlers
	GEvent.addListener(this.map, "movestart", function() {
		if (!instance._moveStartCenter)
			instance._moveStartCenter = instance.map.getCenter();
	});		
	
	GEvent.addListener(this.map, "moveend", function() { instance.MapMoved(); });
}

Map.prototype.MapMoved = function() {
	if (typeof this.OnMapMoved == 'function') {		
		var bounds = this.map.getBounds();

		if (this._moveStartCenter) {
			var considerable = !bounds.containsLatLng(this._moveStartCenter);
			if (considerable)
				this._moveStartCenter = null;

			this.OnMapMoved(considerable, this.GetZoom());
		}
	}
}

Map.prototype.ClearMarkers = function()
{
	this.markerManager.clearMarkers();
	this.map.clearOverlays();
}

Map.prototype.SetCenter = function(latitude, longitude, zoom)
{
	this.map.setCenter(new GLatLng(latitude, longitude), zoom);
}

Map.prototype.SetZoom = function(level)
{
	this.map.setZoom(level);
}

Map.prototype.GetZoom = function()
{
	return this.map.getZoom();
}

Map.prototype.ShowInfoWindow = function(latitude, longitude, domElement)
{
  var point = new GLatLng(latitude, longitude);
  this.map.openInfoWindow(point, domElement);
}

Map.prototype.HideInfoWindow = function()
{
  this.map.closeInfoWindow();
}

Map.prototype.SetViewPort = function(swLat, swLong, neLat, neLong)
{
	if (!this.IsEnabled)
		return;

  var sw = new GLatLng(swLat, swLong);
  var ne = new GLatLng(neLat, neLong);
  
  var bounds = new GLatLngBounds(sw, ne);
  
  var zoom = this.map.getBoundsZoomLevel(bounds);
  
  this.map.setCenter(bounds.getCenter(), zoom);  
}

Map.prototype.AddMarker = function(latitude, longitude, imgSrc, handlers)
{
	var img = new GIcon();
   
	img.image = imgSrc;
	img.shadow = null;	
	
	img.iconSize = new GSize(24, 25);	
	img.iconAnchor = new GPoint(10,28);
	img.infoWindowAnchor = new GPoint(0,0);
			
	markerOptions = { icon: img };
	
	var point = new GLatLng(latitude, longitude);
	var marker = new GMarker(point, markerOptions);
	
	if (handlers)
	{
	  for (var k in handlers)
	  {
	    GEvent.addListener(marker, k, handlers[k]);
	  }
	}
	
	this.map.addOverlay(marker);
}

Map.prototype.AttachZoomHandler = function(handler)
{
	if (!this._zoomHandlerAttached)
	{
		this._zoomHandlerAttached = true;

		GEvent.addListener(this.map, "zoomend", handler);
	}
}

Map.prototype.AttachOnLoadHandler = function(handler)
{
	GEvent.addListener(this.map, "load", handler);
}

Map.prototype.GetBounds = function()
{
	var bounds = this.map.getBounds();	
	
	var sw = bounds.getSouthWest();
	var ne = bounds.getNorthEast();
	
	return {swLat : sw.lat(), swLng : sw.lng(), neLat : ne.lat(), neLng : ne.lng() };
}

Map.prototype.GetDirections = function(from, to, directionsDIV, onError, onLoad)
{
	if (!this.gdir)
	{
		this.gdir = new GDirections(this.map, directionsDIV);
		
		var gdir = this.gdir;
		
		if (typeof onLoad == 'function')
			GEvent.addListener(this.gdir, "load", onLoad)
		
		GEvent.addListener(this.gdir, "error", function() 
			{ 
				var error = null;
				var statusCode = gdir.getStatus().code;
				
				switch (statusCode)
				{
					case G_GEO_UNKNOWN_ADDRESS:
						error = "No corresponding geographic location could be found for one of the specified addresses. This may be due to the fact that the address is relatively new, or it may be incorrect.";
						break;
					case G_GEO_SERVER_ERROR:					
						error = "A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.";
						break;
					case G_GEO_MISSING_QUERY:
						error = "The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.";
						break;
					case G_GEO_BAD_REQUEST:
						error = "A directions request could not be successfully parsed.";
						break;
					default:  
						error = "An unknown error occurred.";	   
						break;
				}
					
				directionsDIV.innerHTML = "<div class='ErrorBlock'>" + error + "</div>";
				
				if (typeof onError == 'function')
					onError();
			});

	}
		
	this.gdir.load("from: " + from + " to: " + to, { "locale" : "en_US" });
}

Map.prototype.RefreshSize = function()
{
	this.map.checkResize();
}