
	/* ********************
	*	GeoMap v0.9
	*	Copyright Zeppelin Group - Technology
	*	GeoMap implementation using Google Maps API v2
	*	Author Martin Hafner on 2008-04-22
	********************* */
	
	function GeoMap()
	{
		
		/* ********************
		*	Private Members
		********************* */
		
		var elements = null;
		var categories = null;
		var ids = null;
		var map = null;
		var geomap = this;
		var singleElement = null;
		var singleElementOption = null;
		
		
		/* ********************
		*	Public Properties
		********************* */
		
		this.mapDiv = 'geomap_canvas';
		this.type = 'road';
		this.latitude = 46.524855
		this.longitude = 11.332397
		this.zoomLevel = 15;
		this.autoAdjustPosition = true;
		this.dynamicDataReload = true;
		this.lang = 'de';
		this.displayTypeControls = true;
		this.displayMapControls = true;
		
		this.loadingImageSrc = '/googlemaps/v2/loading.gif';
		this.iconImagePath = '/googlemaps/v2/';
		this.iconShaddowPath = '/googlemaps/v2/';
		this.balloonUrl = '/googlemaps/v2/balloon.asp';
		this.balloonHeight = 150;
		this.balloonWidth = 200;
		this.geoDataUrl = '/googlemaps/v2/geodata.asp';
		this.geoDataFormat = 'json';
		
		ids = new Array();
		
		
		/* ********************
		*	Public Methods
		********************* */
		
		/* Google Maps specific */
		this.initMap = function()
		{
			if (GBrowserIsCompatible()) {
				map = new GMap2(document.getElementById(this.mapDiv));
				
				// create loading layer
				var geomap_canvas = map.getContainer();
				var o = document.createElement('div');
				o.id = this.mapDiv + 'geomap_loading_overlay';
				o.style.position = 'absolute';
				o.style.display = 'none';
				o.style.zIndex = '190';
				o.style.top = geomap_canvas.offsetTop + 'px';
				o.style.left = geomap_canvas.offsetLeft + 'px';
				o.style.width = geomap_canvas.clientWidth + 'px';
				o.style.height = geomap_canvas.clientHeight + 'px';
				o.style.backgroundColor = 'rgb(240, 240, 240)';
				geomap_canvas.parentNode.appendChild(o);
				
				// create loading image
				var i = document.createElement('img');
				i.id = this.mapDiv + 'geomap_loading_image';
				i.style.position = 'absolute';
				i.style.display = 'none';
				i.style.zIndex = '191';
				i.src = this.loadingImageSrc;
				i.style.top = String(parseInt(geomap_canvas.offsetTop + (geomap_canvas.clientHeight / 2) - 16)) + 'px';
				i.style.left = String(parseInt(geomap_canvas.offsetLeft + (geomap_canvas.clientWidth / 2) - 16)) + 'px';
				geomap_canvas.parentNode.appendChild(i);
				
				// loading overlay and image
				showLoading();
				
				// Create a base icon for all the singleElements
		        var baseIcon = new GIcon();
		        baseIcon.image = geomap.iconImagePath + 'icon_singleElement.png';
		        baseIcon.shadow = geomap.iconShaddowPath + 'shadow_singleElement.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);
		        baseIcon.infoShadowAnchor = new GPoint(18, 25);
			
				singleElementOption = {icon:baseIcon};
				
			}else
			{
				if(MSG_BrowserNotSupportet)
				{
					alert(MSG_BrowserNotSupportet);
				}
				else
				{
					alert('Your browser is not supported by Google Maps');
				}
			}
		}
		
		/* Google Maps specific */
		this.loadMap = function()
		{
			if(map==null)
			{
				geomap.initMap();
			}
			
			elements = new Array();
			categories = new Array();
			//ids = new Array();
		
			// add standard map controls
			map.addMapType(G_PHYSICAL_MAP);
			if (this.displayTypeControls == true)
				map.addControl(new GMapTypeControl());
			if (this.displayMapControls == true)
				map.addControl(new GSmallMapControl());
			var oMapType = null;
			switch (this.type)
			{
				case 'road':
					oMapType = G_NORMAL_MAP;
					break;
				case 'satellite':
					oMapType = G_SATELLITE_MAP;
					break;
				case 'hybrid':
					oMapType = G_HYBRID_MAP;
					break;
				case 'physical':
					oMapType = G_PHYSICAL_MAP;
					break;
				default:
					oMapType = G_NORMAL_MAP;
					break;
			}
			map.setCenter(new GLatLng(this.latitude ,this.longitude, true), this.zoomLevel, oMapType);
			map.clearOverlays();
			
			if(this.autoAdjustPosition==true)
			{
				var autoPositionListener = GEvent.addListener(map, 'autoadjustposition', function(){
					geomap.autoPositionViewport();
					GEvent.removeListener(autoPositionListener);
					GEvent.addListener(map, 'zoomend', function() {
						if(geomap.dynamicDataReload == true)
						{
							refreshMap();
						}
				    });
				});
			}
			else
			{
				GEvent.addListener(map, 'zoomend', function() {
					if(geomap.dynamicDataReload == true)
					{
						refreshMap();
					}
				});
			}
			refreshMap();
		}
		
		this.reloadMap = function()
		{
			refreshMap();
		}
		
		/* Google Maps specific */
		this.unloadMap = function()
		{
			GUnload();
		}
		
		/* Google Maps specific */
		this.showElement = function(id)
		{
			if(elements[String(id)])
			{
				elements[String(id)].show();
				if(elements[String(id)].elementType=='line')
				{
					elements[String(id)].start.show();
					elements[String(id)].end.show();
				}
			}
			else
			{
				if(MSG_ElementToShowNotExists)
				{
					alert(MSG_ElementToShowNotExists);
				}
				else
				{
					alert('The element you tried to show does not exist on the map');
				}
			}
		}
		
		/* Google Maps specific */
		this.hideElement = function(id)
		{
			if(elements[String(id)])
			{
				elements[String(id)].hide();
				if(elements[String(id)].elementType=='line')
				{
					elements[String(id)].start.hide();
					elements[String(id)].end.hide();
				}
			}
			else
			{
				if(MSG_ElementToHideNotExists)
				{
					alert(MSG_ElementToHideNotExists);
				}
				else
				{
					alert('The element you tried to hide does not exist on the map');
				}
			}
		}
		
		/* Google Maps specific */
		this.openBalloon = function(id)
		{
			if(elements[String(id)])
			{
				if(elements[String(id)].isHidden()==false)
				{
					this.closeBalloon();
					GEvent.trigger(elements[String(id)], 'click');
				}
				else
				{
					if(MSG_MSG_ElementToShowBalloonNotExists)
					{
						alert(MSG_MSG_ElementToShowBalloonNotExists);
					}
					else
					{
						alert('The balloon of a hidden element cannot be opend');
					}
				}
			}
			else
			{
				if(MSG_MSG_ElementToShowBalloonNotExists)
				{
					alert(MSG_MSG_ElementToShowBalloonNotExists);
				}
				else
				{
					alert('The balloon of a hidden element cannot be opend');
				}
			}
		}
		
		/* Google Maps specific */
		this.closeBalloon = function(id)
		{
			map.closeInfoWindow();
		}
		
		/* Google Maps specific */
		this.showCategory = function(id)
		{
			for(var i in elements)
			{
				if(elements[i].cat.toLowerCase() == String(id).toLowerCase())
				{
					elements[i].show();
					if(elements[i].elementType=='line')
					{
						elements[i].start.show();
						elements[i].end.show();
					}
				}
			}
		}
		
		/* Google Maps specific */
		this.hideCategory = function(id)
		{
			for(var i in elements)
			{
				if(elements[i].cat.toLowerCase() == String(id).toLowerCase())
				{
					elements[i].hide();
					if(elements[i].elementType=='line')
					{
						elements[i].start.hide();
						elements[i].end.hide();
					}
				}
			}
		}
		
		this.addId = function(id)
		{
			if(!ids[String(id)] || ids[String(id)]==null)
				ids[String(id)] = id;
		}
		
		this.removeId = function(id)
		{
			if(ids[String(id)] && ids[String(id)]!=null)
				ids[String(id)] = null;
		}
		
		this.resetIds = function()
		{
			ids = null;
			ids = new Array();
		}
		
		/* Google Maps specific */
		this.autoPositionViewport = function()
		{
			var southWestLatLng = null; //new GLatLng(0, 0, true); //map.getBounds().getSouthWest();
			var northEastLatLng = null; //new GLatLng(0, 0, true); //map.getBounds().getNorthEast();
			
			for(var i in elements)
			{
				// avoid extended elements by prototype
				if(Number(i)>0)
				{
					if(southWestLatLng==null)
						southWestLatLng = new GLatLng(elements[i].getLatLng().lat(), elements[i].getLatLng().lng(), true);
						
					if(northEastLatLng==null)
						northEastLatLng = new GLatLng(elements[i].getLatLng().lat(), elements[i].getLatLng().lng(), true);
				
					// check if latitude is within the current viewport
					if(elements[i].getLatLng().lat() <= northEastLatLng.lat() && elements[i].getLatLng().lat() >= southWestLatLng.lat())
					{
						// just do nothing
					}
					if(elements[i].getLatLng().lat() > northEastLatLng.lat())
					{
						northEastLatLng = new GLatLng(elements[i].getLatLng().lat(), northEastLatLng.lng(), true);
						//alert("FOR POINT " + i + " CHANGE LATITUDE: lat: " + northEastLatLng.lat() + ", lng: " + northEastLatLng.lng());
					}
					if(elements[i].getLatLng().lat() < southWestLatLng.lat())
					{
						southWestLatLng = new GLatLng(elements[i].getLatLng().lat(), southWestLatLng.lng(), true);
						//alert("FOR POINT " + i + " CHANGE LATITUDE: lat: " + southWestLatLng.lat() + ", lng: " + southWestLatLng.lng());
					}
					
					// check if longitude is within the current viewport
					if(elements[i].getLatLng().lng() <= northEastLatLng.lng() && elements[i].getLatLng().lng() >= southWestLatLng.lng())
					{
						// just do nothing
					}
					if(elements[i].getLatLng().lng() > northEastLatLng.lng())
					{
						northEastLatLng = new GLatLng(northEastLatLng.lat(), elements[i].getLatLng().lng(), true);
						//alert("FOR POINT " + i + " CHANGE LONGITUDE: lat: " + northEastLatLng.lat() + ", lng: " + northEastLatLng.lng());
					}
					if(elements[i].getLatLng().lng() < southWestLatLng.lng())
					{
						southWestLatLng = new GLatLng(southWestLatLng.lat(), elements[i].getLatLng().lng(), true);
						//alert("FOR POINT " + i + " CHANGE LONGITUDE: lat: " + southWestLatLng.lat() + ", lng: " + southWestLatLng.lng());
					}
				}
			}
			var newLatLngBounds = new GLatLngBounds(southWestLatLng, northEastLatLng);
			map.panTo(newLatLngBounds.getCenter());
			var newZoomLevel = map.getBoundsZoomLevel(newLatLngBounds);
			if(newZoomLevel<map.getZoom())
				map.setZoom(newZoomLevel -1);
		}
		
		/* Google Maps specific */
		this.addSingleElement = function(lat, lng, alt)
		{
			if (singleElement != null)
			{
				geomap.removeSingleElement();
			}
			
			singleElement= new GMarker(new GLatLng(lat, lng, true), singleElementOption);
			singleElement.id = 'single';
			singleElement.cat = 'single';
			singleElement.elementType = 'single';
			map.addOverlay(singleElement);
		}
		
		/* Google Maps specific */
		this.removeSingleElement = function()
		{
			map.removeOverlay(singleElement);
			singleElement = null;
		}
		
		
		/* ********************
		*	Private Methods
		********************* */
		
		function showLoading()
		{
			var o = document.getElementById(geomap.mapDiv + 'geomap_loading_overlay');
			var i = document.getElementById(geomap.mapDiv + 'geomap_loading_image');
			if(o && i)
			{
				o.style.display = 'block';
				i.style.display = 'block';
			}
		}
		
		function hideLoading()
		{
			var o = document.getElementById(geomap.mapDiv + 'geomap_loading_overlay');
			var i = document.getElementById(geomap.mapDiv + 'geomap_loading_image');
			if(o && i)
			{
				i.style.display = 'none';
				o.style.display = 'none';
			}
		}
		
		/* Google Maps specific */
		function getElements()
		{
			var idList = '';
			var newElements = null;
			var currentZoomLevel = 19
			
			newElements = new Array();
			showLoading();
			
			for(var i in ids)
			{
				// avoid extended elements by prototype
				if(ids[i] && Number(i)>0)
				{
					if(idList!='')
						idList = idList + ',';
					idList = idList + ids[i]
				}
			}
			
			if(geomap.dynamicDataReload == true)
			{
				currentZoomLevel = map.getZoom();
			}
			
			switch(geomap.geoDataFormat)
			{
			
				case 'json':
					// implementation with JSON data format
					GDownloadUrl(geomap.geoDataUrl + '?format=' + geomap.geoDataFormat + '&lang=' + geomap.lang + '&ids=' + idList + '&zoom=' + currentZoomLevel, function(data, responseCode) {
						
						var geoData = null;
						if (responseCode==200 && data!='' && data!='none')
						{
							try
							{
								geoData = eval('(' + data + ')');
							}
							catch(e)
							{
								geoData = null;
								if(MSG_GeoDataJSONSyntaxError)
								{
									alert(MSG_GeoDataJSONSyntaxError);
								}
								else
								{
									alert('An error occurred during data transportation (JSON)');
								}
							}
							
							if(geoData != null)
							{
								// line
								var startLat = null;
								var startLng = null;
								var endLat = null;
								var endLng = null;
								if (geoData.lines != null && geoData.lines.length > 0)
								{
									for(var i=0; i<geoData.lines.length; i++)
									{
										var currentLatLngArray = new Array();
										for(var j=0; j<geoData.lines[i].latlng.length; j++)
										{
											if(j==0)
											{
												startLat = geoData.lines[i].latlng[j].lat;
												startLng = geoData.lines[i].latlng[j].lng;
											}
											if(j==geoData.lines[i].latlng.length-1)
											{
												endLat = geoData.lines[i].latlng[j].lat;
												endLng = geoData.lines[i].latlng[j].lng;
											}
											currentLatLngArray.unshift(new GLatLng(geoData.lines[i].latlng[j].lat, geoData.lines[i].latlng[j].lng, true));
										}
										
										var show = (elements!=null && elements[String(geoData.lines[i].id)] && elements[String(geoData.lines[i].id)].isHidden()==true) ? false : true;
										newElements[String(geoData.lines[i].id)] = addElementLine(geoData.lines[i].id, geoData.lines[i].cat, startLat, startLng, endLat, endLng, currentLatLngArray, show, geoData.lines[i].color, geoData.lines[i].width);
									}
								}
								
								// point
								if (geoData.points != null && geoData.points.length > 0)
								{
									for(var i=0; i<geoData.points.length; i++)
									{
										var show = (elements!=null && elements[String(geoData.points[i].id)] && elements[String(geoData.points[i].id)].isHidden()==true) ? false : true;
										newElements[String(geoData.points[i].id)] = addElementPoint(geoData.points[i].id, geoData.points[i].catalog, geoData.points[i].cat, geoData.points[i].lat, geoData.points[i].lng, show);
									}
								}
							}
							
							elements = newElements;
							GEvent.trigger(map, 'autoadjustposition');
							hideLoading();
						}
						else
						{
							if(data!='none')
							{
								if(MSG_GeoDataUrlError)
								{
									alert(MSG_GeoDataUrlError);
								}
								else
								{
									alert('An error occurred during data transportation (URL)');
								}
							}
						}
						hideLoading();
					});
					break;
					
				case 'xml':
					// implementation with XML data format
					GDownloadUrl(geomap.geoDataUrl + '?format=' + geomap.geoDataFormat + '&lang=' + geomap.lang + '&ids=' + idList + '&zoom=' + currentZoomLevel, function(data, responseCode) {
						if (responseCode==200 && data!='' && data!='none')
						{
							var xml = GXml.parse(data);
							var markers = xml.documentElement.getElementsByTagName("point");
							var lines = xml.documentElement.getElementsByTagName("line");
							
							// line
							var startLat = null;
							var startLng = null;
							var endLat = null;
							var endLng = null;
							for(var i=0; i<lines.length; i++)
							{
								var currentLatLngArray = new Array();
								var linesLatLng = lines[i].getElementsByTagName('latlng');
								for(var j=0; j<linesLatLng.length; j++)
								{
									if(j==0)
									{
										startLat = linesLatLng[j].getAttribute('lat');
										startLng = linesLatLng[j].getAttribute('lng');
									}
									if(j==linesLatLng.length-1)
									{
										endLat = linesLatLng[j].getAttribute('lat');
										endLng = linesLatLng[j].getAttribute('lng');
									}
									currentLatLngArray.unshift(new GLatLng(linesLatLng[j].getAttribute('lat'), linesLatLng[j].getAttribute('lng'), true));
								}
								
								var show = (elements!=null && elements[String(lines[i].getAttribute('id'))] && elements[String(lines[i].getAttribute('id'))].isHidden()==true) ? false : true;
								newElements[String(lines[i].getAttribute('id'))] = addElementLine(lines[i].getAttribute('id'), lines[i].getAttribute('cat'), startLat, startLng, endLat, endLng, currentLatLngArray, show, lines[i].getAttribute('color'), lines[i].getAttribute('width'));
							}
							
							// point
							for (var i=0; i<markers.length; i++)
							{
								var show = (elements!=null && elements[String(markers[i].id)] && elements[String(markers[i].id)].isHidden()==true) ? false : true;
								newElements[String(markers[i].getAttribute('id'))] = addElementPoint(String(markers[i].getAttribute('id')), String(markers[i].getAttribute('catalog')), String(markers[i].getAttribute('cat')), parseFloat(markers[i].getAttribute('lat')), parseFloat(markers[i].getAttribute('lng')), show);
							}
							
							elements = newElements;
							GEvent.trigger(map, 'autoadjustposition');
							hideLoading();
						}
						else
						{
							if(data!='none')
							{
								if(MSG_GeoDataUrlError)
								{
									alert(MSG_GeoDataUrlError);
								}
								else
								{
									alert('The requested URL for geodata was not found!');
								}
							}
						}
						hideLoading();
					});
					break;
			}
		}
		
		/* Google Maps specific */
		function addElementPoint(id, catalog, cat, lat, lng, show)
		{
			// Create a base icon for all of our markers that specifies the
			var baseIcon = new GIcon();
			baseIcon.shadow = geomap.iconShaddowPath + 'shadow_' + catalog + '_' + cat + '.png';
			baseIcon.shadowSize = new GSize(43, 25);
			baseIcon.image = geomap.iconImagePath + 'icon_' + catalog + '_' + cat + '.gif';
			baseIcon.iconSize = new GSize(25, 25);
			baseIcon.iconAnchor = new GPoint(18, 25);
			baseIcon.infoWindowAnchor = new GPoint(9, 2);
			baseIcon.infoShadowAnchor = new GPoint(34, 25);
			
			var marker = null;
			var markerOption = {icon:baseIcon};
			
			marker = new GMarker(new GLatLng(lat, lng, true), markerOption);
			marker.id = id;
			marker.cat = cat;
			marker.elementType = 'point';
			marker.bindInfoWindowHtml('<iframe src="' + geomap.balloonUrl + '?id=' + id + '&cat=' + cat + '" name="balloon-' + id + '" width="' + geomap.balloonWidth + '" height="' + geomap.balloonHeight + '" align="left" scrolling="no" marginheight="0" marginwidth="0" frameborder="0"></iframe>');
			if(show==false)
			{
				var addOverlayListener = GEvent.addListener(map, 'addoverlay', function(overlay){
					marker.hide();
					GEvent.removeListener(addOverlayListener);
				});
			}
			map.addOverlay(marker);
			return marker;
		}
		
		/* Google Maps specific */
		function addElementLine(id, cat, startLat, startLng, endLat, endLng, latlngArray, show, lineColor, lineSize)
		{
			var polyline = null;
			
			polyline = new GPolyline(latlngArray, lineColor, lineSize);
			polyline.id = id;
			polyline.cat = cat;
			polyline.elementType = 'line';
			polyline.getLatLng = function(){
				return new GLatLng(startLat, startLng, true);
			};
			
			GEvent.addListener(polyline, 'click', function(latlng) {
				if(!latlng)
					latlng = polyline.getLatLng();
				map.openInfoWindowHtml(latlng, '<iframe src="' + geomap.balloonUrl + '?id=' + id + '&cat=' + cat + '" name="balloon-' + id + '" width="' + geomap.balloonWidth + '" height="' + geomap.balloonHeight + '" align="left" scrolling="no" marginheight="0" marginwidth="0" frameborder="0"></iframe>');
			});
			
			if(show==false)
			{
				var addOverlayListener = GEvent.addListener(map, 'addoverlay', function(overlay){
					marker.hide();
					GEvent.removeListener(addOverlayListener);
				});
			}
			map.addOverlay(polyline);
			
			// add also an icon for the start point
			// Create a base icon for all of our markers that specifies the
			var baseIcon = new GIcon();
			baseIcon.shadow = 'http://www.google.com/mapfiles/shadow50.png';
			baseIcon.shadowSize = new GSize(43, 25);
			baseIcon.image = 'http://www.google.com/intl/en_us/mapfiles/dd-start.png'
			baseIcon.iconSize = new GSize(20, 34);
			baseIcon.iconAnchor = new GPoint(10, 34);
			baseIcon.infoWindowAnchor = new GPoint(9, 2);
			baseIcon.infoShadowAnchor = new GPoint(34, 25);
			
			// start point
			var startmarker = null;
			var startmarkerOption = {icon:baseIcon};
			startmarker = new GMarker(new GLatLng(startLat, startLng, true), startmarkerOption);
			polyline.start = startmarker;
			GEvent.addListener(startmarker, 'click', function() {
				startmarker.openInfoWindowHtml('<iframe src="' + geomap.balloonUrl + '?id=' + id + '&cat=' + cat + '" name="balloon-' + id + '" width="' + geomap.balloonWidth + '" height="' + geomap.balloonHeight + '" align="left" scrolling="no" marginheight="0" marginwidth="0" frameborder="0"></iframe>');
			});
			map.addOverlay(startmarker);
			
			//end point
			var endmarker = null;
			baseIcon.image = 'http://www.google.com/intl/en_us/mapfiles/dd-end.png'
			var endmarkerOption = {icon:baseIcon};			
			endmarker = new GMarker(new GLatLng(endLat, endLng, true), endmarkerOption);
			polyline.end = endmarker;
			GEvent.addListener(endmarker, 'click', function() {
				endmarker.openInfoWindowHtml('<iframe src="' + geomap.balloonUrl + '?id=' + id + '&cat=' + cat + '" name="balloon-' + id + '" width="' + geomap.balloonWidth + '" height="' + geomap.balloonHeight + '" align="left" scrolling="no" marginheight="0" marginwidth="0" frameborder="0"></iframe>');
			});
			map.addOverlay(endmarker);
			
			return polyline;
		}
		
		function resetElements()
		{
			elements = null;
			elements = new Array();
			categories = null;
			categories = new Array();
		}
		
		function refreshMap()
		{
			map.clearOverlays();
			getElements();	
		}
		
	}
	
	/* ********************
	*	Localization
	********************* */
	var GeoMapLocalization = {
		Version: '0.9',
		require: function(libraryName) {
			document.write('<script type="text/javascript" src="'+libraryName+'" ></script>');
		},
		load: function() {
			var scripttags = document.getElementsByTagName("script");
			for(var i=0; i<scripttags.length; i++)
			{
				var geomapscripttag = scripttags[i].src.match(/geomap-v0\.9\.js(\?.*)?$/);
				if(geomapscripttag!=null && geomapscripttag!='')
				{
					var include = 'geomap-lang-';
					var path = scripttags[i].src.replace(/geomap-v0\.9\.js(\?.*)?$/,'');
					var includes = scripttags[i].src.match(/\?.*lang=([a-z,]*)/);
					if(includes!=null)
					{
						switch(includes[0])
						{
							case '?lang=de':
								include = include + 'de';
								this.lang = 'de';
								break;
							case '?lang=it':
								include = include + 'it';
								this.lang = 'it';
								break;
							case '?lang=en':
								include = include + 'en';
								this.lang = 'en';
								break;
						}
						GeoMapLocalization.require(path + include + '.js')
					}
				}
			}
		}
	}
	GeoMapLocalization.load();