/**** application specific data for icons ****/
var cIcon = new GIcon();
	cIcon.image = "http://images2.amica.de/ami/images/googlemap/schere_allg_g.png";
	cIcon.printImage = "http://images2.amica.de/ami/images/googlemap/schere_allg_g.png";
	cIcon.mozPrintImage = "http://images2.amica.de/ami/images/googlemap/schere_allg_g.png";
	cIcon.iconSize = new GSize(46, 65);
	cIcon.iconAnchor = new GPoint(0, 65);

var standardIcon = new GIcon();
	standardIcon.image = "http://images2.amica.de/ami/images/googlemap/schere_standard_k.png";
	standardIcon.printImage = "http://images2.amica.de/ami/images/googlemap/schere_klein.png";
	standardIcon.mozPrintImage = "http://images2.amica.de/ami/images/googlemap/schere_klein.png";
	standardIcon.printShadow = "http://images2.amica.de/_.gif";
	standardIcon.iconSize = new GSize(33, 39);
	standardIcon.iconAnchor = new GPoint(0, 39);
	standardIcon.infoWindowAnchor = new GPoint(16, 20);
var economyIcon = new GIcon(standardIcon);
	economyIcon.image = "http://images2.amica.de/ami/images/googlemap/schere_economy_k.png";
	economyIcon.printImage = "http://images2.amica.de/ami/images/googlemap/schere_klein.png";
	economyIcon.mozPrintImage = "http://images2.amica.de/ami/images/googlemap/schere_klein.png";
var luxusIcon = new GIcon(standardIcon);
	luxusIcon.image = "http://images2.amica.de/ami/images/googlemap/schere_luxus_k.png";
	luxusIcon.printImage = "http://images2.amica.de/ami/images/googlemap/schere_klein.png";
	luxusIcon.mozPrintImage = "http://images2.amica.de/ami/images/googlemap/schere_klein.png";
var normalIcon = new GIcon(standardIcon);
	normalIcon.image = "http://images2.amica.de/ami/images/googlemap/schere_allg_g.png";
	normalIcon.printImage = "http://images2.amica.de/ami/images/googlemap/schere_klein.png";
	normalIcon.mozPrintImage = "http://images2.amica.de/ami/images/googlemap/schere_klein.png";

var standardDetailIcon = new GIcon();
	standardDetailIcon.image = "http://images2.amica.de/ami/images/googlemap/schere_kamm.png";
	standardDetailIcon.printImage = "http://images2.amica.de/ami/images/googlemap/schere_kamm.png";
	standardDetailIcon.mozPrintImage = "http://images2.amica.de/ami/images/googlemap/schere_kamm.png";
	standardDetailIcon.printShadow = "http://images2.amica.de/_.gif";
	standardDetailIcon.iconSize = new GSize(43, 60);
	standardDetailIcon.iconAnchor = new GPoint(0, 60);
	standardDetailIcon.infoWindowAnchor = new GPoint(22, 30);

var priceClassIcons = new Object();
	priceClassIcons.STANDARD = standardIcon;
	priceClassIcons.STANDARD.isActive = true;
	priceClassIcons.ECONOMY = economyIcon;
	priceClassIcons.ECONOMY.isActive = true;
	priceClassIcons.LUXUS = luxusIcon;
	priceClassIcons.LUXUS.isActive = true;
	priceClassIcons.none = normalIcon;
	priceClassIcons.none.isActive = false;

var priceClassDetailIcons = new Object();
	priceClassDetailIcons.STANDARD = standardDetailIcon;
	priceClassDetailIcons.ECONOMY = standardDetailIcon;
	priceClassDetailIcons.LUXUS = standardDetailIcon;

/**** ******************************************** ******/

// class for a search map
// this class creates a map that can be used to search for locations, display them and load a description for single results
function SearchMap(domId) {
	var me = this;
	var c;

	// dom id of map container
	this.containerId = domId;

	// default position o map center
	this.mapCenterLat = 51.16;
	this.mapCenterLng = 10.45;

	// default map zoom
	this.mapZoom = 5;

	// used map controls
	this.largeMapControl;
	this.mapTypeControl;

	// flag for setting map searchable; if true, moving map causes new search
	this.isSearchable = true;

	// default icons for search results to be displayed
	this.clusterIcon = G_DEFAULT_ICON;
	this.singleIcon = G_DEFAULT_ICON;
	this.detailIcon = G_DEFAULT_ICON;

	// properties for category-specific icons; if set, default icons are not used
	this.singleIcons;
	this.detailIcons;

	// properties for a special result to be shown in map
	this.detailPosLat;
	this.detailPosLng;
	this.detailPriceClass;

	// default circle properties
	this.searchLoc;
	this.radius = 30;
	this.radiusLineColor = "#FF0000";
	this.radiusLineWeight = 5;
	this.radiusLineOpacity = 0.5;
	this.nodes = 50;
	this.circle;
	this.circleBounds;

	// field to save created map object for external access
	this.mapObj;

	// field to save search result for external access
	this.resultObj;

	// field to set action path for getting result descriptions
	this.descriptionSrc;

	// field to set action for calling a search
	this.searchAction;

	var searchResult;
	var locatedMarkers = new Array();

	var tabs = new Array();

	// function to create an info window tab with result specific information
	// param index: the index of the tab to be created
	// param tabCount: max number of tabs for the given overlay
	// param overlay: the marker for which tabbed info window is created
	function createWindowTab(index, tabCount, overlay){
		// add id to action
		var uri = me.descriptionSrc.concat("&id=" + overlay.descriptionIds[index] + "&view=" + me.containerId);
		uri = encodeURI(uri);

		// create and send ajax request via prototype
		new Ajax.Request(uri, {
				method: 'get',
				// only show info window when successfull; there should be no action when receiving information fails
				onSuccess: function(transport) {
					tabs.push(new GInfoWindowTab(overlay.titles[index], transport.responseText));
					index++;
					if (index < tabCount) {
						// if there are tabs left, create next one
						createWindowTab(index, tabCount, overlay);
					} else {
						// if all tabs have been created, create info window and clear tab array when finished
						var maxWidth = 100 * tabs.length;
			 			overlay.bindInfoWindowTabsHtml(tabs, {maxWidth:maxWidth});
			 			overlay.openInfoWindowTabsHtml(tabs, {maxWidth:maxWidth});
			 			tabs = new Array();
					}
				}
		});
	}

	var sliderListener1;
	var sliderListener2;
	var sliderListener3;

	// function to show controls on map
	function addControls() {
		// create controls
		me.largeMapControl = new GLargeMapControl();
		me.mapTypeControl = new GMapTypeControl();

		// add controls to map
		me.mapObj.addControl(me.largeMapControl);
		me.mapObj.addControl(me.mapTypeControl);

		if (sliderListener1 == null || sliderListener2 == null || sliderListener3 == null) {
			var elem = document.getElementsByTagName("img");
	        for( var i = 0; i < elem.length; i++) {
	            var src = elem[i].getAttribute("src");
	            if (src != null) {
	                if (src == "http://maps.google.com/intl/de_ALL/mapfiles/slider.png") {
	                	sliderListener1 = GEvent.addDomListener(elem[i], "click", function() {
		        			stats();
		   				});
		   				sliderListener2 = GEvent.addDomListener(elem[i].parentNode, "mousedown", function() {
		        			stats();
		   				});
		   			} else if (src == "http://maps.google.com/intl/de_ALL/mapfiles/lmc-bottom.png" || src == "http://maps.google.com/intl/de_ALL/mapfiles/lmc.png") {
		   				sliderListener3 = GEvent.addDomListener(elem[i].parentNode, "click", function() {
		        			stats();
		   				});
			   		}
	            }
	        }
	    }
	}

	// function to remove controls from map
	function removeControls() {
		me.mapObj.removeControl(me.largeMapControl);
		me.mapObj.removeControl(me.mapTypeControl);
	}

	// function to load a map
	// param showControls: flag to decide whether controls should be created or not
	this.load = function(showControls) {

		// map should only be created, if there's not already a map obj available
		if (!(me.mapObj)) {

			var center = new GLatLng(me.mapCenterLat, me.mapCenterLng);
			me.mapObj = initializeMap(me.containerId, center, me.mapZoom);

			// click handler for map
			GEvent.addListener(me.mapObj, "click", function(overlay, point) {
				if (overlay && overlay.isCluster) {
					// if a cluster marker is clicked, map should recenter and zoom in
					me.mapObj.setCenter(overlay.getLatLng(), 8);
				} else if (overlay && overlay.isSingle) {
					if (document.getElementById(me.containerId).style.height == "110px") {
						// if map is shown in small version, open it
						toggleMAP("FGGoogleMap","FGGoogleButton", me);
					}
					// call click statistics for opening a single marker description
					stats();

					if (!overlay.hasInfo) {
						// if a single marker is clicked that has not already loaded its description, description is created
						if (overlay.descriptionIds.length > 1) {
							// if there is more than one description belonging to this marker, create a tabbed info window
							createWindowTab(0, overlay.descriptionIds.length, overlay);
						} else {
							// if theres only one description belonging to this marker create a normal info window
							var uri = me.descriptionSrc.concat("&id=" + overlay.descriptionIds[0] + "&view=" + me.containerId);
							uri = encodeURI(uri);
							new Ajax.Request(uri, {
									method: 'get',
									onSuccess: function(transport) {
										overlay.bindInfoWindowHtml(transport.responseText, {maxWidth:213});
										overlay.openInfoWindowHtml(transport.responseText, {maxWidth:213});
									}
							});
						}
						// set flag to indicate this marker has a description loaded
						overlay.hasInfo = true;
					}
				}
			});

			// handler for moving map event
			GEvent.addListener(me.mapObj, "dragend", function(){
				// call click statistics
				stats();
			});

			// handler for changing map type
			GEvent.addListener(me.mapObj, "maptypechanged", function(){
				// call click statistics
				stats();
			});

			if (me.isSearchable != null && me.isSearchable == true) {
				// when map is a searchable map, add handler for double clicks on map
				GEvent.addListener(me.mapObj, "dblclick", function(overlay, point){
					// if double click was somewhere on the map and a search action is available,
					// call a search with clocked point as center
					if (point && me.searchAction) {
						var params = {lat: point.lat(), lng: point.lng()};
						var uri = encodeURI(me.searchAction);

						// perform search
						me.search(uri, params);
					}

				});
			}

			// initialize marker manager to handle search results
			// custom marker manager from http://gmaps-utility-library-dev.googlecode.com
			// is used, because it has more funtions than standard one (removing markers is not
			// supported in GMarkerManager but in MarkerManager)
			searchResult = new MarkerManager(me.mapObj);
		}

		// load controls if needed
		if (showControls) {
			addControls();
		}
	}

	// funtion to display the map after loading it
	this.display = function() {
		var tmpCenter = me.mapObj.getCenter();
		document.getElementById(me.containerId).style.display="block";
		me.mapObj.checkResize();
		me.mapObj.setCenter(tmpCenter);
	}

	// funtion to hide the map by setting its container style to display:none
	this.hide = function() {
		document.getElementById(me.containerId).style.display="none";
	}

	// function to resize map container to a smaller size
	// this sets the maximum number of shown results to 10
	// and removes map controls
	this.minimize = function(height) {
		var tmpCenter = me.mapObj.getCenter();
		document.getElementById(me.containerId).style.height = height + "px";
		var bounds = new GLatLngBounds();

		if (locatedMarkers.length > 10) {
			for (var i = 10; i < locatedMarkers.length; i++) {
				searchResult.removeMarker(locatedMarkers[i]);
			}
		}

		searchResult.refresh();
		removeControls();

		me.mapObj.checkResize();
		me.mapObj.setCenter(tmpCenter);
		if (me.circleBounds) {
			me.mapObj.setZoom(me.mapObj.getBoundsZoomLevel(me.circleBounds)+2);
		}
	}

	// function to resize map container to a bigger size
	// this sets the maximum number of shown results to 20
	// and adds map controls
	this.maximize = function(height) {
		var tmpCenter = me.mapObj.getCenter();
		document.getElementById(me.containerId).style.height = height + "px";

		if (locatedMarkers.length > 10) {
			for (var i = 10; i < locatedMarkers.length; i++) {
				searchResult.addMarker(locatedMarkers[i], locatedMarkers[i].minZoom, locatedMarkers[i].maxZoom);
			}
		}

		addControls();

		me.mapObj.checkResize();
		me.mapObj.setCenter(tmpCenter);
		if (me.circleBounds) {
			me.mapObj.setZoom(me.mapObj.getBoundsZoomLevel(me.circleBounds)+2);
		}
	}

	// function to call a search
	// param searchAction: the uri of the action to call by ajax
	// param params: search criteria to be read by given search action
	this.search = function(searchAction, params) {
		new Ajax.Request(searchAction, {
			method: 'get',
			parameters: params,
			onComplete: function(transport) {
				// result is given as a JSON String
				var result = new String(transport.responseText);
				me.resultObj = result.evalJSON();
				// show found results in map
				showResultInMap(false);
			}
		});
	}

	// function to synchronize two maps (when a map popup is opened)
	// param o: the SearchMap instance to copy from
	// param doLoad: flag to indicate whether map should be loaded or already is
	// param showControls: flag to inidcate whether map controls should also be loaded when map is loaded
	this.synchronize = function(o, doLoad, showControls) {
		// copy map-sopecific values
		me.isSearchable = o.isSearchable;
		me.clusterIcon = o.clusterIcon;
		me.singleIcons = o.singleIcons;
		me.detailIcons = o.detailIcons;
		me.radius = o.radius;
		me.descriptionSrc = o.descriptionSrc;
		me.searchAction = o.searchAction;

		// load map
		if (doLoad && doLoad == true) {
			me.load(showControls);
		}

		// show map result if available
		if (o.resultObj) {
			me.resultObj = o.resultObj;
			showResultInMap(true);
		}

		// show special marker if available
		if (o.detailPosLat && o.detailPosLng) {
			me.detailPosLat = o.detailPosLat;
			me.detailPosLng = o.detailPosLng;
			me.detailPriceClass = o.detailPriceClass;
			showDetail();
		}

		// copy map values
		me.mapObj.setMapType(o.mapObj.getCurrentMapType());
		me.mapObj.setCenter(o.mapObj.getCenter(), o.mapObj.getZoom());
	}

	// function to toggle markers by class
	// if there are icons for the given class name, show them when hidden or hide them when visible
	// param className: the class to toggle
	this.toggleMapClass = function(className) {
		// test, if there are single icons with the given class name
		if (me.singleIcons && me.singleIcons[className]) {
			if (me.singleIcons[className].isActive) {
				hidePriceClass(className);
			} else {
				showPriceClass(className);
			}

			searchResult.refresh();
		}
	}

	// function to show search results in map from external access
	// param showCircle: flag to indicate whether a circle shoud be shown
	this.showResult = function(showCircle) {
		var singleMarkersCount = me.resultObj.singleMarkers.length;

		if (singleMarkersCount > 0) {
			showResultInMap(true);
			if (showCircle && showCircle == true) {
				var cCenter = me.mapObj.getCenter();
				if (me.searchLoc) {
					cCenter = me.searchLoc;
				}
				drawCircle(cCenter, me.radius, me.nodes);
			}
		}

		if (document.getElementById(me.containerId).style.height == "110px") {
			me.minimize(110);
		} else if (document.getElementById(me.containerId).style.height == "460px") {
			me.maximize(460);
		}
	}

	this.showDetail = function() {
		if (me.detailPosLat && me.detailPosLng) {
			showDetail();
		}
	}

	function showDetail() {
		var pos = new GLatLng(me.detailPosLat, me.detailPosLng);

		var icon = me.detailIcon;
		if (me.detailIcons && me.detailIcons[me.detailPriceClass]) {
			icon = me.detailIcons[me.detailPriceClass];
		}

		var marker = new GMarker(pos, {icon: icon, clickable: false});
		me.mapObj.addOverlay(marker);
		me.mapObj.setCenter(pos, 15);
	}

	function showPriceClass(className) {
		if (locatedMarkers && me.singleIcons[className]) {
			me.singleIcons[className].isActive = true;

			for (var i = 0; i < locatedMarkers.length; i++) {
				if (className == locatedMarkers[i].priceClass)
					searchResult.addMarker(locatedMarkers[i], locatedMarkers[i].minZoom, locatedMarkers[i].maxZoom);
			}
		}
	}

	function hidePriceClass(className) {
		if (locatedMarkers && me.singleIcons && me.singleIcons[className]) {
			me.singleIcons[className].isActive = false;

			for (var i = 0; i < locatedMarkers.length; i++) {
				if (className == locatedMarkers[i].priceClass && !locatedMarkers[i].isHidden())
					searchResult.removeMarker(locatedMarkers[i]);
			}
		}
	}

	function showResultInMap(recenter) {
		searchResult.clearMarkers();
		var center = me.mapObj.getCenter();
		var bounds = new GLatLngBounds();

		var singleMarkers = me.resultObj.singleMarkers;
		var clusterMarkers = me.resultObj.clusterMarkers;

		for (var i = 0; i < clusterMarkers.length; i++) {
			var lat = clusterMarkers[i].location.latitude;
			var lng = clusterMarkers[i].location.longitude;
			var pos = new GLatLng(lat, lng);
			bounds.extend(pos);
			var cMarker = new GMarker(pos, {title: clusterMarkers[i].description, icon: me.clusterIcon});
			cMarker.id = clusterMarkers[i].id;
			cMarker.isCluster = true;
			searchResult.addMarker(cMarker, 0, 7);
		}


		for (var i = 0; i < singleMarkers.length; i++) {
			var lat = singleMarkers[i].location.latitude;
			var lng = singleMarkers[i].location.longitude;
			var pos = new GLatLng(lat, lng);
			bounds.extend(pos);
			//read category here and set corresponding image
			var tmpmarkerIcon = me.singleIcon;

			if (me.singleIcons && me.singleIcons[singleMarkers[i].priceClass]) {
				tmpmarkerIcon = me.singleIcons[singleMarkers[i].priceClass];
			}

			var sMarker = new GMarker(pos, {icon: tmpmarkerIcon});

			sMarker.id = singleMarkers[i].id;
			sMarker.priceClass = singleMarkers[i].priceClass;
			sMarker.descriptionIds = singleMarkers[i].descriptionIds;
			sMarker.titles = singleMarkers[i].names;
			sMarker.isSingle = true;
			sMarker.hasInfo = false;

			if (sMarker.id == 0) {
				center = pos;
			}

			if (singleMarkers[i].clustered) {
				sMarker.minZoom = 8;
				sMarker.maxZoom = 17;
			} else {
				sMarker.minZoom = 0;
				sMarker.maxZoom = 17;
			}

			searchResult.addMarker(sMarker, sMarker.minZoom, sMarker.maxZoom);
			locatedMarkers.push(sMarker);

		}
		searchResult.refresh();
		if (recenter && recenter == true) {
			me.mapObj.setCenter(center);
			me.mapObj.setZoom(me.mapObj.getBoundsZoomLevel(bounds));
		}
	}

	function drawCircle(center, r, nodes) {
		//1. km je Grad berechnen:
		var fLat = center.distanceFrom(new GLatLng(center.lat() + 1.0, center.lng())); //Entfernung pro Grad in m
		fLat = fLat / 1000; //Entfernung pro Grad in km
		fLat = 1/fLat; //KM pro Grad

		var fLng = center.distanceFrom(new GLatLng(center.lat(), center.lng() + 1.0));
		fLng = fLng / 1000;
		fLng = 1/fLng;

		//2. Radius berechnen
		var radiusLat = r * fLat;
		var radiusLng = r * fLng;

		var stepMax = (2 * Math.PI);
		var step = stepMax / nodes;

		var c = new Array();
		var bounds = new GLatLngBounds();

		for (var i = 0; i < stepMax; i += step) {
			var lat = center.lat() + radiusLat * Math.sin(i);
			var lng = center.lng() + radiusLng * Math.cos(i);
			var pos = new GLatLng(lat, lng);
			c.push(pos);
			bounds.extend(pos);
		}

		c.push(c[0]);

		me.circle = new GPolyline(c, me.radiusLineColor, me.radiusLineWeight, me.radiusLineOpacity);
		me.mapObj.addOverlay(me.circle);

		me.mapObj.setZoom(me.mapObj.getBoundsZoomLevel(bounds));
		me.circleBounds = bounds;
		bounds = null;
	}
}

function MarkerMap(domId) {
	var me = this;

	this.containerId = domId;

	this.mapCenterLat = 51.16;
	this.mapCenterLng = 10.45;
	this.mapZoom = 5;
	this.largeMapControl;
	this.mapTypeControl;
	this.mapObj;

	this.marker;

	function addControls() {
		me.largeMapControl = new GLargeMapControl();
		me.mapTypeControl = new GMapTypeControl();

		me.mapObj.addControl(me.largeMapControl);
		me.mapObj.addControl(me.mapTypeControl);
	}

	this.load = function(showControls) {

		if (!(me.mapObj)) {
			var center = new GLatLng(me.mapCenterLat, me.mapCenterLng);
			me.mapObj = initializeMap(me.containerId, center, me.mapZoom);
		}

		if (showControls) {
			addControls();
		}
	}

	this.display = function() {
		var tmpCenter = me.mapObj.getCenter();
		me.mapObj.checkResize();
		if (me.marker) {
			me.mapObj.setCenter(me.marker.getLatLng(), 10);
		} else {
			me.mapObj.setCenter(tmpCenter);
		}
	}

	this.createPosMarker = function(pos, text){
		if (me.marker) {
			me.mapObj.removeOverlay(me.marker);
		}
		me.marker = new GMarker(pos, {draggable:true});
		me.mapObj.addOverlay(me.marker);
		me.marker.enableDragging();
		if (text) {

			var html = "<table width=\"100%\" cellpadding=\"0\" cellspacing=\"1\">";
			html += "<tr><td width=\"100%\">" + text +"</td></tr>";
			html += "</table>";
			html = "<div style=\"position: relative; float: left; width: 230px; height: 80px;\">" + html + "</div>";

			me.marker.openInfoWindowHtml(html);
			// Klick-Handler für Marker
			GEvent.addListener(me.marker, "mousedown", function() {
				me.marker.closeInfoWindow();
			});
		}
		GEvent.addListener(me.marker, "dragend", function() {
			me.mapObj.panTo(me.marker.getLatLng());
		});
	}

}

function GeocodingService(country, address, ignoreText) {
	if (country)
		this.country = country;
	else this.country = "";
	this.address = address;
	this.ignoreText = ignoreText;
	this.geocoder = new GClientGeocoder();
	this.geocoder.setBaseCountryCode("DE");
	this.validInput = address.length > 0
		&& this.address.indexOf(this.ignoreText) == -1
		&& this.country.indexOf(this.ignoreText) == -1;

	this.getLocation = function(noInputHandler, noResultHandler, resultHandler) {
		if (this.validInput) {
			country = this.country;
			address = this.address;
			this.geocoder.getLatLng(
				country + " " + address,
				function(point) {
					var resultString = new String();

					if(!point) {
						resultString = '{"success": false, "reason": "noResult"}';
					} else {
						resultString = '{"success": true, "latitude": ' + point.y +', "longitude": ' + point.x +'}';
					}

					var resultObject = resultString.evalJSON();

					if (resultObject.success) {
						resultHandler(address, country, resultObject);
					} else {
						noResultHandler(address, country);
					}
				}
			);
		} else {
			noInputHandler();
		}
	}

	this.getLocations = function(noInputHandler, noResultHandler, resultHandler) {
		if (this.validInput) {
			country = this.country;
			address = this.address;
			this.geocoder.getLocations(
				country + " " +  address,
				function(response) {
					var result = new String();

					if (!response || response.Status.code != 200) {
						result = '{"success": false, "reason": "noResult"}';
					}

					else if (response.Placemark.length > 0) {
						var places = new Array();
						for (var i = 0; i < response.Placemark.length; i++) {
							var place = '{"latitude": ' + response.Placemark[i].Point.coordinates[1]
								   	  + ', "longitude": ' + response.Placemark[i].Point.coordinates[0]
								   	  + ', "addressDetails": "' + response.Placemark[i].address + '"}';
							places.push(place);
						}

						result = '{"success": true, "results": [' + places.join(", ") + ']}';
					}

					var resultObject = result.evalJSON();

					if (resultObject.success) {
						resultHandler(address, country, resultObject);
					} else {
						noResultHandler(address, country);
					}
				}
			);
		} else {
			noInputHandler();
		}
	}
}

function initializeMap(containerId, center, zoom) {
	var map = new GMap2(document.getElementById(containerId));
	map.setCenter(center, zoom);
	return map;
}