var GoogleMapManager = new function(){
	
	// Costants	
	var MARKERS_FOLDER_PATH = "/backend/images/google-map-icons/";
	var DEFAULT_MARKER_FILE_NAME = "default.png";
	var DEFAULT_MAP_ZOOM_FOR_SINGLE_MARKER = 14;
	
	var MARKER_CLUSTERER_ZOOM_LINK_TEXT_BEKENMAKINGEN = "Zoom in om meer bekendmakingen te bekijken  &rarr;"
	var MARKER_CLUSTERER_ZOOM_LINK_TEXT_GENERAL = "Zoom in om meer locaties te bekijken";
	var defaultMarkerClustererZoomLinkText = MARKER_CLUSTERER_ZOOM_LINK_TEXT_BEKENMAKINGEN;
	
	var map = null;
	var geoCoder = null;
	var markerClusterer = null;
	
	var latLngCallsCount = 0;
	
	var mapDivElement;
	var mapLoaderDivElement;
	var pathToGoogleMarkerIcons;
	var isAtLeastOneMarkerGeoCoded = false;
	var isMapRangeDefined = false;
	
	var addedMarkersBounds = new GLatLngBounds();
	var addedMarkers = {};
	var markersForCluster = [];
	
	var clusterIcon = "default.png";
	
	var contextPath = "";
	
	var defaultMapCoords = {
		x: 52.118312,
		y: 4.880676,
		zoom: 8
	};
	
	var clusterIconConfig = {
		width: 53,
		height: 52,
		urlPrefix: "/backend/images/google-map-cluster-icons/" 
	};
	
	var d = document;
	var self = this;
	
	this.cluster;
	
	this.init = function(range, contextPath_, clusterIcon_){
		if (GBrowserIsCompatible()) {
			mapDivElement = d.getElementById("map_canvas"); 
	 		mapDivElement.style.display = "block";
	 		
	        map = new GMap2(mapDivElement);
			geoCoder = new GClientGeocoder();

			// init latLng calls count
			latLngCallsCount = 0;

	        mapLoaderDivElement = d.getElementById("googleMapLoader");
	    	GEvent.addListener(map, "tilesloaded", function() {	    
	    		//console.log("tilesloaded");
				if (mapLoaderDivElement) {
					mapLoaderDivElement.style.display = "none";		  						
				}
		    });
	
			map.addControl(new GSmallZoomControl());
			map.addControl(new GMapTypeControl());
			
			if (range){
				setDefinedRange(range);
			} else {
				map.setCenter(new GLatLng(defaultMapCoords.x, defaultMapCoords.y), defaultMapCoords.zoom);
			}
			
			if (contextPath_){
				contextPath = contextPath_;
			}
			
			if (clusterIcon_){
				clusterIcon = clusterIcon_;
			}
			
	 		map.enableScrollWheelZoom();
		}		
	};
	
	var setDefinedRange = function(range){
		isMapRangeDefined = true;
		range = range.replace("(","");
		range = range.replace(")","");
		range = range.replace(" ","");
		
		var params = range.split("&&");
		range = params[0];
		var rangeZoom = parseInt(params[1]);   				
		var coords =  range.split(",");
		var rangeMapCoords = new GLatLng( parseFloat(coords[0]), parseFloat(coords[1]));
	    map.setCenter(rangeMapCoords, rangeZoom);
	};

	/** visibility **/

	var hideMap = function(){
		mapDivElement.style.display = "none";
		if(mapLoaderDivElement) {
			mapLoaderDivElement.style.display = "none";
		}
	};

	var isHideMap = function() {
		return mapDivElement.style.display == "none" && (mapLoaderDivElement ? mapLoaderDivElement.style.display == "none" : true);
	}

	var showMap = function(){
		mapDivElement.style.display = "block";
	};	

	var isShowMap = function() {
		return mapDivElement.style.display == "block" || (mapLoaderDivElement && mapLoaderDivElement.style.display == "block");
	}

	/** *** **/

	var getMarkerIconPath = function(markerIcon){
		var iconImage = "";
		if (markerIcon.indexOf("/") == -1) {	
			if (!pathToGoogleMarkerIcons) {
			    if(contextPath){
			      iconImage += contextPath + MARKERS_FOLDER_PATH;
			    }else { 
			      iconImage = MARKERS_FOLDER_PATH;
			    }
			    pathToGoogleMarkerIcons = iconImage;
			}
			if (markerIcon) {
				iconImage = pathToGoogleMarkerIcons + markerIcon;
			} else {
				iconImage = pathToGoogleMarkerIcons + "default.png";
			}
		} else {
			iconImage = markerIcon;
		}	
	    return iconImage;
	};
	
	var trim = function(str){	
		return str.replace(/^\s+|\s+$/g,"");
	};
	
	var makeGIcon = function(markerIconPath){
		var iconImg = new GIcon(G_DEFAULT_ICON);
		iconImg.iconSize = new GSize(20, 34);			
		iconImg.image = markerIconPath;
		return iconImg;
	};
	
	var getMarkerPopupTextIfClustered = function(date, address, postcode, type, sort, link){
		var str = "<div class='markerPopup'>";
		if (date){
			str += date + " | ";
		}
		str += address  + " " + postcode + 
				"<br /><br />";
		if (type){
			str += type + ", "; 
		}
		if (sort){
			str +=  sort;	
		}
		
		if (type || sort){
			str += "<br /><br />";
		}
				
		str += "<a href = '" + link +"'>Naar detailspagina</a></div><br />";
		return str;
	};
	
	var makeClusterIconObj = function(){
		// Define custom cluster icon
		var clusterIconObj = new GIcon();
		clusterIconObj.image				= contextPath + clusterIconConfig.urlPrefix + clusterIcon;
		clusterIconObj.iconSize			= new GSize(27, 40);
		clusterIconObj.shadow				= contextPath + '/backend/images/new_shadow.png';
		clusterIconObj.shadowSize			= new GSize(40, 40);
		clusterIconObj.iconAnchor			= new GPoint(10, 30);
		clusterIconObj.infoWindowAnchor	= new GPoint(10, 8);
		
		return clusterIconObj;
	}
	
	var myClusterClick = function(args){
		markerClusterer.defaultClickAction=function(){
			map.setCenter(args.clusterMarker.getLatLng(), map.getBoundsZoomLevel(args.clusterMarker.clusterGroupBounds))
			delete markerClusterer.defaultClickAction;
		}		
		var html = '';	
		for (var i = 0; i < args.clusteredMarkers.length; i++){
			html += args.clusteredMarkers[i].html;
		}
		
		html = getFormattedHTML(html);
		html += "<br/><a href='#' class='clusterMeerLink' onclick='GoogleMapManager.cluster.defaultClickAction()'>" + defaultMarkerClustererZoomLinkText + "</a>";
		
		args.clusterMarker.openInfoWindowHtml(html);
	}
	
	var refreshCluster = function(){
		var markers = []
		for (var i in addedMarkers){
			if (addedMarkers.hasOwnProperty(i)){
				markers.push(addedMarkers[i].marker);
			}
		}
		if (markerClusterer != null) {
          markerClusterer.removeMarkers();
        }
        
        var clusterIconObj = makeClusterIconObj();
        
        markerClusterer = new ClusterMarker(map, { markers: markers, clusterMarkerClick: myClusterClick, clusterMarkerTitle: " " } );
		markerClusterer.clusterMarkerIcon = clusterIconObj;
		if (!isMapRangeDefined){
			markerClusterer.fitMapToMarkers();
			map.setZoom(map.getZoom() - 1);
		} else {
			markerClusterer.refresh(false);
		}
		self.cluster = markerClusterer;
	};
	
	var addClickHandler = function(marker, html){
		GEvent.addListener(marker, "click", function() {
			marker.openInfoWindowHtml(getFormattedHTML(html));
		});
	};
	
	var getFormattedHTML = function(html){
		return "<div style='he\\ight /**/:auto; -height:170px; max-height:170px; width:370px; overflow:auto; margin:10px 5px 0 10px;'>" + html + "</div>";
	};
	
	this.showSimpleMarker = function(postcode, address, markerIcon, xCoord, yCoord, zoom){
		if(!zoom) {
			zoom = 1;
		}
		
		if (!postcode && !address && !xCoord && !yCoord){
			return;
		}
		
		if (geoCoder) {
			if(postcode.length>6  && parseInt(postcode)){
				postcode = postcode.substring(0,6);
			}
				
			var searchString = "Europe, The Netherlands, ";
			if (postcode.length >= 4){
				searchString += postcode;
			}
			
			if (address){
				if ((/^(\d)+$/).test(address)){
					// it is number -> do not for search string
				} else {
					searchString += " " + address;	
				}
			}
			
			// for output
			if (postcode && postcode != "") {
				address = address ? ", " + address : "";
			}	 
			
			if (xCoord && yCoord){
				//isAtLeastOneMarkerGeoCoded = true;					
				var point = new GLatLng(parseFloat(xCoord), parseFloat(yCoord));
				map.setCenter(point, DEFAULT_MAP_ZOOM_FOR_SINGLE_MARKER);
				var iconImg = makeGIcon(getMarkerIconPath(markerIcon));
				var markerNew = new GMarker(point, iconImg); 
				map.addOverlay(markerNew);
				GEvent.addListener(markerNew, "click", function() {
					markerNew.openInfoWindowHtml(postcode + "" + address + "<br />" + xCoord + ", " + yCoord);
				});
				
				addedMarkersBounds.extend(point);
				
				/*
				if (!isAtLeastOneMarkerGeoCoded){
					hideMap();
				};
				*/
				if(map.getBoundsZoomLevel(addedMarkersBounds) <= zoom) {
					zoom = 1;
				}
				map.setZoom(map.getBoundsZoomLevel(addedMarkersBounds) - zoom);
				map.setCenter(addedMarkersBounds.getCenter());
				
			} else {
				getLatLngWrapper(geoCoder, searchString, function(point) {
					if (point) {		
						//isAtLeastOneMarkerGeoCoded = true;					
						map.setCenter(point, DEFAULT_MAP_ZOOM_FOR_SINGLE_MARKER);					
						var iconImg = makeGIcon(getMarkerIconPath(markerIcon));
						var marker = new GMarker(point, iconImg); 
						map.addOverlay(marker);
						GEvent.addListener(marker, "click", function() {
							marker.openInfoWindowHtml(postcode + "" + address);
						});
						
						addedMarkersBounds.extend(point);
						
						if(map.getBoundsZoomLevel(addedMarkersBounds) <= zoom) {
							zoom = 1;
						}
						map.setZoom(map.getBoundsZoomLevel(addedMarkersBounds) - zoom);
						map.setCenter(addedMarkersBounds.getCenter());
					}
					/*
					if (!isAtLeastOneMarkerGeoCoded){
						hideMap();
					}
					*/
				}); 
			}
		}
	};
	
	this.showSingleMarkerOnArticle = function(postcode, title, markerIcon, addressForOutput){
		if (geoCoder) {
			if(postcode.length>6  && parseInt(postcode)){
				postcode = postcode.substring(0,6);
			}
				
			var searchString = "Europe, The Netherlands, " + postcode; 
			
			getLatLngWrapper(geoCoder, searchString, function(point) {
				if (point) {		
					isAtLeastOneMarkerGeoCoded = true;					
					map.setCenter(point, DEFAULT_MAP_ZOOM_FOR_SINGLE_MARKER);					
					var iconImg = makeGIcon(getMarkerIconPath(markerIcon));
					var marker = new GMarker(point, iconImg); 
					map.addOverlay(marker);
					GEvent.addListener(marker, "click", function() {
						var html = '';
						if (addressForOutput){
							html = title + "<br /><br />" + addressForOutput;
						} else {
							html = title;
						}
						marker.openInfoWindowHtml(html);
					});
				}
				if (!isAtLeastOneMarkerGeoCoded){
					hideMap();
				}
			}); 
		}
	};
	
	this.showMarkerOnSubcategoryWithCluster = function(postcode, title, markerIcon, addressForOutput, detailsLink){
		if (geoCoder) {
			
			var searchString = "Europe, The Netherlands, " + postcode;
			defaultMarkerClustererZoomLinkText = MARKER_CLUSTERER_ZOOM_LINK_TEXT_GENERAL;
			
			function displayMarker(postcode, address, point, title){
				var key = point.lat().toString() + point.lng().toString();
				
				var markerHtml = "<b>" + title + "</b>" + 
								((address) ? "<br/ ><br/ >" + address : "") + 
								"<br /><br />" +
								(detailsLink ? "<a href='" + detailsLink + "'>Naar detailspagina</a>" : "") +
								"<br /><br />";
				
				if (!addedMarkers[key]){								
					var iconImg = makeGIcon(getMarkerIconPath(markerIcon));
					var marker = new GMarker(point, iconImg);
					addedMarkersBounds.extend(point);
					
					addedMarkers[key] = {};
					addedMarkers[key].marker = marker;
					addedMarkers[key].markerText = markerHtml;
					addClickHandler(marker, addedMarkers[key].markerText);
					
					addedMarkers[key].marker.html = addedMarkers[key].markerText; 
					
					if (!isMapRangeDefined){
						map.setZoom(map.getBoundsZoomLevel(addedMarkersBounds) - 1);
						map.setCenter(addedMarkersBounds.getCenter());
					}
				} else {						    
				    var marker = addedMarkers[key].marker;						    
					var iconImg = makeGIcon(getMarkerIconPath(markerIcon));    					  
					
					addedMarkers[key].markerText += markerHtml;
													
					GEvent.clearListeners(marker, "click"); 
					addClickHandler(marker, addedMarkers[key].markerText);								
					marker.html = addedMarkers[key].markerText;
				}
				refreshCluster();
			}
			
			(function(postcode, address, title){
				getLatLngWrapper(geoCoder, searchString, function(point) {
					if (point) {
						displayMarker(postcode, address, point, title);
					}				
				});
			})(postcode, addressForOutput, title);
		}
	}

	this.showPermissionsOnMap = function(loc, title){
		if (geoCoder) {
			var locat = loc;
			if(loc.length>6  && parseInt(loc)){
				locat = loc.substring(0,6);
			}
				
			getLatLngWrapper(geoCoder, "Europe, The Netherlands, " + locat + ", " + title, function(point) {
				if (!point) {
					mapDivElement.style.display="none";
				} else {
					map.setCenter(point, DEFAULT_MAP_ZOOM_FOR_SINGLE_MARKER);
					var marker = new GMarker(point);
					map.addOverlay(marker);
					GEvent.addListener(marker, "click", function() {
						marker.openInfoWindowHtml(title);
					});
				}
			});
		}
	}
	
	this.showAnnouncementItemWithCluster = function(postcode, address, date, title, link, type, sort, markerIcon, addressCoords){
		if (geoCoder) {
			var postcodeArray = postcode.split(";");
			var addressArray = address.split(";");
			var adressCoordsArray = addressCoords.split(";");
			
			for (var i=0; i<postcodeArray.length; i++){
				
				var address = trim(addressArray[i]);
				var postcode = postcodeArray[i];
				if(postcodeArray[i].length>6  && parseInt(postcodeArray[i])){
					postcode = postcodeArray[i].substring(0,6);
				}
				var searchString = "Europe, The Netherlands, " + (address ? address : postcode);
				var addressForOutput = addressArray[i].split(",")[1];
				if (!addressForOutput){
					addressForOutput = postcodeArray[i];
				}
				
				var displayMarker = function(postcode, address, point){
					var key = point.lat().toString() + point.lng().toString();
					address = address ? address + "," : "";
					
					if (!addedMarkers[key]){								
						var iconImg = makeGIcon(getMarkerIconPath(markerIcon));
    					var marker = new GMarker(point, iconImg);
						addedMarkersBounds.extend(point);
						
						addedMarkers[key] = {};
						addedMarkers[key].marker = marker;
						addedMarkers[key].markerText = getMarkerPopupTextIfClustered(date, address, postcode, type, sort, link);
						addClickHandler(marker, addedMarkers[key].markerText);
						
						addedMarkers[key].marker.html = addedMarkers[key].markerText; 
						
						if (!isMapRangeDefined){
							map.setZoom(map.getBoundsZoomLevel(addedMarkersBounds) - 1);
							map.setCenter(addedMarkersBounds.getCenter());
						}
					} else {						    
					    var marker = addedMarkers[key].marker;						    
						var iconImg = makeGIcon(getMarkerIconPath(markerIcon));    					  
    					//marker= new GMarker(marker.getLatLng(), iconImg);
							
    					
						addedMarkers[key].markerText += getMarkerPopupTextIfClustered(date, address, postcode, type, sort, link);
														
						GEvent.clearListeners(marker, "click"); 
						addClickHandler(marker, addedMarkers[key].markerText);								
						marker.html = addedMarkers[key].markerText;
					}
					refreshCluster();
				}
				
				var coords = trim(adressCoordsArray[i]);
				if (coords){
					coords = coords.split(",");
					displayMarker(postcode, address, new GLatLng(coords[1], coords[0]));
				} else {
					(function(postcode, address){
						getLatLngWrapper(geoCoder, searchString, function(point) {
							if (point) {
								displayMarker(postcode, address, point);
							}				
						});
					})(postcode, addressForOutput);
				}
			}
		}
	};
	
	var getMarkerPopupText = function(title, addressForOutput, postcode, type, sort, uri, lat, lon){
		var html = '<div class="markerPopup"><b>'+title+'</b>';
		if (addressForOutput || postcode){
			html += '<br/><br/>' + addressForOutput + postcode + '<br/>';
		} else if (lat && lon){
			html += '<br/><br/>' + lat + ', ' + lon + '<br/>';
		}
		html += type;						
		if(sort != ""){
			html += ', '+sort;
		} 
		html += '<br/><br/><a href="'+uri+'">Meer informatie</a>';
		html += "</div><br/>";
		return html;
	};
	
	this.showItemOnMap = function (postcode, address, title, uri, type, sort, markerIcon, addressCoords){
		
		if (!postcode && !address && (!addressCoords || addressCoords === ",")){
			return;
		}
		
		if (geoCoder) {
			if(postcode.length>6  && parseInt(postcode)){
				postcode = postcode.substring(0,6);
			}
			
			var searchString = "Europe, The Netherlands, ";
			if (postcode.length >= 4){
				searchString += postcode;
			}
			
			if (address){
				if ((/^(\d)+$/).test(address)){
					// it is number -> do not for search string
				} else {
					searchString += " " + address;
				}
			}
			
			var addressForOutput = address.split(",")[1] || "";			
			addressForOutput = addressForOutput ? addressForOutput + ", " : "";
			
			var displayMarker = function(postcode, address, point) {
				if (point) {
					if (!isAtLeastOneMarkerGeoCoded) {
						isAtLeastOneMarkerGeoCoded = true;
					}

					if (!isShowMap()) {
						//console.log("showMap");
						showMap();
					}

					var key = point.lat() + "_" + point.lng();
					var html = getMarkerPopupText(title, addressForOutput, postcode, type, sort, uri, point.lat(), point.lng());
					
					var marker = null;
					
					if (!addedMarkers[key]){
						var iconImg = makeGIcon(getMarkerIconPath(markerIcon));
						marker = new GMarker(point, iconImg);
						
						addedMarkersBounds.extend(point);
						
						addedMarkers[key] = {};
						addedMarkers[key].marker = marker;
						addedMarkers[key].markerText = html;
						
						map.addOverlay(marker);
						
						map.setZoom(map.getBoundsZoomLevel(addedMarkersBounds));
						map.setCenter(addedMarkersBounds.getCenter());
					} else {
						marker = addedMarkers[key]; 
						marker.markerText += html;
														
						GEvent.clearInstanceListeners(marker); 
					}
					
					GEvent.addListener(marker, "mouseover", function() {
						var html = getFormattedHTML(addedMarkers[key].markerText);
						marker.openInfoWindowHtml(html);
					});
					GEvent.addListener(addedMarkers[key].marker, "click", function() {
						var html = getFormattedHTML(addedMarkers[key].markerText);
						marker.openInfoWindowHtml(html);
					});
				}				
			}				
			
			if (addressCoords && addressCoords != ","){
				var coords = trim(addressCoords);
				coords = coords.split(",");

				displayMarker(postcode, address, new GLatLng(coords[1], coords[0]));
				console.log(addressCoords);
			} else {
				(function(postcode, address) {
					getLatLngWrapper(geoCoder, searchString, function(point) {
						if (point) {
							displayMarker(postcode, address, point);
						}
						if (!isAtLeastOneMarkerGeoCoded && !isHideMap()) {
							//console.log("hideMap");
							hideMap();
						}
					});
				})(postcode, addressForOutput);
			}
		}	
	};
	
	this.showCompany = function(location,str,house,city,country, showAlways){
		if(location.length = 0) {
			return;
		}
		
		var query = location;
		
		if (str!="" && house!="" && city!=""){
			query = str + " " + house + ", " + location + ", " + city;
		}
		
		query = query + ", The Netherlands, Europe";
		
		if (geoCoder) {
			getLatLngWrapper(geoCoder, query, function(point) {
				if (!point) {
					if (!showAlways){
						document.getElementById("map_canvas").style.display="none";
					}
				} else {
					map.setCenter(point, 13);
					var marker = new GMarker(point);
					map.addOverlay(marker);
					marker.openInfoWindowHtml(str + " " + house + ", " + city + ", " + country);
				}
			});
		}
	};

	/*
	 * This function is wrriten bacause there is an issue into Google API "getLatLng".
	 * The workaround is to make the delay between the calls of "getLatLng" function.
	 * The best delay time is 225 ms.
	 */
	var getLatLngWrapper = function(geoCoder, queryString, latLngCallback) {
		setTimeout(
			function() {
				geoCoder.getLatLng(queryString, latLngCallback);
			},
			latLngCallsCount * 225
		);

		//increment calls count
		latLngCallsCount++;
	};
}();
