var map;
var google_map_center_latitude;
var	google_map_center_longitude;
var	google_map_default_zoom;

function initialize(mapElementId) {
	if (GBrowserIsCompatible()) {
		map = new GMap2(document.getElementById(mapElementId));
		map.setCenter(new GLatLng(google_map_center_latitude, google_map_center_longitude), google_map_default_zoom);
		//map.addControl(new GLargeMapControl());
		
		var customUI = map.getDefaultUI();
		//customUI.controls.scalecontrol = false;
		customUI.controls.largemapcontrol3d = false;
		customUI.zoom.scrollwheel = true;
		customUI.maptypes.normal = true;
		customUI.maptypes.satellite = true;
		customUI.maptypes.hybrid = true;
		customUI.maptypes.physical = false;
		customUI.controls.largemapcontrol3d = true;
		customUI.controls.smallzoomcontrol3d = false;
		customUI.controls.scalecontrol = false;
		map.setUI(customUI);
		changed_view(1); // Show start points
		// Happens repeatedly when dragging...
		GEvent.addListener(map, "move", function() {
			dragging_move();
		});
		// Data is updated when these Events happen:
		GEvent.addListener(map, "moveend", function() {
			dragging_ended();
		});
		GEvent.addListener(map, "zoomend", function() {
			changed_view(1);
		});
	}
}

function CenterMap(lngNew, latNew, zoomNew) {
	if (GBrowserIsCompatible()) {
		if (map != null) {
			map.setCenter(new GLatLng(latNew, lngNew), zoomNew);
		} else {
			google_map_center_latitude = latNew;
			google_map_center_longitude = lngNew;
			google_map_default_zoom = zoomNew;
		}
	}
}

// - - - Updating of moves, dragging and end-of-drag:
var time_last_drag_move = -1;
var time_diff_drag_abs	= 1100;		// 1.1 of a second (I think).
var old_drag_lon = -1;
var old_drag_lat = -1;

var lastZoom = -1;
var lastBounds;
// Important -- stores shown data pts.
var cached_Mks = {};

function dragging_move() {
	var now = new Date();
	now = now.getTime();
	if (now - time_last_drag_move > time_diff_drag_abs) {
		changed_view(0);
		time_last_drag_move = now;
		return;
	}
}

function dragging_ended() {
	time_last_drag_move = -1;
	changed_view(0);
}

function changed_view(zoomp) {
	var bounds = map.getBounds();
	var southWest = bounds.getSouthWest();
	var nE = bounds.getNorthEast();
	// Seems to send events for both zoom and move when zooming, so
	// zoom event is probably not needed. But take it anyway so it
	// works if changes...
	if (map.getZoom() == lastZoom && typeof(lastBounds) == 'object') {
		var tmp = lastBounds.getSouthWest();
		// If size changes, should change all 4 points?
		if (southWest.lng()==tmp.lng() && southWest.lat()==tmp.lat()) {
			tmp = lastBounds.getNorthEast();
			if (nE.lng() == tmp.lng() && nE.lat() == tmp.lat()) {
				return;
			}
		}
	}
	if (zoomp) {
		// Throw away all data when changing zoom:
		clear_all_overlays();
	}
	// Remember old:
	lastBounds = new GLatLngBounds(southWest, nE);
	lastZoom  = map.getZoom();
	var bounds = map.getBounds();
	var southWest = bounds.getSouthWest();
	var northEast = bounds.getNorthEast();
	get_json_pts('/'+ northEast.toUrlValue() + '/'	+ southWest.toUrlValue());
}

function clear_all_overlays() {
	map.clearOverlays();
	cached_Mks = {};
}

function get_json_pts(area) {
	//var request = GXmlHttp.create(); (Didn't work...)
	var request = mk_xmlhttpreq();
	// Handle set names!!

	var urltxt = 'points/BeginProcces'+area+'/'+map.getZoom();
	//document.getElementById("urltxtinput").value = urltxt; // debug only
	request.open('GET', urltxt , true);

	request.onreadystatechange = mkUpdateFun(request);
	request.send(null);
}

// Create Google Marker:
var zoffset = 0;
// Z index idea from Esa Ilmari and (as usual) econym.demon.co.uk
function mkMarker(point, tag, opts, url, multi) {
	var marker;
	var icon	= opts['icon'];
	// - - - Make GMarker object (with options):
	var markerOptions = {};
	if (opts['z']) {
		var z = opts['z'];
		markerOptions['zIndexProcess']= function(marker,b) {
			zoffset++;
			return z * (10000000 + zoffset);
		};
	}
	if (tag)  { markerOptions['title']= tag; }
	if (icon) { markerOptions['icon'] = icon; }
	marker = new GMarker(point, markerOptions);

	if (url != null) {
		GEvent.addListener(marker, "click", function() {
			document.location.href=url;
		});
	}

	if (multi != null) {
		GEvent.addListener(marker, "click", function() {
			marker.openInfoWindowHtml(multi, {pixelOffset: new GSize(10, 10)});
		});
	}

	return marker;
}

	// Icon stuff:
	var aggregI, multipI, mulbigtipI;

	function getAggregIcon() {
		if (!aggregI) {
			aggregI = new GIcon(G_DEFAULT_ICON, "/img/flag_full.png");
			aggregI.iconSize = new GSize(32, 29);
			aggregI.shadow = "";
		}
		return aggregI;
	}

	function getMultiPtIcon() {
		if (!multipI) {
			multipI = new GIcon(G_DEFAULT_ICON, "/img/flag_full.png");
			multipI.iconSize = new GSize(32, 29);
			multipI.shadow = "";
		}
		return multipI;
	}
	
	function getMultiPtBigIcon() {
		if (!mulbigtipI) {
			mulbigtipI = new GIcon(G_DEFAULT_ICON, "/img/flag_big.png");
			mulbigtipI.iconSize = new GSize(40, 26);
			mulbigtipI.shadow = "";
		}
		return mulbigtipI;
	}

// Used to get a unique ID on every op. (If move map twice, so a second
// move is started before last one is finished.)
var uppdateID = 1;
var presentUpd=-1;

function mkUpdateFun(request) {
	var localUpdate = ++uppdateID;
	var f = function() {
		if (request.readyState != 4) { return; }

		// If moves twice before has time to update...
		//if (localUpdate != uppdateID) { return 0; }
		var now = new Date();
		now = now.getTime() % 1000000;
		if (presentUpd > localUpdate) {
			// A later update has already been received...
			return 0;
		}
		presentUpd = localUpdate;
		var jscript = request.responseText;	// (From server.)

		var points  = undefined;

		eval(jscript);						// Set value in 'points'.
		// (Used in loop below, probably faster to get value once.)
		var zoomnow = map.getZoom();
		// N B -- do ugly thing by replacing point info w Marker...
		for (i in points) {
			if (points.errormsg) {
			    delete points;
			    continue;
			}

			if (cached_Mks[i]) {
				// This pt is already visible on map. Don't
				// do anything.
				points[i] = cached_Mks[i];
				cached_Mks[i] = null;
				continue;
			}
			if (points[i].lat > 89.99) { continue; } // Garbage.
			var aggIcon = getAggregIcon(points[i]);
			var mulIcon = getMultiPtIcon(points[i]);
			var m;
			var pll = new GLatLng(points[i].lat,points[i].lon);
			if (points[i].typ == '+') {
				// Multiple-points-Icon
				m =mkMarker(pll,points[i].t, { icon:  mulIcon });
			} else {
				// Handle other types differently. Normal Icon.
				m = mkMarker(pll,   points[i].t, { icon:  aggIcon });
			}
			// N B -- Overwrites spec of pt.
			points[i] = m;
			map.addOverlay(m);
		}

		// Delete Markers that aren't visible anymore:
		for (i in cached_Mks) {
			var marker = cached_Mks[i];		// Can be set to null above
			if (marker) { map.removeOverlay(marker); }
		}
		cached_Mks = points;
	};

	return f;
}

// Monopolists have business motivation not to work with standards,
// so they aren't compatible with anyone but themselves.
function mk_xmlhttpreq () {
	var xh = GXmlHttp.create();
	if (xh != null) { return xh; }
	// Std IExploder:
	try {
		xh = new ActiveXObject("Msxml2.XMLHTTP");
		return xh;
	} catch (e) { }
	try {
		xh = new ActiveXObject("Microsoft.XMLHTTP");
		return xh;
	} catch (e) { }
	try {
		xh = new XMLHttpRequest();
		return xh;
	} catch (e) { }
	// Only other way I could find...
	try {
		xh = window.createRequest();
		return xh;
	} catch (e) { }
	return undefined;
}
