/**
	* iKISS - GoogleMaps - API Klasse
*/

ikiss_gmap = function() {

	var tob = this;                    // Objektreferenz

	// Defaultwerte -> können im Modultemplate überschrieben werden
	tob.id              = 'igm';         // Klassenbezeichner
	tob.modul_id        = 9;             // Modul-ID
	tob.setZoom         = true;          // Optimale Zoomstufe anhand der Adressmarker automatisch ermitteln
	tob.zoomlevel       = 13;            // Default-Zoomstufe
	tob.s_lat           = 53.86589;      // Default-Breitengrad
	tob.s_lng           = 10.686607;     // Default-Längengrad
	tob.router          = 'google';      // Default-Routenplaner ist Google; wenn leer, dann wird der interne Routenplaner verwendet
	tob.setRouteLatLng  = false;         // Routenplanung ohne / mit Angabe der geografischen Koordinaten für die korrekte Routenplanung auch bei unbekannten Adressen
	tob.def_icon        = 'default';     // Icon für Adressmarker
	tob.search_icon     = 'fahne';       // Icon für Textsuche
	tob.defaultSearch   = '';            // bei Eingabe einer Adresse ohne Kommata wird dieser Suchstring automatisch angehängt
	tob.defaultWWSearch = true;          // bei weltweiter Suche tob.defaultSearch nicht automatisch anhängen
	tob.autoSearch      = 0;             // wird 1, wenn der defaultSearch-String automatisch angehängt wird
	tob.numbIcons       = ['marker|99']; // numerierte Icons (Basisset: 'iconr' = rot 1-25, 'icong' = grün 1-25, 'iconb' = blau 1-25, 'marker' = rot 1-99) ('r','g','b','marker')
	tob.iconURL         = '';            // URL für indiv. Icons, wenn leer, dann HTTP_HOST
	tob.clientAbsX      = 0;             // absolute x-Position des Map-Divs bei Window-Resize (statt clientOffsetX!)
	tob.clientOffsetX   = 40;            // oder negativer X-Offset für setHeight() bei Window-Resize
	tob.clientOffsetY   = 30;            // negativer Y-Offset für setHeight() bei Window-Resize
	tob.clientMinWidth  = 150;           // minimal-Breite der Map
	tob.clientMinHeight = 265;           // minimal-Höhe der Map
	tob.mapOffsetY      = 0;             // untere Größenreduzierung des Map-Div
	tob.adrOffsetY      = -4;            // untere Größenreduzierung des Adr-Div
	tob.messageOK       = 'OK.';         // Default-Message
	tob.debug           = false;         // Debug-Modus (für Meldungen)

	// Templates -> können im Modultemplate überschrieben werden
	tob.infoText        = '<b>#{Name}</b><br />#{Name2}<br />#{Strasse}&nbsp;#{Hausnr}<br /><br />#{Land}-#{PLZ}&nbsp;#{Ort}<hr size="1" />'; // Infotext-Template
	tob.detailLink      = '';           // hier kann der ganze Detaillink inkl. <A>-Tag definiert werden (alternativ nur .detailURL)
	tob.detailURL       = '/adr.phtml?call=detail&FID=#{FID}'; // statt .detailLink kann hier vereinfacht nur die URL definiert werden, der Link ist dann Standard: [Detail]
	tob.separator       = '<div class="igm_separator">#{title}</div>';

	tob.gc_object       = {};    // Geocoder-Ergebnis
	tob.addresses       = [];    // Alle Adressen
	tob.adr_stack       = [];    // Stack für Adressen ohne Geokoordinaten
	tob.icons           = [];    // Alle Icons
	tob.markers         = [];    // Speicher für individuelle Marker
	tob.markCount       = -1;    // Index für Marker
	tob.geocoding       = false; // Flag für laufenden Geocoding-Prozess

	var param           = [];    // URL-GET-Parameter

	/**
		* Initialisierung der Map und Aktivierung der Controls
	*/
	tob.initialize  = function() {
		if (GBrowserIsCompatible())	{
			tob.map =	new	GMap2($("map"));
			param = tob.getParam();
			if (param['zoom']) {
				tob.zoomlevel_act = parseInt(param['zoom'],10);
				tob.setZoom = false;
			}
			else
				tob.zoomlevel_act = tob.zoomlevel;

			if (param['lat'] && param['lng']) {
				tob.s_lat = param['lat'];
				tob.s_lng = param['lng'];
			}

			tob.map.setCenter(new GLatLng(tob.s_lat, tob.s_lng),tob.zoomlevel_act);
			tob.map.disableContinuousZoom();
			tob.map.enableScrollWheelZoom();

			tob.map.enableDoubleClickZoom();
			tob.map.enableDragging();
			tob.map.enableInfoWindow();

			tob.map.addControl(new GLargeMapControl());
			tob.map.addControl(new GMapTypeControl());
			tob.map.addControl(new GScaleControl());
			tob.map.addControl(new GOverviewMapControl());

			tob.geocache = new GGeocodeCache();
			tob.geocoder = new GClientGeocoder(tob.geocache);
			tob.bounds = new GLatLngBounds();

			tob.separatorTpl = new Template(tob.separator);

			tob.polygons = new tob.poly();

			tob.setEvents();
			tob.setIcons();
		}
		else
			alert('Sorry, your browser is not compatible with GoogleMaps!');
	}


	/**
		* Initialisierung der Map und Aktivierung der Controls
	*/
	tob.setEvents  = function() {
			// bei Klick auf die Karte zum angeklickten Punkt wandern, außer bei Klick auf Marker (Overlay != false)
			GEvent.bind(tob.map, "click", this,
				function(overlay, point) {
					if (!overlay)
						this.map.panTo(point);
					else
						this.$(overlay);
					tob.polygons.addPointToLine(point);
				}
			);
			
	}


	/**
		* Geokoordinate für eine bestimmte Adresse ermitteln
	*/
	tob.getGeo = function(address, mode) {
		tob.getgeo_mode = mode;
		tob.gpoint = false;
		if (isNaN(address)) { // Adresse als Suchstring
			tob.address = address;
			tob.addresses_idx = -1;
			var cladr = tob.address;
			if (tob.defaultSearch && !tob.autoSearch && !cladr.match(/,/))
				cladr = cladr + ', ' + tob.defaultSearch;
			++ tob.autoSearch;
			var gc_object = tob.geocache.get(cladr);
			if (gc_object) {
				tob.handleGC(gc_object,true);
				return true;
			}
			$('igm_msg').update('Bitte warten, Adressen werden ermittelt!');
		}
		else { // iKISS-Adresse
			tob.addresses_idx = address; // aktuellen Adressindex speichern
			tob.address = tob.addresses[address][1];
			var cladr = tob.address;
		}
		// Geokoordinaten für die Adresse ermitteln und übergeben an .handleGC()
		cladr = tob.convertAdr(cladr);
		tob.geocoder.getLocations(cladr,tob.handleGC);
	}


	/**
		* Google Geocoder Callback-Funktion für .getGeo() oder GeoCache
		* Verarbeitung der Google Geocoder-Anfrage
	*/
	tob.handleGC = function(gc_object, gc_cache) {
		tob.gc_object = gc_object;
		if (tob.gc_object.Placemark) { // Volltextsuche hat Ergebnisse...
			if (!gc_cache)
				tob.geocache.put(tob.gc_object.name,tob.gc_object); // Rein in den GeoCache...
			tob.handlePlacemarks();
		}
		else { // Adresse wurde nicht gefunden
			if (tob.addresses_idx != -1) { // iKISS-Adress-Geocoding
				var adr = tob.addresses[tob.addresses_idx];
				if (++adr[5] > 3) { // erst nach 3 Fehlversuchen abbrechen
					if (!tob.failure_flag) {
						tob.failure_flag = true;
						$('igm_msg').update();
					}
					tob.adr_stack = tob.adr_stack.without(tob.addresses_idx); // vom Stack entfernen
					tob.$('<b>Geocoding-Failure:</b> (' + adr[6] + ')' + adr[0] + ', '+ adr[1] + '<br />'); // und Fehler anzeigen
				}
			}
			else { // Volltextsuche
				if (tob.defaultSearch && tob.autoSearch == 1) {// Suche ohne tob.defaultSearch wiederholen, wenn erste Suche ohne Ergebnis 
					tob.getGeo(tob.address);
				}
				else // Mißerfolgsmeldung ausgeben, wenn beide Suchen kein Ergebnis liefern
 					$('igm_msg').update("Die Adresse '" + tob.address + "' wurde nicht gefunden!");
			}
		}
		tob.geocoding = false;
	}


	/**
		* vom Google Geocoder ermittelte Placemarks verarbeiten
	*/
	tob.handlePlacemarks = function() {

		var plc = tob.gc_object.Placemark.length;
		var pli = 0; // Placemark-Index (für Geocoder-Cache-Hit)

		// Prüfung auf Geocoder-Cache-Hit
		for (var i = 0; i < plc; ++i) {
			if (tob.address == tob.gc_object.Placemark[i].address) { // Cache-Hit
				pli = i;
				var gc_cache_hit = true;
				break;
			}
		}

		// Geokoordinate generieren
		var coord = tob.gc_object.Placemark[pli].Point.coordinates;
		var gpoint = new GLatLng(coord[1],coord[0]);

		if (!tob.getgeo_mode) // Karte auf gewählten Punkt zentrieren
			tob.map.setCenter(gpoint,tob.zoomlevel_act);

		if (tob.addresses_idx != -1) { // bei iKISS-Adressen die ermittelte Geokoordinate in Adressarray und iKISS speichern
			var adr = tob.addresses[tob.addresses_idx];
			adr[3] = gpoint;
			tob.setMarker(tob.addresses_idx); // Marker setzen
			tob.adr_stack = tob.adr_stack.without(tob.addresses_idx); // vom Stack entfernen

			// AJAX-Request zur Speicherung der Koordinaten in iKISS
			new Ajax.Request('/custom/googlemaps_gc_request.phtml?call=geocoder&ModID='+tob.modul_id+'&FID='+adr[6]+'&lat='+coord[1]+'&lng='+coord[0], {
				method: 'get',
				onSuccess: function(transport) {
					tob.$(transport.responseText + '<br />');
				}
			});
		}
		else { // Volltext-Suchergebnisse verarbeiten
			var marker_idx = -1;
			if (!gc_cache_hit) { //Neue Objekte cachen...
				if (plc > 1) { // mehrere Placemarks gefunden -> Placemark-Linkliste anzeigen
					$('igm_msg').update();
					for (var i = 0; i < plc; ++i) {
						tob.geocache.put(tob.gc_object.Placemark[i].address,tob.gc_object);
						$('igm_msg').innerHTML += '<a href="javascript:' + tob.id + '.adrSearch(\'' + tob.gc_object.Placemark[i].address + '\')">' + tob.gc_object.Placemark[i].address.replace(/[, ]*Germany/g,'') + '</a><br />';
					}
				}
				else {
					tob.geocache.put(tob.gc_object.Placemark[0].address,tob.gc_object);
					$('igm_msg').update('<a href="javascript:' + tob.id + '.adrSearch(\'' + tob.gc_object.Placemark[0].address + '\')">' + tob.gc_object.Placemark[0].address.replace(/[, ]*Germany/g,'') + '</a><br />');
				}
			}

			// Prüfung, ob der zu setzende Marker schon existiert
			var len = tob.markers.length;
			for (var i = 0; i < len; ++i) {
				if (tob.markers[i].address == tob.gc_object.Placemark[pli].address) {
					marker_idx = i;
					break;
				}
			}

			// Marker setzen
			tob.setCustomMarker(pli, gpoint, marker_idx);
		}

	}

	/**
		* Marker bei erfolgreicher Adressermittlung per Volltextsuche setzen
	*/
	tob.setCustomMarker = function(pli, gpoint, marker_idx) {
		if (marker_idx == -1)
			var marker_nr = ++tob.markCount;
		else
			var marker_nr = marker_idx;

		var dbg = '#' + marker_nr; // Debug

		// Infotext generieren
		var infotext = tob.gc_object.Placemark[pli].address.replace(/[, ]*Germany/g,'').split(/,\s*/);
		try { // Landkreis und Bundesland hinzufügen, wenn vorhanden
			infotext.push(
				tob.gc_object.Placemark[pli].AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.SubAdministrativeAreaName,
				tob.gc_object.Placemark[pli].AddressDetails.Country.AdministrativeArea.AdministrativeAreaName
			);
		} catch(e){}
		infotext.push('&nbsp;',tob.createLinks(marker_nr,0));
		infotext = infotext.uniq(); // Doppelbezeichnungen entfernen (Ort = Gemeinde)

		if (marker_idx == -1) { // neuen Marker erstellen
			tob.markers[marker_nr] = new GMarker(gpoint, tob.icons[tob.search_icon]);
			tob.markers[marker_nr].address = tob.gc_object.Placemark[pli].address;
			tob.markers[marker_nr].title = infotext[0];
			dbg += 'c';
		}
		if (tob.markers[marker_nr].visibile != true) {
			tob.map.addOverlay(tob.markers[marker_nr]);
			tob.markers[marker_nr].visibile = true;
			dbg += 'v';
		}

		// Info-Fenster anzeigen
		tob.createInfoWindow(tob.markers[marker_nr], infotext.join('<br />'));

		if (marker_idx == -1) {
			GEvent.addListener(tob.markers[marker_nr], "click",
				function() {
					tob.createInfoWindow(this, infotext.join('<br />'));
				}
			);
		}

		tob.$(dbg);
	}


	/**
		* Tabs für Marker-Infofenster generieren
	*/
	tob.createInfoWindow = function(marker,infotext) {
	
		var latlng = '';

		if (!isNaN(marker.idx)) {
			var adr = tob.addresses[marker.idx];
			if (adr[1])
				var targetAdr = adr[1];
			else if (adr[7])
				var targetAdr = adr[7].Strasse + ' ' + adr[7].Hausnr + ', ' + adr[7].PLZ + ' ' + adr[7].Ort;
			tob.$(adr);
			if (tob.setRouteLatLng) {
				latlng = '@' + adr[3].y + ',' + adr[3].x;
			}
		}
		else {
			var targetAdr = marker.address;
		}
		
		var tabs = new Array(
			new GInfoWindowTab('Info',    '<div id="igm_iw_info" style="width:300px">' + infotext + '</div>'),
			new GInfoWindowTab('Route',   '<div id="igm_iw_route" style="width:300px"><form id="igm_iw_route_form" onsubmit="' + tob.id + '.getRoute($(\'igm_iw_route_form\').igm_startAdr.value, $(\'igm_iw_route_form\').igm_targetAdr.value); return false;"><b>Start:</b><br /><input type="text" name="igm_startAdr" style="width:150px" /><br /><br /><b>Ziel:</b><br /><input type="hidden" name="igm_targetAdr" value="' + targetAdr + latlng + '" />' + targetAdr + '<br /><br /><input type="submit" value="Route berechnen!" />&nbsp;<input type="button" value="L&ouml;schen" onclick="' + tob.id + '.router.clear(); $(\'igm_iw_route_form_butl\').style.display = \'none\';" id="igm_iw_route_form_butl" style="display:none" /></form></div>')
		);

//		if (marker.idx)
//			tabs.push(new GInfoWindowTab('Details', '<div id="igm_iw_detail" style="width:300px"></div>'));
		marker.openInfoWindowTabsHtml(tabs);
	}


	/**
		* Funktionslinks für Marker-Infofenster generieren
	*/
	tob.createLinks = function(idx,mode) {
		// Funktionslinks einfügen
		var buts = '';

		// nur für Adress-Marker
		if (mode) {
			var dlink = false;
			if (tob.detailLink)
				dlink = new Template(tob.detailLink);
			else if (tob.detailURL)
				dlink = new Template('[<a href="' + tob.detailURL + '">Details</a>]&nbsp;');
			buts += ((dlink) ? dlink.evaluate(tob.addresses[idx][7]) : '') + '[<a href="javascript:' + tob.id + '.zoomMarker(' + idx + ',' + mode + ');">Zoom</a>]&nbsp;';
		}

		// nur für manuelle Marker
		if (!mode) {
			buts += '[<a href="javascript:' + tob.id + '.zoomMarker(' + idx + ',' + mode + ');">Zoom</a>]&nbsp;';
			buts += '[<a href="javascript:' + tob.id + '.killMarker(' + idx + ');">L&ouml;schen</a>]&nbsp;';
		}

		buts += '[<a href="javascript:' + tob.id + '.getCoord(' + idx + ',' + mode + ');">Koordinaten</a>]&nbsp;';
		return buts;
	}


	/**
		* Alle Adressen auf Geokoordinaten prüfen, Marker hinzufügen und Adressliste darstellen
	*/
	tob.setAddresses	= function() {
		$('igm_adr').update(); // Adressfenster löschen
		if ($('igm_msg')) // Ladeanzeige
			$('igm_msg').update();
		var currAdr = undefined;
			
		// Alle Adressen anzeigen und auf Geokoordinate prüfen
		tob.addresses.each(
			function(adr,idx) {
				if (adr[1]) {
					$('igm_adr').innerHTML += '<a href="javascript:' + tob.id + '.adrShow(' + idx + ')">' + adr[0] + '</a><br />';
					if (!adr[3]) // keine Geokoordinate, dann Adressindex zum Geocoder-Stack hinzufügen
						tob.adr_stack.push(idx);
					else
						tob.setMarker(idx);
					if (param['OID'] == adr[6])
					  currAdr = idx;
				}
				else { // Separator
					$('igm_adr').innerHTML += tob.separatorTpl.evaluate({title: adr[0]});
				}
			}
		);
		$('igm_adr').innerHTML += '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'; // Darstellungs-Bugfix für IE6

		if (!isNaN(currAdr))
			tob.adrShow(currAdr);
		else if (param['OID']) { // Adresse per AJAX laden
			tob.getObj(0,param['OID']);
		}

		// Geokoordinatenermittlung
		tob.currentIndex = 0; // Aktuelle vom Geocoder zu verarbeitende Adresse (Array-Index)
		tob.setAdr();
	}


	/**
		* Geokoordinate ermitteln für die Adresse .addresses[.currentIndex]
	*/
	tob.setAdr = function(singleMode) {
		if (!tob.geocoding) {
			var adr_stack_len = tob.adr_stack.length;
			if (adr_stack_len) {
				if (++tob.currentIndex >= adr_stack_len)
					tob.currentIndex = 0;
				// Geokoordinate ermitteln, wenn kein anderer Geocode-Prozess läuft
				if (!tob.addresses[tob.adr_stack[tob.currentIndex]][3]) {
					tob.geocoding = true;
					tob.getGeo(tob.adr_stack[tob.currentIndex],1);
				}
			}
			else if (tob.addresses.length) { // Alle Adressen verarbeitet
				$('igm_msg').update(tob.messageOK + '<br /><br />');
				if (singleMode)
				  tob.adrShow(tob.addresses.length-1); //
				else if (tob.setZoom)
					tob.setOptimalZoom();
				return;
			}
			else
				return;
		}
		// Funktion solange erneut aufrufen, bis .adr_stack keine Elemente mehr enthält
		window.setTimeout(tob.id + '.setAdr('+singleMode+')', 100);
	}


	/**
		* Adressobjekt.Marker generieren
	*/
	tob.setMarker = function(idx) {
		var adr = tob.addresses[idx];
		if (adr[3] && !adr[4]) { // Geokoordinate, aber noch kein Marker vorhanden?
			adr[4] = new GMarker(adr[3], tob.icons[(adr[2]) ? adr[2] : tob.def_icon]); // Koordinate, Icon
			adr[4].idx = idx; // Adressindex zum Marker-Objekt hinzufügen (.adrShow)
			tob.map.addOverlay(adr[4]);
			GEvent.addListener(adr[4], "click", tob.adrShow);
		}
	}


	/**
		* Adresse laden; Vorbereitung für Adress-Infofenster
	*/
	tob.adrShow = function(idx) {
		if (isNaN(idx) && this.idx > -1)
			idx = this.idx; // Aufruf über Marker.click (.setMarker)
		var adr = tob.addresses[idx];
		if (adr[4]) {
			tob.getObj(idx); // Adressobjekt holen
			tob.adrCheck(idx); // und weiterverarbeiten
			tob.zoomMarker(idx,1,1);
			tob.setZoom = false;
		}
	}

	/**
		* Adress-Infofenster anzeigen
	*/
	tob.adrCheck = function(idx, calls) {
		if (!calls)
			calls = 1;
		var adr = tob.addresses[idx];
		if (adr[7]) { // Marker und Adressobjekt vorhanden, dann Info anzeigen
			tob.$(adr[7]); // Debug-Anzeige
			var infotext = new Template(tob.infoText);
			tob.createInfoWindow(adr[4], infotext.evaluate(adr[7]) + tob.createLinks(idx,1));
			return true;
		}
		if (++calls < 11)
			window.setTimeout(tob.id + '.adrCheck(' + idx + ',' + calls + ')', 250); // sonst wiederholen, bis Adressobjekt geladen ist (max. 10)
		else
			alert('Zeitüberschreitung: die Adresse konnte nicht geladen werden!');
	}


	/**
		* Volltextsuche über Textfeldeingabe
	*/
	tob.adrSearch = function(address) {
		tob.zoomlevel_act = 15;
		tob.getGeo(address);
	}

	/**
		* Karten-Zoomlevel auf optimale Zoomstufe setzen, um alle Adressmarker zu sehen
	*/
	tob.setOptimalZoom = function(mode) {
		var cnt = tob.addresses.length;
		for (var i = 0; i < cnt; i++) {
			if (tob.addresses[i][4])
				tob.bounds.extend(tob.addresses[i][4].getPoint());
		}
		if (mode) {
			var cnt = tob.markers.length;
			for (var i = 0; i < cnt; i++) {
				tob.bounds.extend(tob.markers[i].getPoint());
			}
		}
		if (!tob.bounds.isEmpty()) {
			zoomlevel = tob.map.getBoundsZoomLevel(tob.bounds);
			tob.map.setZoom((zoomlevel > 17) ? 17 : zoomlevel);
			tob.map.setCenter(tob.bounds.getCenter());
		}
		else
			tob.map.setCenter(new GLatLng(tob.s_lat, tob.s_lng),tob.zoomlevel_act);
	}

	/**
		* Höhe der Karte automatisch anpassen
	*/
	tob.setHeight = function() {
		if (Prototype.Browser.Opera)
			var client_h = document.body.clientHeight;
		else if (Prototype.Browser.Gecko)
			var client_h = window.innerHeight;
		else
			var client_h = (document.documentElement.clientHeight || document.body.clientHeight);
		var ofs = Position.cumulativeOffset($('map'));
		map_y = client_h - ofs[1] - tob.clientOffsetY;
		if (map_y < tob.clientMinHeight) map_y = tob.clientMinHeight;
		$('igm_client').style.height = map_y + 'px';
		$('map').style.height = (map_y + tob.mapOffsetY) + 'px';
		$('igm_adr').style.height = (map_y + tob.adrOffsetY) + 'px';
		if (tob.map) tob.map.checkResize();
	}

	/**
		* Breite und Höhe der Karte automatisch anpassen
	*/
	tob.setSize = function() {
		if (Prototype.Browser.Opera)
			var client_w = document.body.clientWidth;
		else if (Prototype.Browser.Gecko)
			var client_w = window.innerWidth;
		else
			var client_w = (document.documentElement.clientWidth || document.body.clientWidth);

		var adr_w = $('igm_adr').getWidth();
		if (tob.clientAbsX) {
			var map_x = client_w - (tob.clientAbsX + adr_w);
			$('igm_client').style.left = tob.clientOffsetX + 'px';
		}
		else {
			var ofs = Position.cumulativeOffset($('igm_searchform'));
			var ofs_map = Position.cumulativeOffset($('igm_client'));
			if (ofs_map[0] - ofs[0] < 20)
				var map_x = client_w - (ofs_map[0] + tob.clientOffsetX + adr_w);
			else
				var map_x = client_w - (ofs[0] + $('igm_searchform').getWidth() + tob.clientOffsetX + adr_w);
		}
		if (map_x < tob.clientMinWidth)
			map_x = tob.clientMinWidth;
		$('igm_client').style.width = (map_x + adr_w) + 'px';
		$('map').style.width = map_x + 'px';
		$('igm_adr').style.left = $('map').style.width;
		tob.setHeight();
	}
			
	/**
		* manuell gesetzten Marker löschen
	*/
	tob.killMarker = function(idx) {
		tob.map.removeOverlay(tob.markers[idx]);
		tob.markers[idx].visibile = false;
		tob.map.closeInfoWindow();
	}


	/**
		* alle Marker löschen
		* mode = 1 : manuelle Marker; 2 : Adress-Marker; 3 : Alle
	*/
	tob.killAllMarker = function(mode) {
		tob.map.closeInfoWindow();
		if (!mode || mode&1) {
			var cnt = tob.markers.length;
			for (var i = 0; i < cnt; i++) {
				tob.map.removeOverlay(tob.markers[i]);
				tob.markers[i].visibile = false;
			}
		}

		if (mode&2) {
			var cnt = tob.addresses.length;
			for (var i = 0; i < cnt; i++) {
				if (tob.addresses[i][4]) {
					tob.map.removeOverlay(tob.addresses[i][4]);
					tob.addresses[i][4].visibile = false;
				}
			}
			$('igm_adr').update('&nbsp;');
		}
	}


	/**
		* Marker-Zoom
	*/
	tob.zoomMarker = function(idx,mode,noZoomIn) {
		if (tob.map.getZoom() < 15)
			tob.map.setZoom(15);
		else if (!noZoomIn)
			tob.map.zoomIn();
		if (mode)
			tob.map.setCenter(tob.addresses[idx][3]);
		else
			tob.map.setCenter(tob.markers[idx].getPoint());
		tob.map.panDirection(0, 0.6); // ein kleines Stück nach unten bitte...
	}


	/**
		* Geokoordinaten eines Markers anzeigen
	*/
	tob.getCoord = function(idx,mode) {
		if (idx) {
			if (mode)
				var point = tob.addresses[idx][3];
			else
				var point = tob.markers[idx].getPoint();
		}
		else
			var point = tob.map.getCenter();

		var p_lat = Math.round(point.lat() * 1000000) / 1000000;
		var p_lng = Math.round(point.lng() * 1000000) / 1000000;
		$('igm_msg').update('Koordinaten: <br />' + 'Breitengrad: ' + p_lat + '<br />L&auml;ngengrad: ' + p_lng);
	}


	/**
		* Routenberechnung
	*/
	tob.getRoute = function(startAdr, targetAdr) {
		if (!startAdr) {
			alert('Bitte geben Sie eine Startadresse ein!');
			return false;
		}

		if (!targetAdr) {
			alert('Bitte geben Sie eine Zieladresse ein!');
			return false;
		}

		var query = 'from:' + tob.convertAdr(startAdr) + ' to:' + tob.convertAdr(targetAdr);
		tob.$(query);
		if (tob.router == 'google') {
			window.open("http://maps.google.de/maps?t=m&hl=de&q=" + query, "_blank");
		}
		else {
			$('igm_iw_route_form_butl').style.display = 'inline';
			var panel = $('igm_adr'); // DIV für Routenausgabe
			panel.update();
			if (!tob.router)
				tob.router = new GDirections(tob.map, panel);
			tob.router.clear();
			GEvent.addListener(tob.router, "error", tob.routeHandleErrors);
			tob.router.load(query, { "locale": "de_DE" });
		}
	}


	/**
		* Fehlerbehandlung
	*/
	tob.routeHandleErrors = function() {
		//var rstatus = tob.router.getStatus().code;
		if (tob.router.getStatus().code == G_GEO_UNKNOWN_ADDRESS)
			alert("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.\nError code: " + tob.router.getStatus().code);
		else if (tob.router.getStatus().code == G_GEO_SERVER_ERROR)
			alert("A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.\n Error code: " + tob.router.getStatus().code);
		else if (tob.router.getStatus().code == G_GEO_MISSING_QUERY)
			alert("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.\n Error code: " + tob.router.getStatus().code);
		else if (tob.router.getStatus().code == G_GEO_BAD_KEY)
			alert("The given key is either invalid or does not match the domain for which it was given. \n Error code: " + tob.router.getStatus().code);
		else if (tob.router.getStatus().code == G_GEO_BAD_REQUEST)
			alert("A directions request could not be successfully parsed.\n Error code: " + tob.router.getStatus().code);
		else alert("An unknown error occurred.");
	}


	/**
		* Infofenster mit Tab generieren
	*/
	tob.createTabInfo = function() {
	}


	/**
		* Adressstring Geocoder-gerecht konvertieren
	*/
	tob.convertAdr = function(adrString) {
		adrString = adrString.replace(/&(\w)uml;/g, '$1e'); // Umlaut-Entities konvertieren
		adrString = adrString.replace(/&szlig;/g, 'ss');    // &szlig; konvertieren
		adrString = adrString.replace(/str\./g, 'strasse');
		return adrString;
	}


	/**
		* Adressobjekt-Detaildaten per Ajax aus iKISS holen und im Adressarray speichern
	*/
	tob.getObj = function(idx, OID) {
		if (!idx && OID) { // Adresse per OID-Parameter laden
			idx = tob.addresses.length;
			tob.addresses[idx] = ['','','',false,false,0,OID,undefined];
		}
		var adr = tob.addresses[idx];
		if (adr[7] == undefined) {
			tob.addresses_idx = idx;
			new Ajax.Request('/custom/googlemaps_gc_request.phtml?call=getobj&ModID='+tob.modul_id+'&FID='+adr[6], {
				method: 'get',
				onSuccess: function(transport) {
					var obj = tob.addresses[tob.addresses_idx];
					obj[7] = transport.responseText.evalJSON();
					if (OID) { // Einzeladresse per Adress-Objekt-ID aufrufen
						tob.addresses[tob.addresses_idx][0] = obj[7].Titel + ' ' + obj[7].Vorname + ' ' + obj[7].Name;
						tob.addresses[tob.addresses_idx][1] = obj[7].Strasse + ' ' + obj[7].Hausnr + ', ' + obj[7].PLZ + ' ' + obj[7].Ort;
						if (obj[7].MapX != 0) { // Adresse anzeigen
							tob.addresses[tob.addresses_idx][3] = new GLatLng(obj[7].MapY/1000000,obj[7].MapX/1000000,0);
							tob.setMarker(idx);
							tob.adrShow(idx);
						}
						else { // Adresse geokodieren und anschliessend anzeigen
							tob.adr_stack.push(idx);
							tob.setAdr(true);
						}
					}
				},
				onFailure: function(transport) {
					tob.addresses[tob.addresses_idx][7] = false;
					tob.$('getObj failed:' + transport.status);
				}
			});
		}
	}


	/**
		* Straßensuche
	*/
	tob.strSubmit = function () {
		try {
			tob.autoSearch = 0;
			if ($('str_sel') && $('str_sel').selectedIndex > 0) {
				tob.adrSearch($('str_sel').options[$('str_sel').selectedIndex].value || $('str_sel').options[$('str_sel').selectedIndex].text);
			}
			else if ($('str_tx').value && $('str_tx').value != $('str_tx').defaultValue) {
				if (!tob.defaultWWSearch)
					tob.autoSearch = 1;
				tob.adrSearch($('str_tx').value);
			}
			else
				tob.map.setCenter(new GLatLng(tob.s_lat, tob.s_lng),tob.zoomlevel);
		} catch (e) {;}

		return false;
	}


	/**
		* GET-Parameter in Array übertragen
	*/
	tob.getParam = function(querystring) {
		if (!querystring)
			querystring = window.location.search
		var params = [];
		querystring = unescape(querystring);
		querystring = querystring.slice(1);
		var paare = querystring.split('&');
		var plen = paare.length;
		for (var i=0; i < plen; i++) {
			var key = paare[i].substring(0, paare[i].indexOf('='));
			var val = paare[i].substring(paare[i].indexOf('=')+1, paare[i].length);
			params[key] = val;
		}
		return params;
	}


	/**
		* Debug-Ausgabe für Arrays / Objekte generieren
	*/
	tob.print_r = function(theObj, withFunctions) {
		var result = '';
		var constr = false;
		if (theObj.constructor == Array || theObj.constructor == Object || typeof(theObj.constructor) == 'function') {
			result += '<ul>';
			for (var p in theObj){
				try {constr = theObj[p].constructor;}	catch(e) {constr = false;}
				if (constr == Array || constr == Object) {
					result += '<li>[' + p + '] => ' + typeof(theObj) + '</li>';
					result += '<ul>' + tob.print_r(theObj[p]) + '</ul>';
				}
				else {
					if (withFunctions || (!withFunctions && typeof(theObj[p]) != 'function'))
						result += '<li>[' + p + '] => ' + theObj[p] + '</li>';
				}
			}
			result += '</ul>';
		}
		return result;
	}

	/**
		* Debug-Meldung ausgeben
	*/
	tob.$ = function(msg) {
		if (tob.debug) {
			var constr = false;
			try {constr = msg.constructor;}	catch(e) {}
			if (constr == Array || constr == Object || typeof(msg) == 'function' || typeof(constr) == 'function')
				GLog.writeHtml(tob.print_r(msg));
			else
				GLog.writeHtml(msg);
		}
	}


	/**
		* Icons initialisieren
	*/
	tob.setIcons = function() {

		// ggf. Icon-URL auf eigenen Host setzen
		if (!tob.iconURL) {
			var urlparts = document.URL.split("/");
			if (urlparts[0] == 'http:' && urlparts[2])
				tob.iconURL = "http://" + urlparts[2] + "/media/googlemaps/";
		}

		// Basiseigenschaften für Icons
		tob.IconProps = new Array();

		tob.IconProps['base'] = new GIcon();
		tob.IconProps['base'].iconSize = new GSize(32,32);
		tob.IconProps['base'].shadowSize = new GSize(32,32);
		tob.IconProps['base'].iconAnchor = new GPoint(16,32);
		tob.IconProps['base'].infoWindowAnchor = new GPoint(16,32);

		tob.IconProps['default'] = new GIcon();
		tob.IconProps['default'].iconSize = new GSize(20,34);
		tob.IconProps['default'].shadowSize = new GSize(37,34);
		tob.IconProps['default'].iconAnchor = new GPoint(10,34);
		tob.IconProps['default'].infoWindowAnchor = new GPoint(10,34);

		tob.IconProps['pin'] = new GIcon();
		tob.IconProps['pin'].iconSize = new GSize(32,32);
		tob.IconProps['pin'].shadowSize = new GSize(32,32);
		tob.IconProps['pin'].iconAnchor = new GPoint(22,28);
		tob.IconProps['pin'].infoWindowAnchor = new GPoint(22,28);

		tob.icons['default']    = new GIcon(tob.IconProps['default'], "http://maps.google.com/mapfiles/marker.png", null, "http://maps.google.com/mapfiles/shadow50.png");
		tob.icons['fahne']      = new GIcon(tob.IconProps['base'], "http://maps.google.com/mapfiles/kml/pal2/icon5.png", null, "http://maps.google.com/mapfiles/kml/pal2/icon5s.png");
		tob.icons['pin']        = new GIcon(tob.IconProps['pin'], "http://maps.google.com/mapfiles/kml/pal5/icon14.png", null, "http://maps.google.com/mapfiles/kml/pal5/icon14s.png");
		tob.icons['arzt']       = new GIcon(tob.IconProps['base'], "http://maps.google.com/mapfiles/kml/pal3/icon38.png", null, "http://maps.google.com/mapfiles/kml/pal3/icon38s.png");
		tob.icons['unterkunft'] = new GIcon(tob.IconProps['base'], "http://maps.google.com/mapfiles/kml/pal2/icon20.png", null, "http://maps.google.com/mapfiles/kml/pal2/icon20s.png");
		tob.icons['restaurant'] = new GIcon(tob.IconProps['base'], "http://maps.google.com/mapfiles/kml/pal2/icon32.png", null, "http://maps.google.com/mapfiles/kml/pal2/icon32s.png");
		tob.icons['behoerde']   = new GIcon(tob.IconProps['base'], "http://maps.google.com/mapfiles/kml/pal5/icon57.png", null, "http://maps.google.com/mapfiles/kml/pal5/icon57s.png");
		tob.icons['feuerwehr']  = new GIcon(tob.IconProps['base'], "http://maps.google.com/mapfiles/kml/pal2/icon0.png", null, "http://maps.google.com/mapfiles/kml/pal2/icon0s.png");
		tob.icons['sport']      = new GIcon(tob.IconProps['base'], "http://maps.google.com/mapfiles/kml/pal2/icon49.png", null, "http://maps.google.com/mapfiles/kml/pal2/icon49s.png");
		tob.icons['haus']       = new GIcon(tob.IconProps['base'], "http://maps.google.com/mapfiles/kml/pal3/icon31.png", null, "http://maps.google.com/mapfiles/kml/pal3/icon31s.png");

		if (tob.iconURL) {
			tob.icons['apotheke']   = new GIcon(tob.IconProps['base'], tob.iconURL + "apotheke.PNG", null);
			tob.icons['polizei']    = new GIcon(tob.IconProps['base'], tob.iconURL + "polizei.PNG", null);
			tob.icons['parkplatz']  = new GIcon(tob.IconProps['base'], tob.iconURL + "parkplatz.PNG", null);
			tob.icons['hallenbad']  = new GIcon(tob.IconProps['base'], tob.iconURL + "hallenbad.PNG", null);
			tob.icons['freibad']    = new GIcon(tob.IconProps['base'], tob.iconURL + "freibad.PNG", null);

			// Nummerierte Icons
			var numi = tob.numbIcons.length;
			var j = 0;
			var mp = new Array();
			for (j = 0; j < numi; ++j) {
				mp = tob.numbIcons[j].split("|");
				if (!mp[1])
					mp[1] = 25;
				for (var i = 1; i < mp[1]; ++i) {
					tob.icons[mp[0] + i] = new GIcon(tob.IconProps['default'], tob.iconURL + mp[0] + i + ".png", null, "http://maps.google.com/mapfiles/shadow50.png");
				}
			}
		}

	}

	/**
		* Polygon-Klasse für die Erstellung und Verwaltung von Polygon-Objekten
	*/
	tob.poly = function() {

		tpo = this;
		tpo.polygons      = [];    // Daten der Polygone

		var lineFlag      = false; // Flag für Linenmodus
		var klickpoints   = [];    // Stack für angeklickte Punkte (Polygon)
		var polyIndex     = 0;    // Polygonzähler

		/**
			* Linie zeichnen
		*/
		tpo.drawLine = function() {
			lineFlag = !lineFlag;
			if (lineFlag) {
				if (tpo.polygons[polyIndex])
					++polyIndex;
				klickpoints = [];
				$('igmALine').update('Strecke beenden');
				$('igmAPoly').style.visibility = "visible";
			}
			else {
				$('igmALine').update('Strecke');
				$('igmAPoly').style.visibility = "hidden";
			}
		}

		tpo.setMarker = function(point,polyNr) {
			tpo.polygons[polyNr].marker = new GMarker(point, tob.icons['pin']);
			tob.map.addOverlay(tpo.polygons[polyNr].marker);
			GEvent.addListener(tpo.polygons[polyNr].marker, "click",
				function() {
					if (tpo.polygons[polyNr].poly) {
						var wp = 'Wegpunkte: ' + tpo.polygons[polyNr].poly.getVertexCount() + '<br />';
						if (tpo.polygons[polyNr].area) {
							var infotext = '<u>Fl&auml;che ' + (polyNr+1) + '</u><br />' + wp;
							infotext += 'Umfang: ' + parseInt(tpo.polygons[polyNr].length) + ' m<br />';
							infotext += 'Fl&auml;che: ' + parseInt(tpo.polygons[polyNr].area) + ' qm<br />';
						}
						else {
							var infotext = '<u>Strecke ' + (polyNr+1) + '</u><br />' + wp;
							infotext += 'L&auml;nge: ' + parseInt(tpo.polygons[polyNr].length) + ' m<br />';
						}
					}
					infotext += '<br /><br />[<a href="javascript:' + tob.id + '.polygons.remove(' + polyNr + ')">L&ouml;schen</a>]';

					this.openInfoWindowHtml(infotext);
				}
			);
		}


		tpo.remove = function(polyNr) {
			if (lineFlag)
				tpo.drawLine();
			tob.map.closeInfoWindow();
			tob.map.removeOverlay(tpo.polygons[polyNr].poly);
			tpo.polygons[polyNr].marker.remove();
			tpo.polygons[polyNr] = {};
			$('igm_msg').update();
		}


		/**
			* Linienpunkt hinzufügen
		*/
		tpo.addPointToLine = function(point) {
			if (!lineFlag || !point)
				return false;
			klickpoints.push(point);
			if (klickpoints.length > 1) {
				var len = 0;
				tob.map.removeOverlay(tpo.polygons[polyIndex].poly);
				tpo.polygons[polyIndex].poly = new GPolyline(klickpoints,"#000000",2,0.5,'#ff0000',0.5);
				tob.map.addOverlay(tpo.polygons[polyIndex].poly);
				var plen = tpo.polygons[polyIndex].poly.getVertexCount();
				tpo.polygons[polyIndex].length += point.distanceFrom(tpo.polygons[polyIndex].poly.getVertex(plen-2));
				$('igm_msg').update('<b>Streckenlänge (' + plen + '):</b> ' + parseInt(tpo.polygons[polyIndex].length) + ' Meter');
			}
			else {
				tpo.polygons[polyIndex] = {};
				tpo.polygons[polyIndex].length = 0;
				tpo.polygons[polyIndex].area = 0;
				tpo.setMarker(point,polyIndex);
			}
		}


		/**
			* Polygon aus Linie zeichnen
		*/
		tpo.drawPoly = function(obj) {
			if (lineFlag)
				tpo.drawLine();
			klickpoints.push(klickpoints[0]);
			tob.map.removeOverlay(tpo.polygons[polyIndex].poly);
			tpo.polygons[polyIndex].poly = new GPolygon(klickpoints,"#000000",2,0.5,'#ff0000',0.5);
			tob.map.addOverlay(tpo.polygons[polyIndex].poly);

			var plen = tpo.polygons[polyIndex].poly.getVertexCount();
			tpo.polygons[polyIndex].length += tpo.polygons[polyIndex].poly.getVertex(plen-2).distanceFrom(tpo.polygons[polyIndex].poly.getVertex(plen-1));
			tpo.polygons[polyIndex].area = tpo.calcArea(polyIndex);
			$('igm_msg').update('<b>Streckenlänge (' + klickpoints.length + '):</b> ' + parseInt(tpo.polygons[polyIndex].length) + ' Meter<br /><b>Fläche:</b> ' + parseInt(tpo.polygons[polyIndex].area) + ' qm');
		}

		/**
			* Polygonfläche berechnen
		*/
		tpo.calcArea = function(pIndex) {
			var i,j,point,xi,yi,xj,yj;
			var a = 0;
			var radiansPerDegree = 0.0174532;
			var earthRadiusMeters = 6367460;
			var metersPerDegree = 2.0 * Math.PI * earthRadiusMeters / 360;
			var plen = tpo.polygons[pIndex].poly.getVertexCount();
			for (i = 0; i < plen; ++i) {
				j = (i+1) % plen;
				point = tpo.polygons[pIndex].poly.getVertex(i);
				xi = point.lng()* metersPerDegree * Math.cos((point.lat() * radiansPerDegree));
				yi = point.lat()* metersPerDegree;
				point = tpo.polygons[pIndex].poly.getVertex(j);
				xj = point.lng()* metersPerDegree * Math.cos((point.lat() * radiansPerDegree));
				yj = point.lat()* metersPerDegree;
				a += xi * yj - xj * yi;
			}
			return Math.abs(a / 2);
		}
	}

}

