var centreLat=52.47028485794806;
var centreLon=4.768677805217449;
var buttonTextNormal="Kaart"; //Text that shows up on the button for the custom layer (n=normal, s=sat, h=hybrid)
var buttonTextSatellite="Satelliet";
var buttonTextHybrid="Beide";
var map; //the GMap2 itself
var mapBounds=new GLatLngBounds(new GLatLng(52.41717924550393,4.674043182918128),new GLatLng(52.52339047039219,4.863312427516771));
var opacity=0.5;

var dgmr = {};
dgmr.maxZoomLevel = 16; // TODO: show a warning when this zoom level is exceeded!
dgmr.tileLayer = null;
dgmr.mapLayers =	{ cumulatie_lden:	null
					, cumulatie_lnight: null
					, weg_lden: null
					, weg_lnight: null
					, rail_lden: null
					, rail_lnight: null
					, lucht_lden: null
					, lucht_lnight: null
					, industrie_lden: null
					, industrie_lnight: null
					};
dgmr.currentMapLayer = 'cumulatie_lden';
dgmr.locationMarker = null;


////////////////////////////////////////////////////////////////////////////////////////////////////
function customGetTileURL(a,b) {
  //converts tile x,y into keyhole string
  if (b<=6 || b>dgmr.maxZoomLevel) { return "../img/tiles/blank-tile.png"; };

  var c=Math.pow(2,b);
  var x=360/c*a.x-180;
  var y=180-360/c*a.y;
  var x2=x+360/c;
  var y2=y-360/c;
  var lon=x; //Math.toRadians(x); //would be lon=x+lon0, but lon0=0 degrees
  var lat=(2.0*Math.atan(Math.exp(y/180*Math.PI))-Math.PI/2.0)*180/Math.PI; //in degrees
  var lon2=x2;
  var lat2=(2.0*Math.atan(Math.exp(y2/180*Math.PI))-Math.PI/2.0)*180/Math.PI; //in degrees
  var tileBounds=new GLatLngBounds(new GLatLng(lat2,lon),new GLatLng(lat,lon2));

  if (!tileBounds.intersects(mapBounds)) { return "../img/tiles/blank-tile.png"; };
	var d=a.x;
	var e=a.y;
	var f="t";
	for(var g=0;g<b;g++){
		c=c/2;
		if(e<c){
			if(d<c){f+="q"}
			else{f+="r";d-=c}
		}
		else{
			if(d<c){f+="t";e-=c}
			else{f+="s";d-=c;e-=c}
		}
	}
	return '../img/tiles/' + dgmr.currentMapLayer + '/'+f+'.png'
}

////////////////////////////////////////////////////////////////////////////////////////////////////
function changeOpacity(op) {
	if(op != opacity) {
		opacity=op;
		forceMapRedraw();
	}
}


////////////////////////////////////////////////////////////////////////////////////////////////////
function getWindowHeight() {
	if (window.self && self.innerHeight) {
		return self.innerHeight;
	}
	if (document.documentElement && document.documentElement.clientHeight) {
		return document.documentElement.clientHeight;
	}
	return 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
function resizeMapDiv() {
	//Resize the height of the div containing the map.
	//Do not call any map methods here as the resize is called before the map is created.
	var d=document.getElementById("map");
	var offsetTop=0;
	for (var elem=d; elem!=null; elem=elem.offsetParent) {
		offsetTop+=elem.offsetTop;
	}
	
	var f=document.getElementById('footer');
	var footerTop=0;
	for (var elem=f; elem!=null; elem=elem.offsetParent) {
		footerTop+=elem.offsetTop;
	}
	
	var height = getWindowHeight() - f.offsetHeight - 48 - offsetTop;
	if (height>=0) {
		d.style.height=height+"px";
	}
}


////////////////////////////////////////////////////////////////////////////////////////////////////
function load() {
	if (GBrowserIsCompatible()) {
		resizeMapDiv();
		
		var copyright = new GCopyright(1, mapBounds, 6,
										'&copy; 2007 <a href="http://www.dgmr.nl" target="_blank">DGMR</a>');
		var copyrightCollection = new GCopyrightCollection("Geluidscontouren");
		copyrightCollection.addCopyright(copyright);
		
		// create our tile layers
		for(var geluidsoort in dgmr.mapLayers) {
			var dgmr_tileLayer = new GTileLayer(copyrightCollection, 0, dgmr.maxZoomLevel);
			dgmr_tileLayer.getTileUrl = customGetTileURL;
			dgmr_tileLayer.isPng = function() { return false; };
			dgmr_tileLayer.getOpacity = function() { return opacity; };
			dgmr.mapLayers[geluidsoort] = dgmr_tileLayer;
		}
		dgmr.tileLayer = dgmr.mapLayers[dgmr.currentMapLayer];

		var tileLayers;
		//create a custom G_NORMAL_MAP layer
		tileLayers =	[ G_NORMAL_MAP.getTileLayers()[0]
						, dgmr.tileLayer
						];
		var mapTypeNormal = new GMapType(tileLayers, new GMercatorProjection(20), buttonTextNormal,
										{maxResolution:19, minResolution:0, errorMessage:"Geen contouren beschikbaar"});

		//create a custom G_SATELLITE_MAP layer
		tileLayers =	[ G_SATELLITE_MAP.getTileLayers()[0]
						, dgmr.tileLayer
						];
		var mapTypeSatellite = new GMapType(tileLayers, new GMercatorProjection(20), buttonTextSatellite,
											{maxResolution:19, minResolution:0, errorMessage:"Geen contouren beschikbaar"});

		//create a custom G_HYBRID_MAP layer
		tileLayers =	[ G_HYBRID_MAP.getTileLayers()[0]
						, dgmr.tileLayer
						, G_HYBRID_MAP.getTileLayers()[1]
						];
		var mapTypeHybrid = new GMapType(tileLayers, new GMercatorProjection(20), buttonTextHybrid,
											{maxResolution:19, minResolution:0, errorMessage:"Geen contouren beschikbaar"});
		

		//Now create the custom map. Would normally be G_NORMAL_MAP,G_SATELLITE_MAP,G_HYBRID_MAP
		map = new GMap2(document.getElementById("map"), {mapTypes:[mapTypeNormal,mapTypeSatellite,mapTypeHybrid]} );
		map.addControl(new GLargeMapControl());
		map.addControl(new GMapTypeControl());
		map.addControl(new GScaleControl());
		var overviewMap = new GOverviewMapControl();
		map.addControl(overviewMap);
		overviewMap.hide();
		new GKeyboardHandler(map);
		map.enableContinuousZoom();
		map.enableScrollWheelZoom();
		var zoomLevel = map.getBoundsZoomLevel(mapBounds);
		map.hideControls();
		map.setCenter(new GLatLng(centreLat, centreLon), zoomLevel, mapTypeNormal);
		
		////'mouseover' listener shows controls
		GEvent.addListener(map, "mouseover", function(){
			map.showControls();
		});

		////'mouseout' listener hides controls
		GEvent.addListener(map, "mouseout", function(){
			map.hideControls(); 
		});
		
		////'zoomend' checks for maximum zoom level
		GEvent.addListener(map, "zoomend", mapZoomEnd)

		//// prevent page scroll
		function wheelevent(e) {
			if (!e) {
				e = window.event;
			}
			if (e.preventDefault){
				e.preventDefault();
			}
			e.returnValue = false;
		}
		GEvent.addDomListener(map.getContainer(), "DOMMouseScroll", wheelevent);
		map.getContainer().onmousewheel = wheelevent; 
	
		//// Hide info window when clicked on map
		GEvent.addListener(map, "click", 
							function(a_marker, a_point) {
//								alert('map.onclick(marker: ' + typeof a_marker + ', point: ' + typeof a_point + ')');
								if (a_marker) {
									map.removeOverlay(a_marker);
								}
								var infoWindow = map.getInfoWindow();
								if(!infoWindow.isHidden()) {
									infoWindow.hide();
								}
								if(dgmr.locationMarker != null) {
									map.removeOverlay(dgmr.locationMarker);
									dgmr.locationMarker = null;
								}
							}
						);
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
function searchLocation(a_form) {
	var geocoder = new GClientGeocoder();
	var address = a_form.location.value;
	
	// if no search keywords were entered, re-center the map on the area of interest
	if(address == '') {
		var zoomLevel = map.getBoundsZoomLevel(mapBounds);
		map.setCenter(new GLatLng(centreLat, centreLon), zoomLevel);
		return;
	}
	
	// 
	var bounds = map.getBounds();
	if(bounds.intersects(mapBounds)) {
		geocoder.setViewport(bounds);
	} else {
		geocoder.setViewport(mapBounds);
	}
	geocoder.setBaseCountryCode('nl');
	geocoder.getLocations(address, mapAddressesFound);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
function changeMap(a_layerElement) {
	if(a_layerElement.value != dgmr.currentMapLayer) {
		dgmr.currentMapLayer = a_layerElement.value;

		// Replace the tile layer
		var activeMapType = map.getCurrentMapType();
		var tileOverlays = activeMapType.getTileLayers();
		for(var i = 0; i < tileOverlays.length; i++) {
			if(tileOverlays[i] == dgmr.tileLayer) {
				tileOverlays[i] = dgmr.mapLayers[dgmr.currentMapLayer];
				(new GTileLayerOverlay(tileOverlays[i])).redraw(false);
				break;
			}
		}
		
		dgmr.tileLayer = dgmr.mapLayers[dgmr.currentMapLayer];
		
		// Now, we need to force a redraw of the map
		forceMapRedraw();
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
function mapAddressesFound(response) {
	map.clearOverlays();

	var address = response.name; // TODO: weghalen
		
	// TODO: remove debug code
	if(response) {
		var d = document.getElementById('debug');
		d.innerHTML = response.toJSONString().replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/([{\[])/g, '$1<blockquote>').replace(/([}\]])/g, '</blockquote>$1').replace(/","/g, '",<br/>"');
	}
	
	if (!response || response.Status.code != G_GEO_SUCCESS) {
		alert('"' + address + '" niet gevonden!');
	} else {
		if(response.Placemark.length == 1) {
			mapShowLocation(response.Placemark[0]);
		} else {
			mapShowLocation(response.Placemark[0]);
//			for(var p = 0; p < response.Placemark.length; p++) {
//				var place = response.Placemark[p];
//				point = new GLatLng(place.Point.coordinates[1],
//									place.Point.coordinates[0]);
//			}
		}
		return;
		
		place = response.Placemark[0];
		point = new GLatLng(place.Point.coordinates[1],
							place.Point.coordinates[0]);
		map.setCenter(point);
		
		dgmr.locationMarker = new GMarker(point, {title: response.name});
		map.addOverlay(dgmr.locationMarker);
		var html = '';
		try {
			html = place.address;
			// TODO: als postcode en straat/huisnummer is gevonden, geef dan ook de 
			// contourklasse weer

//				html = place.toJSONString().replace(/{/g, '{<blockquote>').replace(/}/g, '</blockquote>}').replace(/","/g, '",<br/>"');
//				html = place.AddressDetails.Country.AdministrativeArea.Locality.DependentLocality.Thoroughfare.ThoroughfareName + '<br/>'
//						+ place.AddressDetails.Country.AdministrativeArea.Locality.LocalityName
//						+ ' (' + place.AddressDetails.Country.AdministrativeArea.AdministrativeAreaName + ')'
		} catch(e) {
			html = place.address;
		}
		dgmr.locationMarker.openInfoWindowHtml(html);
		GEvent.addListener(dgmr.locationMarker, "dblclick", 
							function(a_marker, a_point) {
								alert('marker.ondblclick(marker: ' + typeof a_marker + ', point: ' + typeof a_point + ')');
//									alert('marker.ondblclick(' + (a_marker == null ? 'null' : a_marker.toJSONString()) + ', ' + (a_point == null ? 'null' : a_point.toJSONString()) + ')');
								map.removeOverlay(this);
							}
						);
		GEvent.addListener(dgmr.locationMarker, "click", 
							function(a_marker, a_point) {
//								alert('marker.onclick(marker: ' + typeof a_marker + ', point: ' + typeof a_point + ')');
//									alert('marker.onclick(' + (a_marker == null ? 'null' : a_marker.toJSONString()) + ', ' + (a_point == null ? 'null' : a_point.toJSONString()) + ')');
								if (a_marker) {
									var infoWindow = map.getInfoWindow();
									alert('InfoWindow is hidden: ' + infoWindow.isHidden());
									if(infoWindow.isHidden()) {
										infoWindow.show();
									} else {
										infoWindow.hide();
									}
									map.removeOverlay(a_marker);
								}
//									map.removeOverlay(this);
							}
						);
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
function hideWarnings() {
	document.getElementById('misc_warning').style.display = 'none';
}
					
////////////////////////////////////////////////////////////////////////////////////////////////////
function mapShowLocation(place) {
	var currentZoom = map.getZoom();
	var newZoom = currentZoom;

	// Zoom to found location
	if(place.AddressDetails.Accuracy) {
		newZoom = place.AddressDetails.Accuracy + 7;
		if(!((newZoom > currentZoom) || (currentZoom - newZoom <= 3))) {
			newZoom = currentZoom;
		}
	}
	
	// Center on found location;
	var point = new GLatLng(place.Point.coordinates[1],
							place.Point.coordinates[0]);
	map.setCenter(point, newZoom);
	
	// if accuracy = 8 (street level), then lookup noise class of address
	if(place.AddressDetails.Accuracy && place.AddressDetails.Accuracy >= 8) {
		var marker = new GMarker(point, {title: place.address});
		map.addOverlay(marker);
		
		var html = '';
		html = '<h4>' + place.address + '</h4>';
		// TODO: als postcode en straat/huisnummer is gevonden, geef dan ook de 
		// contourklasse weer
		
		var postalCodeNumber = selectSingleObject(place.AddressDetails, 'PostalCodeNumber');
		var thoroughfareName = selectSingleObject(place.AddressDetails, 'ThoroughfareName');
		
		if(postalCodeNumber == null) {
			acnDownloaded('{message: "Ongeldige postcode!"}', 500);
		} else {
			var url = '../acn.js.asp?pc=' + encodeURIComponent(postalCodeNumber)
									+ '&tf=' + (thoroughfareName == null ? '' : encodeURIComponent(thoroughfareName))
									+ '&lat=' + point.lat().toString()
									+ '&long=' + point.lng().toString();
			// TODO: remove debug code
			var d = document.getElementById('debug');
			d.innerHTML += '<hr />' + url.replace(/^[^\?]*\?/, '') + '<br />';
			// --end of debug code
			
			GDownloadUrl(url, acnDownloaded);
		}
	} else if(place.AddressDetails.Accuracy != null) {
		var warning = document.getElementById('misc_warning');
		warning.innerHTML = 'Gezochte locatie is niet nauwkeurig genoeg... Probeer straat en huisnummer en eventueel plaatsnaam.';
		warning.style.display = '';
		setTimeout(hideWarnings, 8000);
	}
	
	// show info window
	function acnDownloaded(json, statuscode) {
		if(statuscode != 200) {
			html += '<p>Geluidbelasting niet bekend<!-- status: ' + statuscode + ' --></p>';
		} else {
			try {
				// TODO: remove debug code
				d.innerHTML += '<hr />' + json + '<br />'; 
				
				var ap = eval('dummy = ' + json);
				map.setCenter(new GLatLng(ap.lat, ap.lng));
				
				var address = selectSingleObject(place.AddressDetails, 'DependentLocalityName');
				if(address == null) {
					address = selectSingleObject(place.AddressDetails, 'LocalityName');
				}
				if(address == null) {
					html = html.replace(postalCodeNumber, ap.postcode);
				} else {
					html = '<h4>' + ap.straat + (ap.huisnummer == null ? '' : ' ' + ap.huisnummer) + '<br />'
								+ ap.postcode + ' &nbsp;' + address + '</h4>';
				}
				
				function renderNoiseClasses(a_name, a_classLden, a_classLnight) {
					return  '<tr>'
							+ '<td>' + a_name + '</td>'
							+ '<td class="noisecolor dB_' + a_classLden[0] + '">&nbsp;</td>'
							+ '<td class="noiseclass">' + a_classLden[0] + ' - ' + a_classLden[1] + '</td>'
							+ '<td class="noisecolor dB_' + a_classLnight[0] + '">&nbsp;</td>'
							+ '<td class="noiseclass">' + a_classLnight[0] + ' - ' + a_classLnight[1] + '</td>'
							+ '</tr>'
				}
				
				html += '<table class="adrespunt">'
					  + '<tr><th>Geluidbelasting [dB]</th><td colspan="2" class="noiseclass">24-uurs</td><td colspan="2" class="noiseclass">nacht</td></tr>'
					  + renderNoiseClasses('Wegverkeer', ap.vld, ap.vln)
					  + renderNoiseClasses('Railverkeer', ap.rld, ap.rln)
					  + renderNoiseClasses('Luchtvaart', ap.lld, ap.lln)
					  + renderNoiseClasses('Industrie', ap.ild, ap.iln)
					  + renderNoiseClasses('Gecumuleerd', ap.cud, ap.cun)
					  + '</table>';
			} catch(e) {
				html += '<p>Geluidbelasting niet bekend<!-- error: ' + (e.message + '; json = "' + json + '"').replace(/--/g, '- -') + ' --></p>';
			}
		}
		marker.openInfoWindowHtml(html);
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
function mapZoomEnd(oldLevel, newLevel) {
	var zoomWarning = document.getElementById('zoomwarning');
	if(newLevel > dgmr.maxZoomLevel) {
		zoomWarning.style.visibility = '';
	} else {
		zoomWarning.style.visibility = 'hidden';
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
function forceMapRedraw() {
	// HACK: quickly switch map type and back; only works when there's more than one tile layer
	var activeMapType = map.getCurrentMapType();
	var mapTypes = map.getMapTypes();
	if(activeMapType == mapTypes[0]) {
		map.setMapType(mapTypes[1]);
	} else {
		map.setMapType(mapTypes[0]);
	}
	map.setMapType(activeMapType);
}

function ee(e){if(e&&e.shiftKey&&e.ctrlKey){map.setCenter(new GLatLng(45.12348, -123.11364), 18, map.getMapTypes()[2])}}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Drills down into an object to find a member with the given name
function selectSingleObject(a_rootObject, a_memberName) {
	if(a_memberName == null) {
		return null;
	} else {
		if(a_memberName in a_rootObject) {
			return a_rootObject[a_memberName];
		} else {
			var result = null;
			for(var member in a_rootObject) {
				if(typeof a_rootObject[member] == 'object') {
					result = selectSingleObject(a_rootObject[member], a_memberName);
					if(result != null) {
						break;
					}
				}
			}
			return result;
		}
	}
}
