var ModelkiGoogleMapsSearch = {
	config: {
		init: {
			mapZoom: 6,
			mapCenter: new google.maps.LatLng(51.9194380, 19.1451360),
			strokeColor: "#000000",
			style: null,
			minValue: 19,
			maxValue: 1,
			sliderValue: 10
		},
		calculateRadius: {
			radius: [5916575, 2958287, 1479143, 739571, 369785, 184892, 92446, 46223, 23111, 11555, 5777, 2888, 1444, 722, 361, 180, 90, 45, 22, 11],
		},
		search: {
			url: null,
			dataSelectors: {},
			dataHtmlSelector: null
		},
		placeCircleMarker: {
			icon: null
		},
		placeMarker: {
			icon: null
		}
	},
	map: null,
	marker: null,
	circle: null,
	markers: [],
	markerClusterer: null,
	
	init: function() {
		var mapZoom = parseInt($("input#map_zoom").val());
		
		if (isNaN(mapZoom)) {
			mapZoom = this.config.init.mapZoom;
		}
		
		$("input#map_zoom").val(mapZoom);
		
		var mapCenter = this.config.init.mapCenter;
		
		var mapCenterLat = parseFloat($("input#map_center_lat").val());
		var mapCenterLng = parseFloat($("input#map_center_lng").val());
		
		if (!isNaN(mapCenterLat) && !isNaN(mapCenterLng)) {
			mapCenter = new google.maps.LatLng(mapCenterLat, mapCenterLng);
		}
		
		mapCenterLat = mapCenter.lat();
		mapCenterLng = mapCenter.lng();
		
		$("input#map_center_lat").val(mapCenterLat);
		$("input#map_center_lng").val(mapCenterLng);
		
		this.map = new google.maps.Map(document.getElementById("map"), {
			zoom: mapZoom,
			center: mapCenter,
			mapTypeId: google.maps.MapTypeId.ROADMAP
		});
		
		google.maps.event.addListener(this.map, "zoom_changed", function() {
			var mapZoom = ModelkiGoogleMapsSearch.map.getZoom();
			
			$("input#map_zoom").val(mapZoom);
			
			if (mapZoom < 0) {
				mapZoom = 0;
			}
			
			if (mapZoom > 19) {
				mapZoom = 19;
			}
			
			var radius = parseInt($("input#radius").val());
			
			if (radius > 0) {
				var sliderValue = parseInt($("input#slider_value").val());
				
				radius = ModelkiGoogleMapsSearch.calculateRadius(sliderValue, mapZoom);
				
				ModelkiGoogleMapsSearch.circle.setRadius(radius);
				
				$("input#radius").val(radius);
				
				ModelkiGoogleMapsSearch.search();
			}
		});
		
		google.maps.event.addListener(this.map, "idle", function() {
			$("input#map_center_lat").val(ModelkiGoogleMapsSearch.map.getCenter().lat());
			$("input#map_center_lng").val(ModelkiGoogleMapsSearch.map.getCenter().lng());
		});
		
		google.maps.event.addListener(this.map, "click", function(event) {
			ModelkiGoogleMapsSearch.placeCircleMarker(event.latLng);
			ModelkiGoogleMapsSearch.search();
		});
		
		var sliderValue = parseInt($("input#slider_value").val());
		
		if (isNaN(sliderValue)) {
			sliderValue = this.config.init.sliderValue;
		}
		
		var options = {
			min: this.config.init.minValue,
			max: this.config.init.maxValue,
			startValue: sliderValue,
			stepping: 1,
			slide: function(e, ui) {
				if (ModelkiGoogleMapsSearch.circle.getMap()) {
					var zoom = ModelkiGoogleMapsSearch.map.getZoom();
					var radius = ModelkiGoogleMapsSearch.calculateRadius(ui.value, zoom);
					ModelkiGoogleMapsSearch.circle.setRadius(radius);
					$("input#slider_value").val(ui.value);
					$("input#radius").val(radius);
				} else {
					$("input#slider_value").val('');
					$("input#radius").val('');
				}
			},
			change: this.search
		};
		
		$("input#slider_value").val(sliderValue);
		
		var radius = parseInt($("input#radius").val());
		
		if (radius > 0) {
			options.startValue = $("input#slider_value").val();
			
			$(".slider").slider(options);
			
			var lat = parseFloat($("input#lat").val());
			var lng = parseFloat($("input#lng").val());
			
			var latLng = new google.maps.LatLng(lat, lng);
			
			this.placeCircleMarker(latLng);
		} else {
			$(".slider").slider(options);
			$(".slider").slider("disable");
		}
		
		this.markerClusterer = new MarkerClusterer(this.map, [], {
			styles: this.config.init.styles
		});
	},
	
	calculateRadius: function(sliderValue, mapZoom) {
		return Math.round(sliderValue * ModelkiGoogleMapsSearch.config.calculateRadius.radius[mapZoom] / 5);
	},
	
	placeCircleMarker: function(latLng) {
		$(".slider").slider("enable");
		
		var radius = parseInt($("input#radius").val());
		
		if (isNaN(radius)) {
			var sliderValue = $(".slider").slider("value");
			var mapZoom = ModelkiGoogleMapsSearch.map.getZoom();
			
			radius = ModelkiGoogleMapsSearch.calculateRadius(sliderValue, mapZoom);
		}
		
		$("input#radius").val(radius);
		
		if (this.marker && this.circle) {
			this.marker.setMap(this.map);
			this.marker.setPosition(latLng);
			this.circle.setMap(this.map);
			this.circle.setRadius(radius);
		} else {
			var options = {
				map: this.map,
				position: latLng,
				draggable: true
			}
			
			if (this.config.placeCircleMarker.icon != null) {
				var image = new google.maps.MarkerImage(
					this.config.placeCircleMarker.icon,
					new google.maps.Size(64, 64),
					new google.maps.Point(0, 0),
					new google.maps.Point(32, 32)
				);
				
				options.icon = image;
				
				var shape = {
					coord: [1, 32, 18, 28, 28, 18, 32, 1, 36, 16, 46, 28, 61, 32, 46, 36, 36, 46, 31, 61, 28, 46, 18, 36, 1, 32],
					type: 'poly'
				};
				
				options.shape = shape;
			}
			
			this.marker = new google.maps.Marker(options);
			
			google.maps.event.addListener(this.marker, "dragend", function() {
				ModelkiGoogleMapsSearch.updateCircleMarkerPosition(ModelkiGoogleMapsSearch.circle.getCenter());
				ModelkiGoogleMapsSearch.search();
			});
			
			google.maps.event.addListener(this.marker, "click", function() {
				ModelkiGoogleMapsSearch.marker.setMap(null);
				ModelkiGoogleMapsSearch.circle.setMap(null);
				ModelkiGoogleMapsSearch.updateCircleMarkerPosition(null);
				
				$("input#radius").val('');
				$(".slider").slider("disable");
				
				ModelkiGoogleMapsSearch.search();
			});
			
			this.circle = new google.maps.Circle({
				map: this.map,
				radius: radius,
				fillColor: "#fff",
				fillOpacity: 0.0,
				strokeColor: this.config.init.strokeColor,
				strokeOpacity: 1,
				strokeWeight: 2
			});
			
			this.circle.bindTo("center", this.marker, "position");
		}
		
		this.map.setCenter(latLng);
		this.updateCircleMarkerPosition(latLng);
	},
	
	updateCircleMarkerPosition: function(latLng) {
		if (latLng) {
			$("input#lat").val(latLng.lat());
			$("input#lng").val(latLng.lng());
		} else {
			$("input#lat").val('');
			$("input#lng").val('');
		}
	},
	
	placeMarker: function(markerData) {
		var latLng = new google.maps.LatLng(markerData["lat"], markerData["lng"]);
		var title = markerData["title"];
		var contentString = '<h1><a href' + '="' + markerData["link"] + '">' + markerData["title"] + '<\/a><\/h1><div style="padding: 5px;"><a href' + '="' + markerData["link"] + '"><img src' + '="' + markerData["foto"] + '" alt="' + markerData["foto_alt"] + '" width="' + markerData["img_w"] + '" height="' + markerData["img_h"] + '" \/><\/a><\/div>';
		
		var options = {
			position: latLng,
			title: title
		};
		
		if (this.config.placeMarker.icon != null) {
			var image = new google.maps.MarkerImage(
				this.config.placeMarker.icon,
				new google.maps.Size(20, 34),
				new google.maps.Point(0, 0)
			);
			
			options.icon = image;
			
			var shape = {
				coord: [9, 0, 6, 1, 4, 2, 2, 4, 0, 8, 0, 12, 1, 14, 2, 16, 5, 19, 7, 23, 8, 26, 9, 30, 9, 34, 11, 34, 11, 30, 12, 26, 13, 24, 14, 21, 16, 18, 18, 16, 20, 12, 20, 8, 18, 4, 16, 2, 15, 1, 13, 0],
				type: 'poly'
			};
			
			options.shape = shape;
		}
		
		var marker = new google.maps.Marker(options);
		
		var infoWindow = new google.maps.InfoWindow({
			content: contentString
		});
		
		google.maps.event.addListener(marker, "click", function() {
			infoWindow.open(this.map, marker);
		});
		
		this.markerClusterer.addMarker(marker);
	},
	
	search: function() {
		var data = {};
		
		for (i in ModelkiGoogleMapsSearch.config.search.dataSelectors) {
			data[i] = $(ModelkiGoogleMapsSearch.config.search.dataSelectors[i]).val()
		}
		
		if (ModelkiGoogleMapsSearch.config.search.url) {
			$.post(
				ModelkiGoogleMapsSearch.config.search.url,
				data,
				function(data, textStatus, XMLHttpRequest) {
					$(ModelkiGoogleMapsSearch.config.search.dataHtmlSelector).html(data.html);
					
					ModelkiGoogleMapsSearch.markerClusterer.clearMarkers();
					
					for (i in data.markers) {
						ModelkiGoogleMapsSearch.placeMarker(data.markers[i]);
					}
				},
				"json"
			);
		}
	}
}

ModelkiGoogleMapsPlaceMarker = function(mapId, latSelector, lngSelector) {
	this.mapId = mapId;
	this.latSelector = latSelector;
	this.lngSelector = lngSelector;
	
	this.config = {
		init: {
			mapZoom: 6,
			mapCenter: new google.maps.LatLng(51.9194380, 19.1451360)
		},
		placeMarker: {
			icon: null
		},
		geocodeAddress: {
			selectors: []
		}
	}
	
	this.geocoder = null;
	this.map = null;
	this.marker = null;
	
	this.updateMarkerPosition = function(latLng) {
		if (latLng) {
			$(this.latSelector).val(latLng.lat());
			$(this.lngSelector).val(latLng.lng());
		} else {
			$(this.latSelector).val('');
			$(this.lngSelector).val('');
		}
	}
	
	this.init = function() {
		this.geocoder = new google.maps.Geocoder();
		
		var mapZoom = this.config.init.mapZoom;
		var latLng = this.config.init.mapCenter;
		var lat = parseFloat($(this.latSelector).val());
		var lng = parseFloat($(this.lngSelector).val());
		
		var placeMarker = false;
		
		if (!isNaN(lat) && !isNaN(lng)) {
			placeMarker = true;
			latLng = new google.maps.LatLng(lat, lng);
			mapZoom = 16;
		}
		
		this.map = new google.maps.Map(document.getElementById(this.mapId), {
			zoom: mapZoom,
			center: latLng,
			mapTypeId: google.maps.MapTypeId.ROADMAP
		});
		
		if (placeMarker) {
			this.placeMarker(latLng);
		} else {
			this.marker = null;
		}
		
		google.maps.event.addListener(this.map, "click", (function(modelkiGoogleMapsPlaceMarker) { return function(event) {
			modelkiGoogleMapsPlaceMarker.placeMarker(event.latLng);
		}})(this));
	}
	
	this.placeMarker = function(latLng) {
		if (this.marker) {
			this.marker.setMap(this.map);
			this.marker.setPosition(latLng);
		} else {
			var options = {
				position: latLng,
				map: this.map,
				draggable: true
			};
			
			if (this.config.placeMarker.icon != null) {
				var image = new google.maps.MarkerImage(
					this.config.placeMarker.icon,
					new google.maps.Size(20, 34),
					new google.maps.Point(0, 0)
				);
				
				options.icon = image;
				
				var shape = {
					coord: [9, 0, 6, 1, 4, 2, 2, 4, 0, 8, 0, 12, 1, 14, 2, 16, 5, 19, 7, 23, 8, 26, 9, 30, 9, 34, 11, 34, 11, 30, 12, 26, 13, 24, 14, 21, 16, 18, 18, 16, 20, 12, 20, 8, 18, 4, 16, 2, 15, 1, 13, 0],
					type: 'poly'
				};
				
				options.shape = shape;
			}
			
			this.marker = new google.maps.Marker(options);
			
			google.maps.event.addListener(this.marker, "dragend", (function(modelkiGoogleMapsPlaceMarker) { return function() {
				modelkiGoogleMapsPlaceMarker.updateMarkerPosition(
					this.getPosition()
				);
			}})(this));
			
			google.maps.event.addListener(this.marker, "click", (function(modelkiGoogleMapsPlaceMarker) { return function() {
				modelkiGoogleMapsPlaceMarker.marker.setMap(null);
				modelkiGoogleMapsPlaceMarker.updateMarkerPosition(null);
			}})(this));
		}
		
		this.map.setCenter(latLng);
		this.updateMarkerPosition(latLng);
	}
	
	this.geocodeAddress = function() {
		if (this.geocoder) {
			var address = [];
			
			for (var i = 0; i < this.config.geocodeAddress.selectors.length; i++) {
				address[i] = $(this.config.geocodeAddress.selectors[i]).val();
			}
			
			this.geocoder.geocode({'address': address.join(' ')}, (function(modelkiGoogleMapsPlaceMarker) { return function(results, status) {
				if (status == google.maps.GeocoderStatus.OK) {
					modelkiGoogleMapsPlaceMarker.map.setCenter(results[0].geometry.location);
				}
			}})(this));
		}
	}
}
