(function($)
{
	function GoogleMaps(root, configuration)
	{
		var self 			= this;
        var domObject       = root;
		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	= [];
        var sortMode        = configuration.sortMode;
        var sortFilter      = configuration.sortFilter;
        var searchOptions   = {
            type : undefined,
            term : undefined
        };
        var addressOptions  = {
            mode : 'complete',
            term : undefined
        };
        var routing         = {
            enabled      : configuration.routing,
            active       : configuration.routingconfig.active,
            instance     : undefined,
            configuration: configuration.routingconfig
        };
        var disabled        = (configuration.disabled == true) ? true : false;


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

			/**
			 * Suche starten. Google-Request schicken
			 */
			search: function(__searchterm, __searchBy) {
            
                if (routing.active == true) {
                    self.leaveRoutingMode(function () { self.search(__searchterm, __searchBy); } );
                    return;
                }
            
				// Die Karte wird auf den Anfangs Zoomwert gesetzt.
				self.zoomlevel	= 0;
				self.zoomstep	= 0;
				self.autosearch	= '';
                addressOptions.mode = 'complete';
                addressOptions.term = undefined;
                
                var searchBy = (__searchBy != undefined && (__searchBy == 'location' || __searchBy == 'name')) ? __searchBy : 'location';

				if (__searchterm.length) {

					// PLZ Zahlen eingegeben
                    if (searchBy == 'location') {
                        searchOptions.type = 'bypostcode';
                        searchOptions.term = __searchterm;
                        
                        if (parseInt(__searchterm) == __searchterm) {
                            $.post(configuration.interface, {postcode: __searchterm}, function(result) {

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

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

                        if (configuration.webtrekk && 'undefined' != typeof wt_sendinfo) {
                            var webtrekk = configuration.webtrekk + jQuery.trim(__searchterm).replace(/\s/g, '_').toLowerCase();
                            wt_sendinfo(webtrekk, 'click');
                        }
                    } else {
                        
                        searchOptions.type = 'byname';
                        searchOptions.term = __searchterm;
                        
                        $.post(configuration.interface, {searchbyname: __searchterm}, function(result) {
                            if (result && result.count > 0) {
                                
                                var mapBounds = new GLatLngBounds(new GLatLng(result.sw.lat, result.sw.lng), new GLatLng(result.ne.lat, result.ne.lng));

                                self.zoomlevel 	= viewport.getBoundsZoomLevel(mapBounds);
                                self.hitPoint 	= mapBounds.getCenter();
                                
                                if (self.zoomlevel > 10) {
                                    self.zoomlevel = 10;
                                }
                                
                                addressOptions.mode = 'namelist';
                                addressOptions.term = __searchterm;
                                
                                viewport.setCenter(mapBounds.getCenter(), self.zoomlevel);
                                
                            } else {
                                viewport.clearOverlays();

                                $('#LocatorListSimple').html('<p class="error">'+$.translate('emptyresult')+'</p>');
                            }
                        }, 'json');
                    }
		    	}
    			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(),
                    sort: sortMode
				};

				$("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() {
                
                if (routing.active === true) {
                    routing.instance.saveRouteData();
                    return;
                }
                
				$("#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)));
                    
					var request = {
						mode:			addressOptions.mode,
						center:			self.hitPoint.lat() + ',' + self.hitPoint.lng(),
						bottomright:	pointSouthWest.lat() + ',' + pointSouthWest.lng(),
						topleft:		pointNorthEast.lat() + ',' + pointNorthEast.lng(),
						zoom:			viewport.getZoom(),
                        searchoptions:  searchOptions,
                        sort:           sortMode
					};
                    
                    if (addressOptions.term != undefined) {
                        request.term = addressOptions.term;
                    }

					$("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(self, configuration.template);
						template.get_tooltip(this.resultID, point, y, x);
					});

					viewport.addOverlay(marker);
				}

				// Dynamische Ergebnisliste
				var template	= new googleMapsTemplate(self, configuration.template);
				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');
				});

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

			},
            
            getViewport : function () {
                return viewport;
            },
            
            enterRoutingMode : function () {
                routing.active = true;
                $(domObject).height(328).parent().height(328);
                viewport.checkResize();
            },
            
            leaveRoutingMode : function (__callback) {
		    	var clippingBounds 	= workspace.getBounds();
		    	var pointSouthWest 	= clippingBounds.getSouthWest();
				var pointNorthEast 	= clippingBounds.getNorthEast();

				var request = {
					mode: 'route',
                    routeactive: false,
					bottomright: pointSouthWest.lat() + ',' + pointSouthWest.lng(),
					topleft: pointNorthEast.lat() + ',' + pointNorthEast.lng(),
                    searchoptions: searchOptions,
                    sort:          sortMode
				};
                
                $.post(
                    configuration.interface,
                    request,
                    function () {
                        routing.active = false;
                        $('#RouteResultDetail').remove();
                        $('#RouteContainer').hide();
                        $('#LocatorListSimple').show();
                        
                        var backupCenter = viewport.getCenter();
                        
                        $(domObject).height(560).parent().height(560);
                        viewport.checkResize();
                        viewport.setCenter(backupCenter);
                        
                        if (__callback != undefined) {

                            try { 
                                __callback();
                            } catch (e) {
                                self.getAddresses();
                            }
                            
                        } else {
                            self.getAddresses();
                        }
                    }
                );
            },
            
            isRouting : function () {
                return routing.active;
            },
            
            hasSortFilter : function () {
                return sortFilter;
            },
            
            getRouting : function () {
                return routing.instance;
            },
            
            getConfiguration : function (__key) {
                if (configuration[__key]) {
                    return configuration[__key];
                }
                
                return undefined;
            },
            
            routeInitFailure : function () {
                self.leaveRoutingMode();
            },
            
            setSortMode : function (__mode) {
                sortMode = __mode;
                self.getAddresses();
            },
            
            getSortMode : function () {
                return sortMode;
            }

		});

		/**
		 * Private Methoden
		 */
		function initialize() {
            if (disabled) {
                $('<div onmousedown="alert($.translate(\'choose_country\').convertToUnicode());" style="background-color: white; opacity: 0.3; filter:Alpha(opacity=30); position: absolute; width: ' + root.width() + 'px; height: ' + root.height() + 'px; z-index: 10000;"></div>').insertBefore(root);
            }
                    
			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 && addressOptions.mode == 'complete') {
                            configuration.input.attr('value', '');
                            searchOptions.term = undefined;
                            searchOptions.type = undefined;
                        }
						$("#infoLayer").hide();
					});

					hasWorkspace = true;
				}

				geocoder = new GClientGeocoder();
				geocoder.setBaseCountryCode(configuration.cctld);
                
                if (disabled) {
                    viewport.disableScrollWheelZoom();
                    viewport.disableGoogleBar();
                    viewport.disableContinuousZoom();
                    viewport.disableDoubleClickZoom();
                    viewport.disableInfoWindow();
                    viewport.disableDragging();
                    
                    /*$('> div.gmnoprint:eq(0)', root).remove();
                    $('> div.gmnoprint:eq(0)', root).remove();*/
                }
                
                if (routing.enabled) {
                    
                    routing.instance = new GoogleMapsRoute(self, routing.configuration);
                    routing.instance.setRouteDetailContainer($('#RouteContainer'));
                    routing.instance.setDestinationDetailContainer($('#LocatorListSimple'));
                    
                    if (routing.active) {
                        routing.instance.setDestinationData(routing.configuration.destinationData);
                        routing.instance.planRoute(function () { self.routeInitFailure(); });
                    }
                }
			}

			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 = {
            'disabled':     false,
			'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
			},
            'sortMode':         'default',
            'template':         'default',
            'sortFilter':       false,
            'routing':          false,
            'routingconfig' :   {
                'active':           false,
                'defaultStreet':    $.translate('proute_street'),
                'defaultCity':      $.translate('proute_zipcity'),
                'destinationData':  {}
            }
		};

		$.extend(options, configuration);

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

		return this;
	};

})(jQuery);

