(function($)
{
	function GoogleMaps(root, configuration)
	{
		var self 			= this;
		var workspace 		= null;
		var viewport		= null;
		var geocoder		= null;
		var hasWorkspace	= false;
		var zoomlevel 		= 0;
		var zoomstep		= 0;
		var autosearch		= '';
		var hitPoint 		= null;
		var markerResult	= [];


		/**
		 * Öffentlicher Bereich
		 */
		$.extend(self, {

			/**
			 * Suche starten. Google-Request schicken
			 */
			search: function(__address) {

				// Die Karte wird auf den Anfangs Zoomwert gesetzt.
				self.zoomlevel	= 0;
				self.zoomstep	= 0;
				self.autosearch	= '';

				if (__address.length) {

					// PLZ Zahlen eingegeben
					if (parseInt(__address) == __address) {
						$.post(configuration.interface, {postcode: __address}, function(result) {

							if (result.postcode) {
								configuration.input.attr('value', result.postcode);
								__address = result.postcode + " " + result.city + ", " + result.address1;
							}

							geocoder.getLocations(__address, self.resolveLocations);
						}, 'json');
					}
					else {
						geocoder.getLocations(__address, self.resolveLocations);
					}

					if (configuration.webtrekk && 'undefined' != typeof wt_sendinfo) {
						var webtrekk = configuration.webtrekk + jQuery.trim(__address).replace(/\s/g, '_').toLowerCase();
						wt_sendinfo(webtrekk, 'click');
					}
		    	}
    			else {
		    		self.getAddresses();
    			}
			},

			/**
			 * Googleabfrage verarbeiten
			 */
			resolveLocations: function(__locations) {
		    	if (!__locations) {
		    		window.alert("Address not found!");
		    	}
		    	else {
					var extendedData	= __locations.Placemark ? __locations.Placemark[0].ExtendedData : undefined;
					var bounds 			= extendedData ? extendedData.LatLonBox : undefined;

					if (bounds) {
						var mapBounds = new GLatLngBounds(new GLatLng(bounds.south, bounds.west), new GLatLng(bounds.north, bounds.east));

						self.zoomlevel 	= workspace.getBoundsZoomLevel(mapBounds);
						self.hitPoint 	= mapBounds.getCenter();

						workspace.setCenter(mapBounds.getCenter(), workspace.getBoundsZoomLevel(mapBounds));
						self.autoSearch();
					}

					// Keine Ergebnisse
					else
					{
						viewport.clearOverlays();

						$('#LocatorListSimple').html('<p class="error">'+$.translate('emptyresult')+'</p>');
					}
				}
		    },

			/**
			 * Einstiegspunkt um die Ansicht möglichst passend zu machen.
			 */
			autoSearch: function() {
				workspace.setZoom(self.zoomlevel);

		    	var clippingBounds 	= workspace.getBounds();
		    	var pointSouthWest 	= clippingBounds.getSouthWest();
				var pointNorthEast 	= clippingBounds.getNorthEast();

				var request = {
					mode: 'count',
					bottomright: pointSouthWest.lat() + ',' + pointSouthWest.lng(),
					topleft: pointNorthEast.lat() + ',' + pointNorthEast.lng()
				};

				$("input[id^='citem']").each(function(){
					request[$(this).attr("name")] = $(this).attr("checked");
				});

				$.post(configuration.interface, request, self.checkZoom, 'json');
			},

			/**
			 * Hier werden nun die Regeln der Config abgefrühstückt
			 */
			checkZoom : function(__response) {

				var rules = {
					'maxzoom':		false,
					'minzoom':		false,
					'maxresult':	false,
					'minresult':	false,
					'zoomstep':		false
				};

				if(configuration.autosearch.maxZoomLevel < self.zoomlevel) rules.maxzoom = true;
				if(configuration.autosearch.minZoomLevel > self.zoomlevel) rules.minzoom = true;
				if(configuration.autosearch.maxResults < __response.count) rules.maxresult = true;
				if(configuration.autosearch.minResults > __response.count) rules.minresult = true;
				if(configuration.autosearch.zoomSteps <= self.zoomstep) rules.zoomstep = true;

				// Wenn die maximale Anzahl an Zooms noch nicht erreicht ist...
				if (!rules.zoomstep) {

					// Regel der Reihe durchgehen
					if (rules.maxzoom) {
						self.zoomlevel--;
						self.zoomstep++;
						self.autosearch = 'maxzoom';
						self.autoSearch();

						return false;
					}

					if (rules.minzoom) {
						self.zoomlevel++;
						self.zoomstep++;
						self.autosearch = 'minzoom';
						self.autoSearch();

						return false;
					}

					if (rules.maxresult && self.autosearch != 'minresult') {
						self.zoomlevel++;
						self.zoomstep++;
						self.autosearch = 'maxresult';
						self.autoSearch();

						return false;
					}

					if (rules.minresult) {
						self.zoomlevel--;
						self.zoomstep++;
						self.autosearch = 'minresult';
						self.autoSearch();

						return false;
					}
				}

				viewport.setCenter(self.hitPoint,self.zoomlevel);

				return true;
			},

			/**
			 * Seperate Abfrage zum rendern der Nodes wird abgeschickt...
			 */
			getAddresses: function() {
				$("#infoLayer").hide();
				workspace.setZoom(self.zoomlevel);

				self.hitPoint 		= viewport.getCenter();
				self.zoomlevel 		= viewport.getZoom();

		    	var clippingBounds 	= viewport.getBounds();
		    	var pointSouthWest 	= clippingBounds.getSouthWest();
				var pointNorthEast 	= clippingBounds.getNorthEast();

				//var bounds = new GLatLngBounds(clippingBounds.getSouthWest(), clippingBounds.getNorthEast());

				// Kartenausschnitt innerhalb der Koordinaten aus der Datenbank
				//if (bounds.containsLatLng(new GLatLng(47.415987, 5.936907)) && bounds.containsLatLng(new GLatLng(54.905972, 14.971165)))
				//{
					//alert(bounds.containsLatLng(new GLatLng(47.415987, 5.936907)));
					//alert(bounds.containsLatLng(new GLatLng(54.905972, 14.971165)));

					//$("#debug").html("latitude: " + pointNorthEast.lat() + " AND " + pointSouthWest.lat() + "<br>" + "longitude: " + pointNorthEast.lng() + " AND " + pointSouthWest.lng());

					var request = {
						mode:			'complete',
						center:			self.hitPoint.lat() + ',' + self.hitPoint.lng(),
						bottomright:	pointSouthWest.lat() + ',' + pointSouthWest.lng(),
						topleft:		pointNorthEast.lat() + ',' + pointNorthEast.lng(),
						zoom:			viewport.getZoom()
					};

					$("input[id^='citem']").each(function(){
						request[$(this).attr("name")] = $(this).attr("checked");
					});

					$.post(configuration.interface, request, self.renderAddresses, 'json');
				//}
			},

			/**
			 * ... und verarbeitet.
			 */
			renderAddresses: function(__response) {

				viewport.clearOverlays();



				for (key in __response.data) {

					if (!__response.data[key].group) {
						continue;
					}

					var currentNode = new GLatLng(__response.data[key].coordinates[1], __response.data[key].coordinates[0]);

					var resultID = __response.data[key].id;

					var greenMarker 		= new GIcon(G_DEFAULT_ICON);
					greenMarker.image 		= __response.data[key].group[1];
					greenMarker.iconSize 	= new GSize(16, 38);
					greenMarker.iconAnchor 	= new GPoint(16, 29);
					greenMarker.shadow  	= "/page/img/locator/shadow.png";
					greenMarker.shadowSize 	= new GSize(36, 38);
					key 					= parseInt(key) + 1;

					var marker 				= new GMarker(currentNode, {icon:greenMarker, title:resultID});
					marker.resultID			= resultID;
					markerResult[key-1] 	= marker;
					
					GEvent.addListener(marker, "click", function()
					{
						var point		= this.getPoint();
						var pixel		= viewport.fromLatLngToContainerPixel(point);
						var pixelMap	= viewport.getSize();
						var x = pixel.x;
						var y = pixel.y;

						var x1 = pixel.x + 340;
						var y1 = pixel.y + 212;

						x = x - 340/2 - 2*marker.getIcon().iconSize.width;
						y = y - 212;

						// Kollision rechts
						if (x1 > pixelMap.width) {
							x = x - 340 + marker.getIcon().iconSize.width;
						}
						else {
							x = x + marker.getIcon().iconSize.width;
						}

						// Kollision unten
						if (y1 < pixelMap.height) {
						}
						else {
							y = y - 212 - marker.getIcon().iconSize.width;
						}

						// Kollision links
						if (x < -190) {
							x = x - (x + 190);
						}

						var template = new googleMapsTemplate();
						template.get_tooltip(this.resultID, point, y, x);
					});

					viewport.addOverlay(marker);
				}

				// Dynamische Ergebnisliste
				var template	= new googleMapsTemplate();
				var element 	= template.get_result_list(__response.data);

				$("a[rel^='shape__']", element).bind("click", function()
				{
					var markerid = parseInt($(this).attr("rel").split("__")[1]);
					GEvent.trigger(markerResult[markerid], 'click');
				});

				$("#infoLayer").bind("click", function(){
					$("#infoLayer").hide();
				});

				$('#LocatorListSimple').html('').append(element);
				element.paging();

			}

		});

		/**
		 * Private Methoden
		 */
		function initialize() {
			if (GBrowserIsCompatible()) {
				$('body').bind('unload', function() {
					GUnload();
				});

				viewport = new GMap2(root[0]);
				viewport.setCenter(new GLatLng(configuration.start.latitude, configuration.start.longitude), configuration.start.zoom);
				viewport.setUIToDefault();

				workspace = viewport;

				if (configuration.workspace)
				{
					if (typeof configuration.workspace == 'string') {
						$('body').append('<div id="' + configuration.workspace + '"></div>');
						element = $('#' + configuration.workspace).css({position: 'absolute', top: '-1000px', left: '-1000px', display: 'block', height: root.height(), width: root.width()});
					}
					else {
						element = configuration.workspace;
					}

					workspace = new GMap2(element[0]);
					workspace.setCenter(new GLatLng(configuration.start.latitude, configuration.start.longitude), configuration.start.zoom);
					workspace.setUIToDefault();

					GEvent.addListener(viewport, 'moveend', function() {
						self.getAddresses();
					});

					GEvent.addListener(viewport, 'dragstart', function() {
						if (configuration.input) configuration.input.attr('value', '');
						$("#infoLayer").hide();
					});

					hasWorkspace = true;
				}

				geocoder = new GClientGeocoder();
				geocoder.setBaseCountryCode(configuration.cctld);
			}

			return self;
		}

		initialize();
	}

	/**
	 * jQuery plugin implementation
	 */
	jQuery.prototype.googleMaps = function(configuration) {
		var api = this.eq(typeof conf == 'number' ? conf : 0).data("GoogleMaps");

		if (api) {
			return api;
		}

		var options = {
			'workspace':	null,
			'input':		null,
			'interface':	'/m/22_7429/page/modules/locator/response.php',
			'cctld':		'DE',
			'webtrekk':		'',

			'autosearch': {
				'minResults':	10,
				'maxResults':	48,
				'minZoomLevel':	0,
				'maxZoomLevel':	15,
				'zoomSteps':	3
			},

			'start': {
				'latitude':		0,
				'longitude':	0,
				'zoom':			12
			}
		};

		$.extend(options, configuration);

		this.each(function() {
			var el = new GoogleMaps($(this), options);
			$(this).data("GoogleMaps", el);
		});

		return this;
	};

})(jQuery);
