var mmGeo = {

    // global vars
    mapList      : {},      // contains list of map which geometries are currently overlayed
    overlayed    : {},      // geometries that are currently on map
    polylines    : {},       // contains the overlayed polylines ( duplicated polylines are not manage at this day ),
    marker_prefix: 'marker_',
    map_prefix   : 'map_',
    temp_overlay : null,
    lastHighlighted : null,
    lastShown : null,
    viewport: {}, 
    extendedViewport: null,
    autoMode: false,
    
    // hack to force ClusterMarker.fitMapToMarkers() call when calling reloading geometries.
    fitMapOnNextUpdate: false,
    

    isOverlayed  : function(marId){
        var id = this.getMarId(marId);
        return typeof(this.overlayed[id]) != "undefined" ? true : false;
    },

    /**
    * add a map to the mapList object
    */

    addMapList : function(mapId){
        if(this.mapList['map_'+mapId] == "undefined") this.mapList['map_'+mapId] = [];
    },


    /**
    * add a marker array as property of the duplicated object
    */

    addDuplicated : function(marId){      	  
        if(typeof this.duplicated[marId] == "undefined") this.duplicated[marId] = [];
    },

    /**
    * add a geometry to a map of mapList object
    * @param object a geometry
    */

    pushToMapList: function(mapId, geometry){

			 var mapId = this.getMapId(mapId);
			 
       if(!this.mapList[mapId]){this.mapList[mapId] = [];}
       
       //check fo an anomym corresponding to this marker ( we are pushing a marker that was duplicated )
       for(var i=0; i< this.mapList[mapId].length;i++){
       	var mapItem = this.mapList[mapId][i];
       	if(geometry.marId === mapItem.marId && mapItem.hasOwnProperty('isDuplicated')){
       		this.mapList[mapId].splice(i, 1);
       		break;
       	}
       }
       mmGeo.mapList[mapId].push(geometry);
    },


    /**
    * add a geometry in the duplicated object
    * @param string mapId  ( "map_x")
    * @param object anonym object containing geomatry data
    */

    pushToDuplicated: function(marId, anonym){      
        // on ne stocke pas l'element sous forme de marqueur mais sous forme d'objet anonyme
        var id = this.getMarId(marId);
        this.addDuplicated(id);
        this.duplicated[id].push(anonym);  //  l'id du marqueur ne pourrait il pas suffire ?
    },
    
    
    pushToOverlayed:function(overlay){
    	var marId = this.getMarId(overlay.marId);
      this.overlayed[marId] = overlay;	
      
    },


    /*
    * remove a marker from the overlayed object
    */

    removeOverlayed  : function(marId){
        var id = this.getMarId(marId);
        delete this.overlayed[id];
    },

    /*
    * remove polyline from map and from the polylines object
    */

    removePolyline : function(mapId, marId){
         if(this.polylines[mapId] && this.polylines[mapId][marId]){
              map.removeOverlay(this.polylines[mapId][marId][0]);
              delete this.polylines[mapId][marId];
        }
    },
    
    addPolyline: function(mapId, marId, polyline){          
        if(!this.polylines[mapId]) this.polylines[mapId] = [];
        this.polylines[mapId][marId] = polyline;
        map.addOverlay(this.polylines[mapId][marId]);
    },
    
    removeMapList:function(mapId){
    	var id = this.getMapId(mapId);
    	delete this.mapList[id];
    },
    
   
    loadGeometries:function(maps){
      var temp = [];
      var self = this;
    	 $.each(maps, function(index,markers){
    	 	 $.each(markers, function(i,m){  	 	 	 
    	 	 	 var g = self.addGeometry(m);
    	 	 	 if(typeof g != 'undefined'){    	 	 	 
    	 	 	   temp.push(g);
    	 	 	 }
    	 	 });
    	 });
       mmCluster = new ClusterMarker(map, { markers:temp, intersectPadding:0} );
       mmCluster.refresh(true);
       temp = null;    

    },
    
    addGeometries:function(maps){
      var temp = [];
      var self = this;
	    $.each(maps, function(index,markers){
	      $.each(markers, function(i,m){
	     	 var geometry  = self.addGeometry(m);
	        if(typeof geometry != 'undefined')temp.push(geometry);
	      });
	    });

      this.quickrefreshcluster();

    }, 
    
      
    addGeometry: function(g){
    		 //create overlay
    		 var overlay = this.createMarker( new GLatLng( g.lat, g.lon ), g.marId, g.panId, g.mapId, g.ico, true ) ;

    	   this.pushToMapList(g.mapId, overlay); 
         this.pushToOverlayed(overlay);
         
         return overlay;  
    	
    },
    
    removeGeometries:function(mapId, refresh){
    	var id = this.getMapId(mapId);

    	for(var index in this.mapList[id]){
    		var marker = this.mapList[id][index];			
				this.removeOverlayed(marker.marId);
    	}	
    					 
    	this.removeMapList(mapId);
    	if(refresh) this.quickrefreshcluster();
    	
    },
   
    addTempMarker:function(g){
    	mmGeo.removeTempMarker();
      mmGeo.temp_overlay = mmGeo.createMarker( new GLatLng(g.lat, g.lon), g.marId, g.panId, g.mapId, g.ico);      
      map.addOverlay(mmGeo.temp_overlay);          
    },
 
    removeTempMarker:function(){
    	if(mmGeo.temp_overlay){
    		map.removeOverlay(mmGeo.temp_overlay);
    		mmGeo.temp_overlay = null;
    	}
    },
        
    quickrefreshcluster: function() { 	

		  mmCluster.removeMarkers();
		  mmGeo.overlayed = {};
	  
		  for(m in mmGeo.mapList){
		  	for(marker in mmGeo.mapList[m]){
		  		mmGeo.pushToOverlayed(mmGeo.mapList[m][marker]);
		  	}
		  }		  
		  
		  mmCluster.addMarkers(mmGeo.overlayed);
		  
		  if(mmGeo.fitMapOnNextUpdate == true) {
		    mmCluster.fitMapToMarkers();
		    // must be rearmed for next call
		    mmGeo.fitMapOnNextUpdate == false;
		  }
		  else {
		    mmCluster.refresh(true);
		  }
	},
	
	createMarker: function(markerLocation, markerId, panId, mapId, markerIcon) {
	  
	  var marker = new mmOverlay(markerLocation, {marId: markerId, panId: panId, mapId: mapId, icon:markerIcon} );
	  
	  GEvent.addListener(marker, 'click', function() {
	  	
	  	mmGeo.lastShownId = markerId; 
	  	mmGeo.removeHighligth();
	    marker.highlight();
	    center = map.getCenter();
	    
	    if(!(center.lat() == markerLocation.lat()) || !(center.lng() == markerLocation.lng()))
	    {
        map.panTo(marker.getPoint());
	    }
	    
	    showMarker(markerId);
	    
	  });
	  
	  return marker;
  },
  
	 getMarId:function(marId){
      return this.marker_prefix + marId;
	 },
   
   getMapId:function(mapId){
      return this.map_prefix + mapId;
   },
     
  
	/**
	 * setCurrentViewport
	 * return viewport coords on map 'moveend' event
	 */	 
	setCurrentViewport:function(){
		mmGeo.viewport = map.getBounds();
		var sw = mmGeo.viewport.getSouthWest();
		var ne = mmGeo.viewport.getNorthEast();
		var zoom = map.getZoom();
		var oldZoom = vp.z;	  
			  
		minlat = sw.lat();
		maxlat = ne.lat();
		minlon = sw.lng();
		maxlon = ne.lng();		
			      
		var extswlat = minlat - 0.05*(maxlat - minlat);
		var extswlng = minlon - 0.05*(maxlon - minlon);
	  var extnelat = maxlat + 0.05*(maxlat - minlat);
	  var extnelng = maxlon + 0.05*(maxlon - minlon);
	    
	  vp.minlat = extswlat;
	  vp.maxlat = extnelat;
	  vp.minlon = extswlng;
	  vp.maxlon = extnelng;      
	  vp.z = zoom;
			
		if(!mmGeo.extendedViewport){     
			mmGeo.extendedViewport = new GLatLngBounds(new GLatLng(extswlat, extswlng), new GLatLng(extnelat, extnelng));
			// no reload in create/auto mode
			if (!$panCrea.is(':visible') && !mmGeo.autoMode){
			  $('#pub-reload', $panPub).trigger('click');
			}
		}
		else{
		  // for higher zoom, extended viewport = normal viewport
		  if(map.getZoom() < 4){
		    mmGeo.extendedViewport = mmGeo.viewport;
		  }
		  // if zoom changed or moving map goes out of extended viewport
		  else if(zoom != oldZoom || !mmGeo.extendedViewport.containsBounds(mmGeo.viewport)){
				mmGeo.extendedViewport = new GLatLngBounds(new GLatLng(extswlat, extswlng), new GLatLng(extnelat, extnelng));
		  	// no reload in create/auto mode
		  	if (!$panCrea.is(':visible') && !mmGeo.autoMode){
		  		$('#pub-reload', $panPub).trigger('click');
		  	}
		  }
		}
		
	},	      

/**
 * desactivate consultation
 * 
 */
  
  desactivateConsultation:function(hidePanMar){  	
  	if(hidePanMar){
    	$('.foot-close', $panMar).trigger('click');
  	}
  	
  	//desactivate clusterMarkers click
  	$.each(mmCluster._clusterMarkers, function(c,v){
      GEvent.clearListeners(v,'click');
    });
    
    //desactivate markers click
    $.each(mmGeo.overlayed, function(c,v){
      GEvent.clearListeners(v,'click');
    });   
  },

/**
 * activate consultation
 */  
   
  activateConsultation:function(){

    $.each(mmGeo.overlayed, function(c,v){      
      GEvent.addListener(v, 'click', function() {            
        map.panTo(v.getLatLng());       
        showMarker(v.markerId);         
      }); 
    });
        
    mmGeo.quickrefreshcluster();
  },
  
  removeHighligth: function(){
  	if(mmGeo.lastHighlighted) mmGeo.lastHighlighted.unHighlight();
  },
  
 /**
  * countp
  * simulate object.length
  * @param object
  * @return int number of object properties
  */
 	
  countp: function(object){
  	var count = 0;
  	for(var i in object){
  		count++;
  	}
  	return count;
  }

};