var jsonContent;
var map = null;
var icon_red = null;
var icon_blue = null;
var icon_black = null;
var icon_yellow = null;
var zoomCursor = null;
var infoWindowPadding = null;
var markers = null;
var gMapMarkersReady = false;
var opInProgress = false;
var geoCoder = null;
var geoCodingResults = [];
var allMarkersArray = [];
var allMarkersHash = {};
var lastActiveMarker;

var streetViewContainer = null;
var streetViewCloseButton = null;
var streetViewChromeCloseButton = null;
var streetViewInstance = null;
var streetViewLocationCheckPending = false;


var baseZoomCursorPos = -170;
var initialZoomCursorPos = 90;
var minZoomLevel = 5;
var maxZoomLevel = 18;
var rulerContainmentHeight = 140;
var rulerContainementOriginY = 30;


var markerGroups = {
    hotels: [],
    locations: [],
    chambres_d_hotes: [],
    campings: [],
	hebergements: [],
    agenda: [],
    artisans: [],
    autres_loisirs: [],
    galeries_art: [],
    loisirs_nature: [],
    loisirs_nautiques: [],
    organismes_de_tourisme: [],
    patrimoine: [],
    produits_du_terroir: [],
    restaurants: [],
    sejours_visites: [],
    sites_naturels: [],
    aeroports: [],
    gares: []
};

var groupsState = {};


function gmap_init() {

    map = new GMap2(document.getElementById('map_canvas'));

    var center_lat = 43.2976116;
    var center_lng = 5.3810421;
    var zoom = 8;

    map.setMapType(G_NORMAL_MAP);
    map.setCenter(new GLatLng(center_lat, center_lng), zoom);
    zoomCursorPos = baseZoomCursorPos + initialZoomCursorPos;
    map.enableScrollWheelZoom();

    map.addControl(new GScaleControl(), new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(130, 20)));
    map.addControl(new UzikControls());
    map.addControl(new UzikMapTypeControls());
    map.addControl(new GOverviewMapControl());
    map.addControl(new UzikMarkersSelectorControl());
    map.addControl(new UzikSearchBarControl());

    infoWindowPadding = new GSize(10, 0);

    icon_red = new GIcon(G_DEFAULT_ICON);
    icon_red.image = cdtRegistry.baseUrl + 'images/map/icon_red.png';
    icon_red.iconSize = new GSize(23, 29);
    icon_red.iconAnchor = new GPoint(11, 29);
    icon_red.shadow = cdtRegistry.baseUrl + 'images/map/ombre.png';
    icon_red.shadowSize = new GSize(38, 31);


    icon_blue = new GIcon(G_DEFAULT_ICON);
    icon_blue.image = cdtRegistry.baseUrl + 'images/map/icon_blue.png';
    icon_blue.iconSize = icon_red.iconSize;
    icon_blue.iconAnchor = icon_red.iconAnchor;
    icon_blue.shadow = cdtRegistry.baseUrl + 'images/map/ombre.png';
    icon_blue.shadowSize = icon_red.shadowSize;

    icon_black = new GIcon(G_DEFAULT_ICON);
    icon_black.image = cdtRegistry.baseUrl + 'images/map/icon_black.png';
    icon_black.iconSize = icon_red.iconSize;
    icon_black.iconAnchor = icon_red.iconAnchor;
    icon_black.shadow = cdtRegistry.baseUrl + 'images/map/ombre.png';
    icon_black.shadowSize = icon_red.shadowSize;

    icon_yellow = new GIcon(G_DEFAULT_ICON);
    icon_yellow.image = cdtRegistry.baseUrl + 'images/map/icon_yellow.png';
    icon_yellow.iconSize = icon_red.iconSize;
    icon_yellow.iconAnchor = icon_red.iconAnchor;
    icon_yellow.shadow = cdtRegistry.baseUrl +' "images/map/ombre.png"';
    icon_yellow.shadowSize = icon_red.shadowSize;


    G_PHYSICAL_MAP.getMinimumResolution = function () {
        return minZoomLevel
    };
    G_NORMAL_MAP.getMinimumResolution = function () {
        return minZoomLevel
    };
    G_SATELLITE_MAP.getMinimumResolution = function () {
        return minZoomLevel
    };
    G_HYBRID_MAP.getMinimumResolution = function () {
        return minZoomLevel
    };
    G_PHYSICAL_MAP.getMaximumResolution = function () {
        return maxZoomLevel
    };
    G_NORMAL_MAP.getMaximumResolution = function () {
        return maxZoomLevel
    };
    G_SATELLITE_MAP.getMaximumResolution = function () {
        return maxZoomLevel
    };
    G_HYBRID_MAP.getMaximumResolution = function () {
        return maxZoomLevel
    };

    GEvent.addListener(map, 'zoomend', function(oldLevel, newLevel) {

        var scrollRatio = ( newLevel - (minZoomLevel-1) ) / ( maxZoomLevel - (minZoomLevel-1) );
        //var zoomCursorContainement = $(zoomCursor).draggable('option', 'containment');
        //var scrollZoneHeight = zoomCursorContainement[3]-zoomCursorContainement[1];
        scrollZoneHeight = rulerContainmentHeight;
        var newZoomCursorPos = baseZoomCursorPos + (scrollZoneHeight - Math.round( (scrollZoneHeight) * scrollRatio ) );//-50 - (8 * (newLevel - 1));
        //console.log('zoomend : newLevel='+newLevel+' ; zoomCursorContainement.minY='+zoomCursorContainement[1]+', zoomCursorContainement.maxY='+zoomCursorContainement[3]+' ; scrollRatio='+scrollRatio+', zoomCursorPos='+zoomCursorPos);
        $(zoomCursor).css('top', newZoomCursorPos + 'px');

        if( typeof(lastActiveMarker)!='undefined' )
            lastActiveMarker.onMouseOut();

    });

    markerPopup = document.createElement("div");
    /*markerPopup.style.background = "#FFFFFF";
    markerPopup.style.border = "1px solid #C0C0C0";
    markerPopup.style.position = "absolute";
    markerPopup.style.left = "80px";
    markerPopup.style.top = "5px";
    markerPopup.style.padding = "5px 25px 5px 25px";
    markerPopup.style.width = "220px";
    markerPopup.style.height = "410px";
    markerPopup.style.color = "#313131";*/
    markerPopup.id = "markerPopup";
    map.getContainer().appendChild(markerPopup);
    var $markerPopup = $(markerPopup);
    $markerPopup.hide();

    for( var i in markerGroups ) {
        groupsState[i] = true;
    }

    geoCoder = new GClientGeocoder();

    preloadGMapAssets();


	$(window).unload(function() {

		if( streetViewInstance!=null )
			streetViewInstance.remove();

		GUnload();
		
	} );
	
	$(".checkbox").each( function() {

        var $me, $myContainer;

        $me = $(this);
        $myContainer = $me.parent();

        $myContainer.css('cursor', 'pointer');

        $myContainer.click(function() {

            if ($me.attr('src').indexOf('empty')>-1 ) {
                showGroup($me.attr('id'));
            }
            else {
                maskGroup($me.attr('id'));
            }
            markers.resetViewport();

        } );
    });

    markers = new MarkerClusterer(map, [], {
        maxZoom: 15,
        gridSize: 80,
        styles: [{
            height: 44,
            width: 78,
            opt_anchor: [12, 45],
            url: cdtRegistry.baseUrl + 'images/map/clusterer.png'
        }]
        });
        
        
    if(jsonContent){
    	addJsonMarkers( jsonContent );
    	jsonContent = null;
    }
    

}


function preloadGMapAssets() {

    var i/*uint*/;
    var assetsToLoad/*Array*/;
    var currentImg/*Image*/;

    assetsToLoad = [
    'images/map/ombre.png',
    'images/map/icon_red.png',
    'images/map/icon_black.png',
    'images/map/icon_blue.png',
    'images/map/infoWindow_black_bg.png',
    'images/map/infoWindow_red_bg.png',
    'images/map/infoWindow_blue_bg.png'
    ];

    for(i=0; i<assetsToLoad.length;i++) {

        currentImg = new Image();
        currentImg.src = cdtRegistry.baseUrl + assetsToLoad[i];

    }

}


/*
 * Custom controls : déplacement
 */
function UzikControls() {
}

UzikControls.prototype = new GControl();

UzikControls.prototype.initialize = function(map) {

    var container = document.createElement("div");

    var pan = document.createElement("div");
    pan.style.background = "url("+cdtRegistry.baseUrl+"images/map/pan.png) no-repeat";
    pan.style.width = '58px';
    pan.style.height = '58px';
    $(pan).attr('class', 'transparentPNG');//pan.setAttribute('class', 'transparentPNG' );
    container.appendChild(pan);

    var panTop = document.createElement("div");
    panTop.style.width = '21px';
    panTop.style.height = '21px';
    panTop.style.position = 'relative';
    panTop.style.left = '17px';
    panTop.style.top = '-1px';
    panTop.style.cursor = 'pointer';
    pan.appendChild(panTop);
    GEvent.addDomListener(panTop, 'click', function() {
        map.panDirection(0, 1);
    });

    var panLeft = document.createElement("div");
    panLeft.style.width = '21px';
    panLeft.style.height = '21px';
    panLeft.style.position = 'relative';
    panLeft.style.left = '-1px';
    panLeft.style.top = '-5px';
    panLeft.style.cursor = 'pointer';
    pan.appendChild(panLeft);
    GEvent.addDomListener(panLeft, 'click', function() {
        map.panDirection(1, 0);
    });

    var panRight = document.createElement("div");
    panRight.style.width = '21px';
    panRight.style.height = '21px';
    panRight.style.position = 'relative';
    panRight.style.left = '35px';
    panRight.style.top = '-28px';
    panRight.style.cursor = 'pointer';
    pan.appendChild(panRight);
    GEvent.addDomListener(panRight, 'click', function() {
        map.panDirection(-1, 0);
    });

    var panBottom = document.createElement("div");
    panBottom.style.width = '21px';
    panBottom.style.height = '21px';
    panBottom.style.position = 'relative';
    panBottom.style.left = '17px';
    panBottom.style.top = '-33px';
    panBottom.style.cursor = 'pointer';
    pan.appendChild(panBottom);
    GEvent.addDomListener(panBottom, 'click', function() {
        map.panDirection(0, -1);
    });

    var streetViewCursor = document.createElement("div");
	var $streetViewCursor = $(streetViewCursor);
	$streetViewCursor.attr('id', 'streetViewCursor');
	$streetViewCursor.addClass('transparentPNG');
    container.appendChild(streetViewCursor);
	var invalidTargetIconPreloader = new Image();var foundIconPreloader = new Image();
	invalidTargetIconPreloader.src = cdtRegistry.baseUrl + 'images/map/streetview_invalidTarget.png';
	foundIconPreloader.src = cdtRegistry.baseUrl + 'images/map/streetview_found.png';

	var me = this;
    var svOverlay = null;
    $streetViewCursor.draggable({
        start: function() {
            svOverlay = new GStreetviewOverlay();
            map.addOverlay(svOverlay);
        },
		drag: function() {
			if( streetViewLocationCheckPending )
				return;
			var targetLocation = me.getStreetViewCursorLocation();
			me.checkStreetViewLocation( targetLocation );
		},
        stop: function() {

			var targetLocation = me.getStreetViewCursorLocation();

			var callbackFunction = function( aBoolean ) {
				//console.log('callbackFunction('+aBoolean+')');
				if( aBoolean==false )
					return;
				map.removeOverlay(svOverlay);
				delete svOverlay;
				me.displayStreetViewLocation( targetLocation );
			};

			me.checkStreetViewLocation( targetLocation, callbackFunction );

        }
    });

    var ruler = document.createElement("div");
    ruler.style.background = "0 0 url("+cdtRegistry.baseUrl+"images/map/zoom.png) no-repeat";
    ruler.style.width = '24px';
    ruler.style.height = '203px';
    ruler.style.marginLeft = '16px';
    ruler.style.position = 'relative';
    //ruler.style.border = 'solid yellow 1px';
    $(ruler).attr('class', 'ruler transparentPNG');//ruler.setAttribute('class', 'transparentPNG' );
    container.appendChild(ruler);

    var plus = document.createElement("div");
    plus.style.width = '21px';
    plus.style.height = '21px';
    plus.style.margin = '1px 0 0 1px';
    plus.style.cursor = 'pointer';
    //plus.style.border = 'solid lime 1px';
    ruler.appendChild(plus);
    GEvent.addDomListener(plus, 'click', function() {
        if( map.getZoom() < maxZoomLevel )
            map.zoomIn();
    //console.log('map.getZoom()='+map.getZoom());
    });

    var minus = document.createElement("div");
    minus.style.width = '21px';
    minus.style.height = '21px';
    minus.style.margin = '159px 0 0 1px';
    minus.style.cursor = 'pointer';
    //minus.style.border = 'solid lime 1px';
    ruler.appendChild(minus);
    GEvent.addDomListener(minus, 'click', function() {
        if( map.getZoom() > minZoomLevel )
            map.zoomOut();
    //console.log('map.getZoom()='+map.getZoom());
    });

    zoomCursor = document.createElement("div");
    zoomCursor.style.background = "url("+cdtRegistry.baseUrl+"images/map/zoom_curseur.png)";
    zoomCursor.style.width = '19px';
    zoomCursor.style.height = '12px';
    //zoomCursor.style.paddingTop = '21px';
    //zoomCursor.style.paddingBottom = '21px';
    zoomCursor.style.backgroundRepeat = 'no-repeat';
    //zoomCursor.style.backgroundPosition = 'center';
    //zoomCursor.style.border = 'solid red 1px';
    zoomCursor.style.margin = '0 0 0 3px';
    zoomCursor.style.cursor = 'move';
    zoomCursor.style.top = zoomCursorPos + 'px';
    $(zoomCursor).attr( 'class', 'zoomCursor' );
    $(zoomCursor).draggable({
        axis: 'y',
        //containment: [0, rulerOffset.top + 21, 0, rulerOffset.top + 21 + 140],//'parent',
        start: function() {
        },
        stop: function() {
            var myContainement = $(this).draggable('option', 'containment');
            var dragZoneHeight = myContainement[3] - myContainement[1];
            var scrollY = $(this).offset().top - myContainement[1];
            var scrollRatio = scrollY / dragZoneHeight;
            var targetScroll = Math.round( maxZoomLevel - ( (maxZoomLevel - (minZoomLevel-1) ) * scrollRatio ) );
            //console.log('dragZoneHeight='+dragZoneHeight+', scrollY='+scrollY+' => scrollRatio='+scrollRatio+', targetScroll='+targetScroll);
            map.setZoom( targetScroll );
        }
    });
    ruler.appendChild(zoomCursor);

    map.getContainer().appendChild(container);

    setTimeout('UzikControls.initRulerContainment();', 1000 );

    return container;
};


/**
 * @see http://techabhishek.bravehost.com/ShowPanorama.htm
 */
UzikControls.prototype.createStreetViewContainer = function() {

	var me;
	var top, left, width, height;
	var $mapContainer, mapContainerOffset;
	var $streetViewContainer, $streetViewCloseButton;

	me = this;

	streetViewContainer = document.createElement('div');
	$streetViewContainer = $(streetViewContainer);
	$mapContainer = $('#map_canvas');
	mapContainerOffset = $mapContainer.offset();
	top = mapContainerOffset.top;
	left = mapContainerOffset.left;
	width = $mapContainer.width();
	height = $mapContainer.height();
	$streetViewContainer.addClass('streetViewContainer');
	$streetViewContainer.css( {
		left: left,
		top: top,
		width:  width,
		height: height
	} );
	document.body.appendChild( streetViewContainer );

	streetViewCloseButton = document.createElement('div');
	$streetViewCloseButton = $(streetViewCloseButton);
	$streetViewCloseButton.addClass( 'streetViewCloseButton' );
	$streetViewCloseButton.attr( {alt: cdtRegistry.i18n.gMap.ReturnToMap, title: cdtRegistry.i18n.gMap.ReturnToMap} );
	$streetViewCloseButton.css( {
		left: (left + (width - 44)),
		top: (top+4)
	} );
	$streetViewCloseButton.click( function() {
		me.closeStreetView();
	} );
	document.body.appendChild( streetViewCloseButton );


	if( cdtRegistry.Chrome ) {

		// a bug in Webkit prevents the correct display or the "close" button over the StreetView flash container
		// --> we have to create another button
		streetViewChromeCloseButton = document.createElement('div');
		var $streetViewChromeCloseButton = $(streetViewChromeCloseButton);
		$streetViewChromeCloseButton.html('<a href="javascript:;" class="chromeStreetViewCloseButton">'+cdtRegistry.i18n.gMap.ReturnToMap+'</a>');
		var $darkblock = $('.darkblock');
		$darkblock.after( $streetViewChromeCloseButton );
		$streetViewChromeCloseButton.after('<div class="clear"></div>');
		$streetViewChromeCloseButton.click( function() {
			me.closeStreetView();
		} );
		
	}


};

UzikControls.prototype.checkStreetViewLocation = function( aLocation /*GLatLng*/, aCallbackFunction /*Function*/ ) {

	var streetViewClient = new GStreetviewClient();
	var $streetViewCursor = $('#streetViewCursor');

	streetViewLocationCheckPending = true;

	streetViewClient.getNearestPanoramaLatLng( aLocation, function( aFoundPoint ) {

		streetViewLocationCheckPending = false;

		//console.log('aFoundPoint='+aFoundPoint);

		if( aFoundPoint instanceof  GLatLng ) {
			$streetViewCursor.addClass('found');$streetViewCursor.removeClass('invalidTarget');
			if( aCallbackFunction instanceof Function )
				aCallbackFunction( true );
		} else {
			$streetViewCursor.addClass('invalidTarget');$streetViewCursor.removeClass('found');
			if( aCallbackFunction instanceof Function )
				aCallbackFunction( false );
		}

	} );


};

UzikControls.prototype.getStreetViewCursorLocation = function() /*GLatLng*/ {

	var $mapCanvas = $('#map_canvas');
	var $streetViewCursor = $('#streetViewCursor');

	var pixelLocationX = $streetViewCursor.offset().left - $mapCanvas.offset().left + ( $streetViewCursor.width()/2 ) ;
	var pixelLocationY = $streetViewCursor.offset().top - $mapCanvas.offset().top + $streetViewCursor.height() - 3 ;
	var cursorLocation = map.fromContainerPixelToLatLng(new GPoint( pixelLocationX, pixelLocationY) );

	return cursorLocation;

};

UzikControls.prototype.displayStreetViewLocation = function( aLocation /*GLatLng*/ ) {

	if( streetViewContainer==null )
		this.createStreetViewContainer();

	$(streetViewContainer).show();
	$(streetViewCloseButton).show();
	if( streetViewChromeCloseButton!=null )
		$(streetViewChromeCloseButton).fadeIn('fast');

	streetViewInstance = new GStreetviewPanorama( streetViewContainer, {
		latlng: aLocation
	});

};

UzikControls.prototype.closeStreetView = function() {

	streetViewInstance.remove();
	$(streetViewContainer).hide();
	//document.body.removeChild(streetViewContainer);
	$(streetViewCloseButton).hide();
	//document.body.removeChild(streetViewCloseButton);

	if( streetViewChromeCloseButton!=null )
		$(streetViewChromeCloseButton).hide();

};

UzikControls.prototype.getDefaultPosition = function() {
    return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(20, 20));
};


UzikControls.initRulerContainment = function () {

    var $mapContainer;
    var $ruler, $zoomCursor;
    var rulerOffset;
    var numZoomLevels;

    $mapContainer = $( map.getContainer() );
    $ruler = $mapContainer.find('.ruler');
    $zoomCursor = $mapContainer.find('.zoomCursor');

    numZoomLevels = maxZoomLevel - minZoomLevel ;

    //$mapContainer.css('position', 'static' );
    rulerOffset = $ruler.offset();
    //console.log(' UzikControls.initRulerContainment() : rulerOffset : top='+rulerOffset.top+', left='+rulerOffset.left);
    /*$zoomCursor.draggable('option', 'containment', [0, rulerOffset.top + rulerContainementOriginY, 0, rulerOffset.top + rulerContainementOriginY + rulerContainmentHeight] );
    $zoomCursor.draggable('option', 'grid', [ 0, Math.ceil(rulerContainmentHeight / numZoomLevels) ] );*/
    //$mapContainer.css('position', 'absolute' );

};

/*
 * Custom controls : map type
 */

function UzikMapTypeControls() {
}

UzikMapTypeControls.prototype = new GControl();

UzikMapTypeControls.prototype.initialize = function(map) {

    var container = document.createElement("div");

    var mapType = document.createElement("div");
    mapType.style.width = '117px';
    mapType.style.height = '20px';
    mapType.style.color = "#FFFFFF";
    mapType.style.cursor = 'pointer';
    mapType.style.fontFamily = 'Arial';
    mapType.style.fontSize = '11px';
    mapType.style.textAlign = 'center';
    container.appendChild(mapType);

    var mapTypePlan = document.createElement("div");
    mapTypePlan.style.background = "#313131";
    mapTypePlan.innerHTML = "Plan";
    mapTypePlan.style.width = '58px';
    mapTypePlan.style.height = '17px';
    mapTypePlan.style.paddingTop = '3px';
    mapType.appendChild(mapTypePlan);
    GEvent.addDomListener(mapTypePlan, 'click', function() {
        map.setMapType(G_NORMAL_MAP);
    });

    var mapTypePhysical = document.createElement("div");
    mapTypePhysical.style.background = "#313131";
    mapTypePhysical.innerHTML = "Relief";
    mapTypePhysical.style.width = '58px';
    mapTypePhysical.style.height = '17px';
    mapTypePhysical.style.paddingTop = '3px';
    mapTypePhysical.style.position = "relative";
    mapTypePhysical.style.top = "-20px";
    mapTypePhysical.style.left = "59px";
    mapType.appendChild(mapTypePhysical);
    GEvent.addDomListener(mapTypePhysical, 'click', function() {
        map.setMapType(G_PHYSICAL_MAP);
    });

    map.getContainer().appendChild(container);
    return container;
};

/*
 * Custom controls : markers selector
 */

function UzikMarkersSelectorControl() {
}

UzikMarkersSelectorControl.prototype = new GControl();

UzikMarkersSelectorControl.prototype.initialize = function(map) {

    if( cdtRegistry.IE6 || cdtRegistry.IE7 )
        return document.createElement('div');//IE6 & IE7 Javascript engines are too slow for this operation... :(

    var container = document.createElement("div");
    /*$(container).draggable({
        cancel: '#markerSelector',
        containment: '#map_canvas'
    });*/

    var markerSelectorBack = document.createElement("div");
    markerSelectorBack.style.background = "url("+cdtRegistry.baseUrl+"images/map/fond.png)";
    markerSelectorBack.style.width = "153px";
    markerSelectorBack.style.padding = "5px";
    markerSelectorBack.style.border = "1px solid #D0D0D0";
    markerSelectorBack.innerHTML = cdtRegistry.i18n.gMap.DisplayOnMap;
    markerSelectorBack.style.cursor = "move";
    markerSelectorBack.style.color = "#313131";
    markerSelectorBack.style.fontFamily = "Arial";
    markerSelectorBack.style.fontSize = "12px";
    container.appendChild(markerSelectorBack);

    var markerSelector = document.createElement("div");
    markerSelector.id = "markerSelector";
    markerSelector.style.background = "#FFFFFF";
    markerSelector.style.width = "135px";
    markerSelector.style.cursor = "default";
    markerSelector.style.marginTop = "3px";
    markerSelector.style.border = "1px solid #D0D0D0";
    markerSelector.style.textAlign = "left";
    markerSelector.style.fontSize = "11px";
    markerSelector.style.padding = "8px";
    markerSelectorBack.appendChild(markerSelector);
    
    var markers = new Array(
    	new Array(
    		{id:"hotels", color:"blue"},
    		{id:"locations", color:"blue"},
    		{id:"chambres_d_hotes", color:"blue"},
    		{id:"campings", color:"blue"},
    		{id:"hebergements", color:"blue"}
    	),
    	new Array(
    		{id:"agenda", color:"black"},
    		{id:"artisans", color:"black"},
    		{id:"loisirs_nature", color:"black"},
    		{id:"loisirs_nautiques", color:"black"},
    		{id:"organismes_de_tourisme", color:"black"},
    		{id:"patrimoine", color:"black"},
    		{id:"produits_du_terroir", color:"black"},
    		{id:"sejours_visites", color:"black"},
    		{id:"sites_naturels", color:"black"},
    		{id:"restaurants", color:"black"},
    		{id:"autres_loisirs", color:"black"}
    	),
    	new Array(
    		{id:"aeroports", color:"red"},
    		{id:"gares", color:"red"}
    	)	
    );
    
    // On stocke les catégories des annonces dans un objet...
    var categories = {};
    $.each(jsonContent, function(index, annonce){
    	categories[annonce[2]] = true;
    });
    
    $.each(markers, function(index, group){
    
    	var list = $('<ul/>');
    
    	$.each(group, function(index, marker){
    	
    		// ... puis on affiche la checkbox uniquement si la catégorie contient des annonces
    		if(categories[marker.id])
    			list.append('<li><img class="checkbox" name="checkbox_'+marker.color+'" src="'+cdtRegistry.baseUrl+'images/map/checkbox_'+marker.color+'.png" id="'+marker.id+'"/> '+cdtRegistry.i18n.gMap.categories[marker.id]+'</li>');
    	
    	});
    	
    	if(list.children().size() > 0) $(markerSelector).append(list);
    
    });

    map.getContainer().appendChild(container);
    return container;
};

/*
 * Custom controls : search bar
 */

function UzikSearchBarControl() {
}

UzikSearchBarControl.prototype = new GControl();

UzikSearchBarControl.prototype.initialize = function(map) {

    var container = document.createElement("div");

    var searchBarResult = document.createElement('div');
	var $searchBarResult = $(searchBarResult);
	$searchBarResult.css({
		width: '270px',
		height: '36px',
		padding: 4,
		display: 'none',
		color: '#3C3C3C',
		background: "#F2F2F2",
		border: '1px solid #BCBCBC'
	});
	$searchBarResult.attr( 'id', 'searchBarResult');
    container.appendChild(searchBarResult);

    var searchBarInput = document.createElement("input");
	var $searchBarInput = $(searchBarInput);
	searchBarInput.type = "text";
	$searchBarInput.css( {
		color: '#3C3C3C',
		backgroundColor: '#F2F2F2',
		width: '200px',
		fontSize :  '11px',
		height :  '18px',
		paddingLeft :  '5px',
		border :  '1px solid #BCBCBC',
		borderRight :  "0"
	} );
	$searchBarInput.addClass('googleMapSearchBarInput');
	var searchBarInputDefautValue = cdtRegistry.i18n.gMap.FindAddress;
    $searchBarInput.val( searchBarInputDefautValue );
	$searchBarInput.focus( function() {
		if( $searchBarInput.val()==searchBarInputDefautValue )
			$searchBarInput.val( '' );
    } );
    $searchBarInput.blur( function() {
		if( $searchBarInput.val()=='' )
            $searchBarInput.val( searchBarInputDefautValue );
    } );
        
    container.appendChild(searchBarInput);

    var searchBarButton = document.createElement("input");
	var $searchBarButton = $(searchBarButton);
    searchBarButton.type = "button";
    $(searchBarButton).css( {
		color: '#FFFFFF',
		backgroundColor: '#00968F',
		fontSize: '11px',
		width: '70px',
		height: '20px',
		border: '1px solid #BCBCBC',
		cursor: 'pointer'
	} );
	$searchBarButton.addClass('googleMapSearchBarButton');
    searchBarButton.value =  cdtRegistry.i18n.gMap.Search;


	var me = this;
    $searchBarButton.click(  function() {
		me.launchSearch();
	} );
    $searchBarInput.keypress(  function( aEvent ) {
		if( aEvent.keyCode==13 /*ENTER*/ )
			me.launchSearch();
	} );
        
    container.appendChild(searchBarButton);
        
    map.getContainer().appendChild(container);
    return container;
};


var searchInProgress  = false;
UzikSearchBarControl.prototype.launchSearch = function() {

	var $searchBarInput, $searchBarButton;

	if( searchInProgress )
		return;

	//console.log('launchSearch()');

	$searchBarInput = $('.googleMapSearchBarInput');
	$searchBarButton = $('.googleMapSearchBarButton');

	clearResults();
    var targetLocationStr = $searchBarInput.val();

	$searchBarInput.attr('disabled', 'disabled');
	$searchBarButton.attr('disabled', 'disabled');

	//console.log('targetLocationStr='+targetLocationStr);

	var resultsFound = false;

	searchInProgress = true;

	geoCoder.getLocations(
		targetLocationStr,
		function(response) {
		
			if ( typeof(response)=='object' && response.Placemark) {
			
				for (var i=0;i<response.Placemark.length;i++)
				{
					var currentData = response.Placemark[ i ];
					//console.log('currentData='+currentData);

					if (currentData.AddressDetails.Country == null)
						continue;

					var inFrance = (currentData.AddressDetails.Country.CountryNameCode == 'FR');
					var inBdR = (currentData.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.SubAdministrativeAreaName == 'Bouches-du-Rhône');

					//console.log('currentData='+currentData+' , inFrance='+inFrance+', inBdR='+inBdR);
					if (!inFrance || !inBdR)
						continue;

					addSearchResult(currentData);

					resultsFound = true;
					
				}//for

			}//if response

			if( resultsFound ) {

				centerOnSearchResult(geoCodingResults[0].data, 0, geoCodingResults.length);
				$( document.getElementById('searchBarResult') ).show();

			} else {
			
				//$.jGrowl(  cdtRegistry.i18n.gMap.NoResult.replace('%s', targetLocationStr) );

			}

			searchInProgress = false;
			$searchBarInput.removeAttr('disabled');
			$searchBarButton.removeAttr('disabled');

		}//function( response )

	);//geoCoder.getLocations()

};

function addSearchResult(data) {
    var coordinates = data.Point.coordinates;
    var point = new GLatLng(coordinates[1], coordinates[0]);
    var searchMarker = new GMarker(point, {
        icon: icon_yellow
    });
    map.addOverlay(searchMarker);

    GEvent.addDomListener(searchMarker, 'mouseover', function() {
        searchMarker.openExtInfoWindow(
            map,
            "yellow_infoWindow",
            data.address
            );
    });

    GEvent.addDomListener(searchMarker, 'mouseout', function() {
        searchMarker.closeExtInfoWindow(map);
    });

    geoCodingResults.push({
        marker: searchMarker,
        data: data
    });
}

function clearResults() {

    while(geoCodingResults.length > 0) {
        var result = geoCodingResults.pop();
        map.removeOverlay(result.marker);
    }

    var $searchBarResult = $('#searchBarResult');
    $searchBarResult.empty();
    $searchBarResult.hide();
    
}

function centerOnSearchResult(data, id, nb) {
    map.setCenter(new GLatLng(data.Point.coordinates[1], data.Point.coordinates[0]), 13);

    var searchBarResult = document.getElementById('searchBarResult');
	var $searchBarResult = $(searchBarResult);

	var searchBarResultContent = data.address;
    searchBarResultContent += '<div style="color: #313131; font-size: 9px; padding-top: 5px; text-align: right;">'
    + '<a href="javascript:;" id="cleanSearch">'+cdtRegistry.i18n.gMap.ClearSearch+'</a> - '
    + '<a href="javascript:;" class="browseSearchResult" id="' + Math.max(0, parseInt(id) - 1) + '">&lt;</a> '
    + (parseInt(id) + 1) + "/" + nb
    + ' <a href="javascript:;" class="browseSearchResult" id="' + Math.min(parseInt(id) + 1, parseInt(nb) - 1) + '">&gt;</a>'
    + '</div>';

    $searchBarResult.html( searchBarResultContent );

    $("a#cleanSearch").click(function() {
        clearResults();
    });

    $(".browseSearchResult").click(function() {
        var id = $(this).attr('id');

        centerOnSearchResult( geoCodingResults[id].data, id, geoCodingResults.length );
    });
}

UzikControls.prototype.getDefaultPosition = function() {
    return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(20, 20));
};

UzikMapTypeControls.prototype.getDefaultPosition = function() {
    return new GControlPosition(G_ANCHOR_TOP_RIGHT);
};

UzikMarkersSelectorControl.prototype.getDefaultPosition = function() {
    return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(10, 30));
};

UzikSearchBarControl.prototype.getDefaultPosition = function() {
    return new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(80, 7));
}

function addMarker(position, icon, group, cat, name, annonceShortId ) {

    var hasLinkedAnnonce;

    //console.log('addMarker('+position+', '+icon+', '+group+', '+cat+', '+name+', '+annonceShortId+')');

    var marker = new GMarker(position, {
        icon: icon
    });

    hasLinkedAnnonce = ( typeof(annonceShortId)!='undefined' && annonceShortId!=null && ! isNaN(annonceShortId) ) ? true : false ;

    if( hasLinkedAnnonce )
        marker.__annonceShortId = annonceShortId;

    var infoWindow_class = "";

    switch (icon) {
        case icon_black:
            infoWindow_class = "black_infoWindow";
            break;

        case icon_red:
            infoWindow_class = "red_infoWindow";
            break;

        case icon_blue:
            infoWindow_class = "blue_infoWindow";
            break;
    }

    // Let's create 2 functions to handle events on markers
    // This way, we can also trigger it "manually"...
    marker.onMouseOver = function() {
        this.openExtInfoWindow(
            map,
            infoWindow_class,
            cat + " : " + name
            );

        lastActiveMarker = this;

    };
    marker.onMouseOut = function() {
        this.closeExtInfoWindow(map);
    };

    marker.onClick = function() {

        var zoomLevel;

        zoomLevel = (cdtRegistry.IE7) ? 13 : 16 ;//JS loop error if too much zoom on IE7 :(

        lastActiveMarker = this;

        marker.onMouseOut();
        map.setCenter(position, zoomLevel);

        if( ! hasLinkedAnnonce )
            return;//for airports and stations, we just zoom...

        var targetUrl, annonceId;
        var $markerPopup, markerPopupIsVisible;

        targetUrl = cdtRegistry.localeUrl + 'guide-de-voyage/ajax-googlemap-annonce';
        annonceId = this.__annonceShortId;
        $markerPopup = $(markerPopup);

        markerPopupIsVisible = ($markerPopup.css('display')=='none') ? false : true ;

        $.ajax({
            async: false,
            url: targetUrl,
            data: 'annonceId=' + annonceId,
            type: 'GET',
            success: function(content) {
                //console.log('ajax content : '+content);
                $markerPopup.html(content);
                map.setCenter(position, 16);
            },
            error: function( aXMLHttpRequest, aTextStatus, aErrorThrown) {
                //$.jGrowl('_onAjaxError() : ' + aTextStatus);
            }
        } );

        /*$("#markerPopup a:last").css('color', '#FF0000');
        $("#markerPopup h1").css('font-size', '18px').css('line-height', '20px');

        var closeButtonCSS = {
            'background':			'0 0 no-repeat url('+cdtRegistry.baseUrl+'images/byController/guideDeVoyage/cross2.gif)',
            'display':				'block',
            'float':				'right',
            'width' :				'18px',
            'height' :				'18px',
            'margin-right' :                        '-18px',
            'margin-top':                           '5px'
        };
        $("#markerPopup .closeButton").css( closeButtonCSS );
        $("#markerPopup .closeButton span").hide();*/

        if( ! markerPopupIsVisible )
            $markerPopup.show('fast');

    };


    // We link these functions to mouse events
    GEvent.addDomListener(marker, 'mouseover',	marker.onMouseOver );
    GEvent.addDomListener(marker, 'mouseout',	marker.onMouseOut );
    GEvent.addDomListener(marker, 'click',		marker.onClick );

	if( ! cdtRegistry.IE6 ) {

		markerGroups[group].push(marker);
		allMarkersArray.push( marker );


	} else {

		// IE6 : direct addition
		map.addOverlay( marker );

	}

	if( typeof(annonceShortId)!='undefined' )
		allMarkersHash[ annonceShortId ] = marker;

    return marker;
}


function addJsonMarkers( aJsonContent ) {

    var i, currentPoint;
    var icon, annonceShortId;

    jsonParsingStartTime = (new Date()).getTime();

    var pointsArray = aJsonContent;
	
    for ( i=0;i<pointsArray.length;i++ ) {

        currentPoint = pointsArray[i];

        icon = icon_black;
        if ((currentPoint[2] == 'hotels') || (currentPoint[2] == 'chambres_d_hotes') || (currentPoint[2] == 'locations') || (currentPoint[2] == 'campings') || (currentPoint[2] == 'hebergements') )
            icon = icon_blue;
        if ((currentPoint[2] == 'aeroports') || (currentPoint[2] == 'gares'))
            icon = icon_red;
		
        annonceShortId = (currentPoint.length>5) ? currentPoint[5] : null;
        addMarker(new GLatLng(currentPoint[0], currentPoint[1]), icon, currentPoint[2], currentPoint[3], currentPoint[4], annonceShortId );

		
    }

    //console.log('JSON parsing finished       ; time=' + Math.round( ( (new Date()).getTime() - jsonParsingStartTime )/1000 ) );
	
    for ( i in markerGroups )
        markers.addMarkers(markerGroups[i]);

    maskGroup('aeroports');
    maskGroup('gares');

    markers.resetViewport();

    //console.log('gMapMarkersReady = true	; time=' + Math.round( ( (new Date()).getTime() - jsonParsingStartTime )/1000 ) );
    gMapMarkersReady = true;


}


function maskGroupsButOne(groupName) {
    var startTime;
    var currentGroupName;

	groupName = groupName.replace("-","_");
    //console.log('maskGroupsButOne('+groupName+')');

    startTime = new Date();

    if( cdtRegistry.IE6 || cdtRegistry.IE7 )
        return;//IE6 & IE7 Javascript engines too slow for this operation... :(

    if( cdtRegistry.IE ) {

        var t = 100;
        for ( currentGroupName in markerGroups) {
            setTimeout('maskGroup("'+currentGroupName+'");', t );
            t += 300;
        }
        setTimeout('showGroup("'+groupName+'");', t );

    } else {

        for ( currentGroupName in markerGroups)
            maskGroup(currentGroupName);

        showGroup(groupName);

        markers.resetViewport();


    }
	
}

function maskGroupsButArray(groups) {

    var startTime;
    var currentGroupName;

    startTime = new Date();

    if( cdtRegistry.IE6 || cdtRegistry.IE7 )
        return;//IE6 & IE7 Javascript engines too slow for this operation... :(

    if( cdtRegistry.IE ) {

        var t = 100;
        for ( currentGroupName in markerGroups) {
            setTimeout('maskGroup("'+currentGroupName+'");', t );
            t += 300;
        }
	
		for (groupName in groups) {
        	setTimeout('showGroup("'+groupName+'");', t );
		}
		
    } else {

        for (currentGroupName in markerGroups)
            maskGroup(currentGroupName);
		
		for (groupName in groups) {
        	showGroup(groups[groupName]);
		}
		
        markers.resetViewport();


    }
	
}


function centerOn(latitude, longitude, annonceShortId, annonceName) {

	toggleFlashMap(true);

    var $mapBlock;
    var targetMarker;
    
    $.scrollTo($('#map'));

    if( typeof(annonceShortId)!='undefined' ) {

		if( ! cdtRegistry.IE6 ) {

			// all but IE6 : we look for the marker and show  it

			var startTime = new Date();
			//console.log('let\'s look for the '+annonceShortId+' in our '+allMarkersArray.length+' markers...');

			if( typeof(allMarkersHash[ annonceShortId ])!='undefined' )
				targetMarker = allMarkersHash[ annonceShortId ];

			//console.log('end loop : time=' + Math.round( ( (new Date()).getTime() - startTime )/1000 ));

		} else {

			// IE6 : we create the marker on the fly

			if( typeof(allMarkersHash[ annonceShortId ])=='undefined' ) {

				annonceName = Base64.decode( annonceName );
				targetMarker = addMarker(  new GLatLng( latitude, longitude), icon_black, '', '', annonceName, annonceShortId );

			} else {

				targetMarker = allMarkersHash[ annonceShortId ];

			}

		}

		targetMarker.onClick();
		targetMarker.onMouseOver();

    }

}

function maskGroup(groupName) {

	groupName = groupName.replace("-","_");

    if( groupsState[groupName]==false )
        return;//already hidden

    if( opInProgress )
        return;

    opInProgress = true;

    $(".checkbox[id='" + groupName + "']").attr('src', cdtRegistry.baseUrl + 'images/map/checkbox_empty.png');

    var group = markerGroups[groupName];

    if (group.length == 0) {
        opInProgress = false;
        return;
    }
        
    for (var i in group) {
        var marker = group[i];
        try {
            markers.removeMarker(marker);
        } catch( e ) {
            //console.log('The marker was not an Cluster : we remove it as a simple GMaker');
            map.removeOverlay( marker );
        }
    }

    groupsState[groupName] = false;

    opInProgress = false;

}

function showGroup(groupName) {
	
	groupName = groupName.replace("-","_");
	
    if( groupsState[groupName]==true )
        return;//already displayed

    if( opInProgress )
        return;

    opInProgress = true;

    var group = markerGroups[groupName];
    var box = $(".checkbox[id='" + groupName + "']");

    box.attr('src', cdtRegistry.baseUrl + 'images/map/' + box.attr('name') + '.png');
    markers.addMarkers(group);

    groupsState[groupName] = true;

    opInProgress = false;

}

function gmap_loadMarkers(url) {

		$.ajax({
			async: false,
			url: url,
			type: 'GET',
			dataType: 'json',
			success: function( aJSONContent ) {
				jsonContent = aJSONContent;
			}
		});

}
