var map;
var address_markers;
var you_are_here_icon = "youarehere_map.gif";
var max_cluster_popup_descriptions = 2 ;
var settings;
var zoombox_tool;
var legend_user_action_done = false;

(function ($) {
	$.fn.gis = function(options) {
		var $this = $(this);

		// hardcoded value - templates have to follow the convention
		var $mapContainer = $("#mapContainer") ;
		var $mapContainerContent = $("#mapContainerContent");

		// no container found for map - don't show map, skip init
		if (!$mapContainer.length) return ;

		$mapContainer.append($mapContainerContent);
		$mapContainerContent.css({visibility: 'visible'});

		if (!window.OpenLayers) {
			jQuery.ajax({ url: media_url + "js/gis/OpenLayers.js", dataType: "script", success: function () { $this.gis(options) } , cache: true});
			return ;
		} else {
			OpenLayers.ImgPath = media_url + "js/gis/img/";
		}
		settings = $.extend(
		{
			max_zoom_level: options.zoom_levels ? 0 : 3,
			zoom_levels: [0,1,2,3,4,5,6,7,8,9],
			zoom: 0,
			lon: 150000.0,
			lat: 169800.0,
			oninit: null,
			zipoints: true,
			location_zoom: 4,
			multimodal: false
		}, options);

		// extend with URL parameters
		settings = $.extend(settings, $.getUrlParams());
		settings.zoom = $.inArray(settings.zoom, settings.zoom_levels);

		var center = new OpenLayers.LonLat(settings.lon, settings.lat);
	
		var bounds = new OpenLayers.Bounds(125755.369856309,157893.305693269,175084.491014552,185238.0478827535);
		var tileSize = new OpenLayers.Size(512,512);
		var mapResolutions = [46.3021759376852,26.4583862501058,13.2291931250529,5.29167725002117,2.64583862501058,1.32291931250529,0.529167725002117,0.264583862501058] ;

		var resolutions = [];

		var map_options = {
				projection: "EPSG:31370",
				units: "m",
				tileSize: tileSize,
				maxExtent: bounds,
				restrictedExtent: bounds,
				location_zoom: settings.location_zoom,
				resolutions: [],
				setZoomLevels: function (zoom_levels) {
					this.resolutions.length = 0;
					for (var i=0;i<zoom_levels.length-settings.max_zoom_level;++i) {
						this.resolutions.push(mapResolutions[zoom_levels[i]]);
					}
				},
				controls: []
		};
		map_options.setZoomLevels(settings.zoom_levels);
		var map_id = $this[0].id;
		map = new OpenLayers.Map(map_id, map_options);
		map.original_settings = settings;

		var map_url = '/tilecache/';
		var layer_name = "urbisFR3";
		if (lang == "nl") layer_name = "urbisNL3";

		var urbis_service = new OpenLayers.Layer.TileCache(
			"Urbis",
			map_url,
			layer_name,
			{
				isBaseLayer: true,
				format: 'image/png',
				transitionEffect: 'resize',
				serverResolutions: mapResolutions
			}
		);
	
		var start_urbis_service ;
		urbis_service.events.register("loadstart", urbis_service, function() {
			start_urbis_service = new Date();
		}) ;

		urbis_service.events.register("loadend", urbis_service, function() {
			var time = new Date() - start_urbis_service;
			$this[0]._tiles_loaded = time ;
			callbacks = $this[0]._on_tiles_loaded ;

			if (callbacks) {
				$(callbacks).each(function(index, callback) {
					this(time) ;
				});
			}
		}) ;

		urbis_service.setOpacity(1);
		map.addLayer(urbis_service);

		// Address Markers
		address_markers = new OpenLayers.Layer.Markers("Address Markers");
		map.addLayer(address_markers);
		address_markers.setZIndex(600);

		addLandmarks();

		map.setCenter(center, settings.zoom);

		// this tricky implementation of selectFeatureControl allows to manage events on features even when all layers are not yet present
		var selectFeatureControl = null;
		map.events.register("addlayer", map, function (evt) {
			if (evt.layer) {
				if (evt.layer.CLASS_NAME == "OpenLayers.Layer.Vector") {
					if (selectFeatureControl == null) {
						selectFeatureControl = new OpenLayers.Control.SelectFeature([evt.layer], {
								id: "selectFeatureControl",
								hover: true,
								onSelect: showTip,
								onUnselect: hideTip,
								clickFeature: function (feature) {
									if (feature.cluster && feature.cluster.length > 1) {
										feature.layer.map.setCenter(feature.geometry.bounds.centerLonLat, Math.min(map.getZoom() + 2, map.baseLayer.numZoomLevels-1));
										hideTip(feature);

									} else if (feature.data.url) {
										if (!$(map.div).hasClass("zooming") && !$(map.div).hasClass("zoomingout")) {
											location.href = feature.data.url;
										}
									}
								}
						} );
						map.addControl(selectFeatureControl);
						selectFeatureControl.activate();
					} else {
						selectFeatureControl.layers.push(evt.layer);
						selectFeatureControl.layer.layers.push(evt.layer);

						// re-init with this new layer
						selectFeatureControl.deactivate();
						selectFeatureControl.activate();
					}
				}
			}
		});
		function end_map_init() {
			var layers = [];

			// set visibility of layers
			if (typeof(settings.active_layers) != "undefined") {
				var active_layers = settings.active_layers.split(",");
				var legend_layers = $(".mapLegend tr");
				for (var i=0; i < legend_layers.length; i++) {
					if ($.inArray($(legend_layers[i]).attr("id"), active_layers) > -1) $(legend_layers[i]).trigger("legend_item_activate");
					else $(legend_layers[i]).trigger("legend_item_deactivate");
				}
			}

			function cursorMove(){
				$(this).addClass("moving");
			}
			function cursorEndMove(){
				$(this).removeClass("moving");
			}
			function zoomboxMove(){
				$(this).removeClass("moving");  // necessary for msie
			}

			FullScreen = OpenLayers.Class(OpenLayers.Control.Button, {
				initialize: function () {
					 OpenLayers.Control.Button.prototype.initialize.apply(this, arguments);
				},
				applyToolTip: function () {
					var text = this.fullscreen ? this.tooltip_off : this.tooltip_on;
					this.panel_div.setAttribute("title", text);
					this.panel_div.setAttribute("alt", text);
				},
				draw: function () {
					OpenLayers.Control.Button.prototype.draw.apply(this, arguments);
					this.applyToolTip();
				},
				fullscreen: false,
				zoom_on_trigger: true,
				EVENT_TYPES: ["activate","deactivate","fullscreen_on", "fullscreen_off"],
				trigger: function () {
					if (this.map) {
						this.fullscreen = !this.fullscreen;
						if (this.fullscreen) {
							if (this.zoom_on_trigger) {
								map.zoomIn();
							}
							this.events.triggerEvent("fullscreen_on");
						} else {
							this.events.triggerEvent("fullscreen_off");
							if (this.zoom_on_trigger) {
								map.zoomOut();
							}
						}
						this.applyToolTip();
					}
				},
				CLASS_NAME: "FullScreen"
			});

			Multimodal = OpenLayers.Class(OpenLayers.Control.Button, {
				initialize: function () {
					 OpenLayers.Control.Button.prototype.initialize.apply(this, arguments);
				},
				applyToolTip: function () {
					var text = this.multimodal ? this.tooltip_off : this.tooltip_on;
					this.panel_div.setAttribute("title", text);
					this.panel_div.setAttribute("alt", text);
				},
				draw: function () {
					OpenLayers.Control.Button.prototype.draw.apply(this, arguments);
					this.applyToolTip();
				},
				multimodal: settings.multimodal,
				zoom_on_trigger: true,
				EVENT_TYPES: ["activate","deactivate","multimodal_on", "multimodal_off"],
				trigger: function () {
					if (this.map) {
						this.multimodal = !this.multimodal;
						if (this.multimodal) {
							/*if (this.zoom_on_trigger) {
								map.zoomIn();
							}*/
							this.events.triggerEvent("multimodal_on");
						} else {
							this.events.triggerEvent("multimodal_off");
							/*if (this.zoom_on_trigger) {
								map.zoomOut();
							}*/
						}
						this.applyToolTip();
					}
				},
				CLASS_NAME: "Multimodal"
			});

			if (window.multimodalOffText) { // skip multimodal if reference not found
				// multimodal action is later bound via <controlname>l.events.register("multimodal_on", ... )
				var multimodal_tool = new Multimodal({displayClass: lang + "_Multimodal " + lang + "_Multimodal", tooltip_on: multimodalOnText, tooltip_off: multimodalOffText }) ;
				var fullscreen_tool = null;
			} else {
				// fullscreen action is later bound via <controlname>l.events.register("fullscreen_on", ... )
				// default if no multimodal text available : fullscreen tool
				var fullscreen_tool = new FullScreen({displayClass:"FullScreen FullScreen", tooltip_on: fullscreenOnText, tooltip_off: fullscreenOffText }) ;
				var multimodal_tool = null;
			}
			//var zoominit_tool = new OpenLayers.Control.ZoomToMaxExtent();
			var nav_history_tool = new OpenLayers.Control.NavigationHistory();
			map.addControl(nav_history_tool);
			var zoombox_tool = new OpenLayers.Control.ZoomBox({id: "zoombox_in", out: false});
			//var zoomout_tool = new OpenLayers.Control.ZoomOut();
            //var zoomout_tool = new zoomOutTool({displayClass:"ZoomOut ZoomOut"});
			var zoomout_tool = new OpenLayers.Control.ZoomBox({id: "zoombox_out", out: true, displayClass:"ZoomOut ZoomOut"});
			var pan_tool = new OpenLayers.Control.Navigation({id: "navigation"});
			pan_tool.zoomWheelEnabled = false;

			var toolbar_panel = new OpenLayers.Control.Panel({'div': document.getElementById("mapToolBar"),'defaultControl':pan_tool});
			toolbar_panel.addControls([nav_history_tool.previous, nav_history_tool.next, zoombox_tool, zoomout_tool, pan_tool, multimodal_tool || fullscreen_tool]);
			map.addControl(toolbar_panel);

			zoombox_tool.events.register("activate", zoombox_tool, function() {
				$("#mapDiv").addClass("zooming");
				$("#mapDiv").bind('mousedown', zoomboxMove);
			});
			zoombox_tool.events.register("deactivate", zoombox_tool, function() {
				$("#mapDiv").removeClass("zooming");
				$("#mapDiv").unbind('mousedown', zoomboxMove);
			});

            zoomout_tool.events.register("activate", zoomout_tool, function() {
				$("#mapDiv").addClass("zoomingout");
			});
            zoomout_tool.events.register("deactivate", zoomout_tool, function() {
				$("#mapDiv").removeClass("zoomingout");
			});

			pan_tool.events.register("activate", pan_tool, function() {
				$("#mapDiv").bind('mousedown', cursorMove);
				$("#mapDiv").bind('mouseup', cursorEndMove);
			});
			pan_tool.events.register("deactivate", pan_tool, function() {
				$("#mapDiv").unbind('mousedown', cursorMove);
				$("#mapDiv").unbind('mouseup', cursorEndMove);
			});
			// first call is required to enable drag hand before any option is explicitly choosen by user
			$("#mapDiv").bind('mousedown', cursorMove);
			$("#mapDiv").bind('mouseup', cursorEndMove);

			$(".olControlNavigationHistoryNextItemInactive").attr({alt:nextViewToolText, title:nextViewToolText});
			$(".olControlNavigationHistoryPreviousItemInactive").attr({alt:previousViewToolText, title:previousViewToolText});
			$(".olControlZoomBoxItemInactive").attr({alt:zoomBoxToolText, title:zoomBoxToolText});
            $(".ZoomOutItemInactive").attr({alt:zoomOutToolText, title:zoomOutToolText});
			$(".olControlNavigationItemActive").attr({alt:panToolText, title:panToolText});

			//map.addControl(new OpenLayers.Control.MouseDefaults());
			//map.addControl(new OpenLayers.Control.KeyboardDefaults());
			//map.events.remove('dblclick');

			//$("#mapDiv").mousedown(cursorMove);
			//$("#mapDiv").mouseup(cursorEndMove);

			mapTools();

            //legend
            var control_activate = function(control) {
                control.activate();
            }
            var control_deactivate = function(control) {
                control.deactivate();
            }
            for (c in map.controls) {
                if (map.controls[c].id == "filterMapPanel") {
                    control = map.controls[c];
                    window.setTimeout(function() {control_activate(control)},500);
                    //window.setTimeout(function() {control_deactivate(control)},2500);
                }
            }
            var hideLegend = function() {
                if (!legend_user_action_done) {
                    legend_user_action_done = true;
                    for (c in map.controls) {
                        if (map.controls[c].id == "filterMapPanel") {
                            var control = map.controls[c];
                            window.setTimeout(function() {control_deactivate(control)},1000);
                        }
                    }
                }
            }
            map.events.register("zoomend", map, hideLegend);
            map.events.register("zoomend", map, hideTip);
		}
		//control to recenter the map (coming back to initial view or search result)
		/*x_recenter = settings.lon; y_recenter = settings.lat; zoom_recenter = settings.zoom;
		$("#doInitialMap").click(function() {
			var center = new OpenLayers.LonLat(x_recenter, y_recenter);
			if($("#doMapFullScreen").css("visibility") != "hidden")
				map.setCenter(center, zoom_recenter);
			else
				map.setCenter(center, zoom_recenter+1);  //full screen mode
		});*/


		// setup fullscreen switch

		if (settings.oninit) {
			var timeout = 200 ;
			var times = 5; // don't try more than 5 times
			// retry until it works ( openlayers tends to crash if the page is not entirely loaded )
			function retry() {
				try {
					//if (settings.zipoints) loadZiPoints();
					if (settings.oninit) settings.oninit($this);
					end_map_init();
				} catch(e) {
					if (window.console) { console.info(e); }
					if (--times > 0) {
						window.setTimeout(retry, timeout);
						timeout += timeout ;
					}
				}
			}
			retry();
		}

		return $this;
	}

	$.fn.onTilesLoaded = function(callback) {
		var $this = this ;
		var me = this[0];

		if (me._tiles_loaded) {
			callback(me._tiles_loaded);
		} else {
			if (!me._on_tiles_loaded) {
				me._on_tiles_loaded = [] ;
			}
			me._on_tiles_loaded.push(callback);
		}
		return $this;
	}
}(jQuery));


function zoomToPoint(x,y, default_zoom) {
	if (address_markers.markers.length > 0) {
		address_markers.clearMarkers();
	}

	var size = new OpenLayers.Size(35,33);
	var offset = new OpenLayers.Pixel(-(size.w/2), -(size.h/2));
	var icon = new OpenLayers.Icon(media_url + "img/map/" + you_are_here_icon, size, offset);
	address_markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(x,y),icon));

	var zoom = default_zoom || map.location_zoom || 4;
	map.setCenter(new OpenLayers.LonLat(x, y), zoom);
	map.x_recenter = x; map.y_recenter = y; map.zoom_recenter = zoom;
}

function zoom_to_user_location() {
	// dynamically load libraries
	if (!window.geo_position_js) {
		jQuery.ajax({ url: media_url + "js/gis/geo.js", dataType: "script", success: zoom_to_user_location, cache: true});
		return;
	}
	function got_lambert(data) {
		zoomToPoint(data.x, data.y, 3);
	}
	function got_position(position) {
		$.getJSON("/gis/lambert?" + position.coords.longitude + "," + position.coords.latitude, got_lambert);

	};
	function _zoom_to_user_location() {
		if (geo_position_js.init()) {
			geo_position_js.getCurrentPosition(got_position, function() { /* fail */ });
		}
	}
	_zoom_to_user_location();
}

function addLandmarks() {
	var landmarks_wms = new OpenLayers.Layer.WMS("landmarks",
		"/urbis/geoserver/wms",
		{
			"layers": 'urbis:URB_M_ZIPOINT',
			"styles": "mobility_landmarks",
			"transparent": true,
			"cql_filter": "TYPE='TS' OR TYPE='RS'"
		},
		{
			isBaseLayer: false,
			visibility: true
		}
	);
	map.addLayer(landmarks_wms);
}

// Zi Points (rail stations, tube stations, ...)
function loadZiPoints() {
	var styleZi = new OpenLayers.Style({"cursor": "inherit"});
	var ruleTS = new OpenLayers.Rule(
		{ filter: new OpenLayers.Filter.Comparison(
				{ type: OpenLayers.Filter.Comparison.EQUAL_TO,
					property: "ZIFT",
					value: "TS"
				}),
			symbolizer: {
				externalGraphic : media_url + "img/map/metro_map.gif",
				graphicOpacity : 1, graphicWidth : 19, graphicHeight : 23, graphicXOffset : -9.5, graphicYOffset : -11.5
			},
			maxScaleDenominator: 20000
		}
	);
	var ruleRS = new OpenLayers.Rule(
		{ filter: new OpenLayers.Filter.Comparison(
				{ type: OpenLayers.Filter.Comparison.EQUAL_TO,
					property: "ZIFT",
					value: "RS"
				}),
			symbolizer: {
				externalGraphic : media_url + "img/map/gare_map.gif",
				graphicOpacity : 1, graphicWidth : 19, graphicHeight : 23, graphicXOffset : -9.5, graphicYOffset : -11.55
			},
			maxScaleDenominator: 20000
		}
	);
	var ruleHO = new OpenLayers.Rule(
		{ filter: new OpenLayers.Filter.Comparison(
				{ type: OpenLayers.Filter.Comparison.EQUAL_TO,
					property: "ZIFT",
					value: "HO"
				}),
			symbolizer: {
				externalGraphic : media_url + "img/map/hopital_map.gif",
				graphicOpacity : 1, graphicWidth : 19, graphicHeight : 23, graphicXOffset : -9.5, graphicYOffset : -11.55
			},
			maxScaleDenominator: 10000
		}
	);
	var ruleMA = new OpenLayers.Rule(
		{ filter: new OpenLayers.Filter.Comparison(
				{ type: OpenLayers.Filter.Comparison.EQUAL_TO,
					property: "ZIFT",
					value: "MA"
				}),
			symbolizer: {
				externalGraphic : media_url + "img/map/hoteldeville_map.gif",
				graphicOpacity : 1, graphicWidth : 19, graphicHeight : 23, graphicXOffset : -9.5, graphicYOffset : -11.55
			},
			maxScaleDenominator: 10000
		}
	);
	styleZi.addRules([ruleTS,ruleRS,ruleHO,ruleMA]);
	var styleMapZi = new OpenLayers.StyleMap({"default": styleZi, "select": new OpenLayers.Style({"cursor": "inherit"})});

	var zifilter = new OpenLayers.Filter.Logical({
		type: OpenLayers.Filter.Logical.OR,
		filters: [
			new OpenLayers.Filter.Comparison(
				{
					type: OpenLayers.Filter.Comparison.EQUAL_TO,
					property: "ZIFT",
					value: "TS"
				}),
			new OpenLayers.Filter.Comparison(
				{
					type: OpenLayers.Filter.Comparison.EQUAL_TO,
					property: "ZIFT",
					value: "RS"
				}),
			new OpenLayers.Filter.Comparison(
				{
					type: OpenLayers.Filter.Comparison.EQUAL_TO,
					property: "ZIFT",
					value: "HO"
				}),
			new OpenLayers.Filter.Comparison(
				{
					type: OpenLayers.Filter.Comparison.EQUAL_TO,
					property: "ZIFT",
					value: "MA"
				})
		]
	});

	var layerZi = new OpenLayers.Layer.Vector("Zi",
			{
				strategies: [new OpenLayers.Strategy.BBOX()],
				projection: new OpenLayers.Projection("EPSG:31370"),
				protocol: new OpenLayers.Protocol.WFS({
					url: "/urbis/geoserver/wfs",
					featureType: "UrbMap_Zi",
					featureNS: "http://www.cirb.irisnet.be/urbis",
					geometryName: "the_geom"
				}),
				filter: zifilter,
				styleMap: styleMapZi,
                print: false
			}
	);
	map.addLayer(layerZi);

	// zi points popup -- TODO not valid anymore with selectfeature refactoring
	function onFeatureUnselect(feature) {
		$("#mapTip").css({"visibility": "hidden"});
	}

	function onFeatureSelect(feature) {
		if (lang == "fr") $("#mapTip").html(feature.data.ZIFN)
		else if (lang =="nl") $("#mapTip").html(feature.data.ZIDN)
		var lonlat = feature.geometry.getBounds().getCenterLonLat();
		var pos = map.getPixelFromLonLat(lonlat);

		$("#mapTip").css({
							'left' : pos.x - $("#mapTip").width() - 20,
							'top' : pos.y - $("#mapTip").height() - 20,
							'visibility': 'visible'
						});
		if (!$.browser.msie) $("#mapTip").corner("keep");
	}

	if (window.ziPointsTip) {
		var selectFeatureControl = new OpenLayers.Control.SelectFeature(layerZi, {callbacks: {'out':onFeatureUnselect,'over':onFeatureSelect,'click':onFeatureSelect}});

		map.addControl(selectFeatureControl);
		selectFeatureControl.activate();
	}
}


function mapTools() {
    // initial view
    $("#initviewTool").click(function(){
        map.setCenter(new OpenLayers.LonLat(map.original_settings.lon, map.original_settings.lat), settings.zoom);
    });

    // print map
    $("#printTool").click(function(){
        layers_str = "";
        layers_wms = [];
        for (layer in map.layers) {
            if (typeof(map.layers[layer].print) != "undefined" && map.layers[layer].print == false) continue;
            if (map.layers[layer].visibility == false) continue;
            if (map.layers[layer].CLASS_NAME == "OpenLayers.Layer.Vector") {
                if (map.layers[layer].print_filter) {
                    var cql_filter = map.layers[layer].print_filter.apply(map.layers[layer]);
                    layers_wms.push({"layers": map.layers[layer].name, "CQL_FILTER": cql_filter, "styles": ""});
                } else {
                    layers_str = layers_str + "mobility:" + map.layers[layer].name + ",";
                }
            }
            if (map.layers[layer].CLASS_NAME == "OpenLayers.Layer.WMS") {
                var layers = map.layers[layer].params.LAYERS;
                var cql_filter = ""; if (typeof(map.layers[layer].params.CQL_FILTER) != "undefined") cql_filter = map.layers[layer].params.CQL_FILTER;
                var styles = ""; if (typeof(map.layers[layer].params.STYLES) != "undefined") styles = map.layers[layer].params.STYLES;
                layers_wms.push({"layers": layers, "CQL_FILTER": cql_filter, "styles": styles});
            }
        }
        if(layers_str != "") layers_str = layers_str.substr(0,layers_str.length-1);
        var title = "";
        if (typeof(map_title) != "undefined") {
            title = map_title;
        }
        printMap(title, layers_str, layers_wms);
    });

    //multimodal
    var multimodal_tools = map.getControlsByClass("Multimodal");
    if (multimodal_tools.length > 0) {
		var multimodal_tool = map.getControlsByClass("Multimodal")[0];
		multimodal_tool.events.register("multimodal_on", multimodal_tool, function () {
			var url = "/map/intermodal/";
			url += "?zoom=" + (settings.zoom_levels[map.zoom] + 1);
			if (map.getZoom() > 1) url += "&lon=" + map.getCenter().lon;
			else url += "&lon=" + (map.getCenter().lon-1000);
			url += "&lat=" + map.getCenter().lat;
			var active_layers = "";
			var legend_layers = $(".mapLegend tr");
			for (var i=0; i < legend_layers.length; i++) {
				if (!$(legend_layers[i]).hasClass("disabled")) active_layers += $(legend_layers[i]).attr("id") + ",";
			}

			var forced_active_layers = map.original_settings.force_multimodal_active_layers;
			if (forced_active_layers)  {
				for (var i=0;i<forced_active_layers.length;++i) {
					active_layers += forced_active_layers[i] + "," ;
				}
			}
			url += "&active_layers=" + active_layers.substr(0, active_layers.length-1);

			//specific parameter for icr
			if ($(".ICR").length > 0) {
				var active_icr = "";
				if (!$("#legendICR_All").hasClass("disabled")) active_icr = "all";
				else {
					for (var i=0; i<icr_activated_list.length; i++) active_icr += icr_activated_list[i] + ",";
					if (show_cpr) active_icr += "cpr" + ",";
					active_icr = active_icr.substr(0, active_icr.length - 1);
				}
				url += "&active_icr=" + active_icr;
			}

            url += "&ref=" + location.pathname ;

			window.location.href = url;
		});
		multimodal_tool.events.register("multimodal_off", multimodal_tool, function () {
			var url = settings.ref || document.referrer.split("?")[0] ;
			url += "?zoom=" + (settings.zoom_levels[map.zoom] - 1);
			if (map.getZoom() > 1) url += "&lon=" + map.getCenter().lon;
			else url += "&lon=" + (map.getCenter().lon+1000);
			url += "&lat=" + map.getCenter().lat;
			var active_layers = "";
			var legend_layers = $(".mapLegend tr");
			for (var i=0; i < legend_layers.length; i++) {
				if (!$(legend_layers[i]).hasClass("disabled")) active_layers += $(legend_layers[i]).attr("id") + ",";
			}
			url += "&active_layers=" + active_layers.substr(0, active_layers.length-1);

			//specific parameter for icr
			if ($(".ICR").length > 0) {
				var active_icr = "";
				if (!$("#legendICR_All").hasClass("disabled")) active_icr = "all";
				else {
					for (var i=0; i<icr_activated_list.length; i++) active_icr += icr_activated_list[i] + ",";
					if (show_cpr) active_icr += "cpr" + ",";
					active_icr = active_icr.substr(0, active_icr.length - 1);
				}
				url += "&active_icr=" + active_icr;
			}
			
			window.location.href = url;
		});
	} else {
		// full screen
		var init_map_height = $("#mapDiv").height();
		var init_map_width = $("#mapDiv").width();
		var fullscreen_tool = map.getControlsByClass("FullScreen")[0];
		fullscreen_tool.events.register("fullscreen_on", fullscreen_tool, function () {
			var map_center = map.center;
			$("#main").fadeOut(0);
			var new_map_height = $(window).height();
			var new_map_width = $("#main").width();
			$("#main").append($("#mapContainerContent"));
			$("#mapDiv").css({
				width: new_map_width,
				height: new_map_height
			});
			map.setCenter(map_center);
			$("#main").fadeIn(500, function () {
				// can't use hide() due to IE bug when coming back to non-fullscreen
				$("#right,#center").css("display","none");
			});
	
			$("#copyrightUrbis").show();
		});
	
		fullscreen_tool.events.register("fullscreen_off", fullscreen_tool, function() {
			var map_center = map.center;
			$("#mapDiv").css({
				width: init_map_width,
				height: init_map_height
			});
			// IE bug: even if $("#right,#center").css("display","none") happen BEFORE this line,
			// map is still unavailable after coming back from fullscreen. Changing the display 2 times ( immediate and postponed reset ) seem to work.
			$("#right,#center").css("display","block");
			window.setTimeout(function () { $("#right,#center").css("display","") }, 100);
			$('#mapContainer').append($('#mapContainerContent'));
			map.setCenter(map_center);
		});
	}
}

var default_style = {
	graphicOpacity: 1,
	graphicWidth: 19,
	graphicHeight: 23,
	graphicXOffset: -9.5,
	graphicYOffset: -23,
	cursor: "default"
} ;

/* popups are objects that take care of formatting legends, for each layer */
var popups = {} ;

var legend_items = [] ;


// TODO -- getting all cluster images is still a bit slow. See if using sprites is really not possible
var clusterStyleId = 0 ;
function makeLayer(name, layer_params, popup, legend_params, ajax_params) {
	/* create layer, customize style, attach to map */
	// TODO -- re-organize parameters for makeLayer !
	//         subclass OpenLayers.Vector ?

	// style_mark can be either a hash ( for default style ) or hash of hash ( style mapping : default, select, .. )

	var hooks = {};
	function find_cluster_styles(style_hash) {
		for (style_entry in style_hash) {
			var style_value = style_hash[style_entry];
			if (typeof style_value == "function") {
				++clusterStyleId;
				var hook_name = "cluster_" + clusterStyleId ;
				hooks[hook_name] = style_value ;
				style_hash[style_entry] = "${" + hook_name + "}";
			}
		}
	}

	if (layer_params.style_mark) {
		// apply defaults to style, then find cluster properties
		for (style_key in layer_params.style_mark) {
			if (typeof layer_params.style_mark[style_key] != "object") {
				OpenLayers.Util.applyDefaults(layer_params.style_mark, default_style)
				find_cluster_styles(layer_params.style_mark[style_key]);
			} else {
				OpenLayers.Util.applyDefaults(layer_params.style_mark["default"], default_style);
				// first loop was to find the first key ; this one loops to find cluster properties
				for (style_key in layer_params.style_mark) {
					find_cluster_styles(layer_params.style_mark[style_key]);
				}
			}
			break;
		}
		
		var style_map = new OpenLayers.StyleMap(layer_params.style_mark);

		// apply cluster hooks
		for (style_key in style_map.styles) {
			var style = style_map.styles[style_key];
			style.context = OpenLayers.Util.extend(style.context || {}, hooks);
		}

		layer_params.styleMap = style_map;
	}

 	var layer = new OpenLayers.Layer.Vector(name, layer_params);
	map.addLayer(layer);

	/* load json */
    if (ajax_params) {
	    var reader = layer_params.reader ;
        if (!reader) {
            var json_format = new OpenLayers.Format.GeoJSON();
            reader = OpenLayers.Function.bind(json_format.read, json_format);
        }
		var last_xhr_date ;
		var ajax_params = $.extend({
		    type: "GET",
		    dataType: "json",
		    ifModified: true,
		    cache: false,
		    success: function (data, status, xhr) {
				var expired = ajax_params.maxage && getXHRAge(xhr) > ajax_params.maxage ;
				if (expired) {
					layer.destroyFeatures();
					return ;
				}
				// don't refresh if current file is older/the same as previously
				var xhrdate = getXHRDate(xhr);
				if (last_xhr_date && last_xhr_date >= xhrdate) return ;
				if (layer.features.length > 0) {
					layer.destroyFeatures();
				}
				last_xhr_date = xhrdate ;

			    $("body").css("cursor","wait");
			    window.setTimeout(function() {
				    layer.addFeatures(reader(data));
				    layer.redraw();
				    $("body").css("cursor","");
			    }, 1);
		    }
	    }, ajax_params);

	    if (ajax_params.interval) {
			var bound_update_date = OpenLayers.Function.bind(updateLastUpdateDate, layer);
			if (ajax_params.success) {
				ajax_params.success = dispatch(ajax_params.success, bound_update_date);
		    } else {
			    ajax_params.success = bound_update_date;
		    }
		    setInterval(function () {
			    jQuery.ajax(ajax_params);
		    }, ajax_params.interval);
	    }
	    jQuery.ajax(ajax_params);
    }
	
	/* show/hide method */
    if (legend_params) {
        var legend_params = $.extend({ visible: true }, legend_params);
        var legend_tr_height = 31;
        if ($.browser.msie && $.browser.version<="7.0") {
            // padding does not add up the same way on ie<=7 , remove 12 pixels ( padding top&bottom = 6 px )
            legend_tr_height = 19;
        }

		if (legend_params.category) var legendTable = $("#" + legend_params.category + "Table").find('tbody');
		else var legendTable = $("#mapLegendTable").find('tbody');
		for (var i=0; i<legend_params.switchs.length;++i) {
			var legend_content = "<tr id='switch_" + name + i + "' style='height:'+legend_tr_height+'px;' ";
            if (legend_params.tooltips && legend_params.tooltips[lang] && legend_params.tooltips[lang][i])
            	legend_content += "title='"+legend_params.tooltips[lang][i]+"'";
            if (legend_params.switchs[i]) {
                legend_content += "class='switch_button'><td class='switch_button'></td>";
            } else if (legend_params.expand_div) {
            	legend_content += "class='expand_button'><td class='expand_button'></td>";
            } else legend_content += "><td style='width:19px' />";
            if (legend_params.titles && legend_params.titles[lang] && legend_params.titles[lang][i])
                legend_content += "<td><span class='maplegend'>" + legend_params.titles[lang][i] + "</span></td>";
            var icon_key = null;
            if (legend_params.icons[lang] && legend_params.icons[lang][i]) icon_key = lang;
            else if (legend_params.icons["all"] && legend_params.icons["all"][i]) icon_key = "all";
            if (icon_key) {
                if (legend_params.titles && legend_params.titles[lang] && legend_params.titles[lang][i]) legend_content += "<td>";
                else legend_content += "<td colspan='2'>";
                legend_content += "<img src='" + legend_params.icons[icon_key][i] + "'>" + "</td>";
            }
            legend_content += "</tr>";
            legendTable.append(legend_content);
		}

        for (var i=0; i<legend_params.switchs.length;++i) {
            if (legend_params.switchs[i] || legend_params.expand_div) {
                (function (i) {
				    var visibility = legend_params.visible;
				    var $switch_button = $("#switch_" + name + i);
				
				    var setVisibility = function (value) {
					    if (value) {
						    $switch_button.removeClass("disabled");
						    if (legend_params.expand_div) {
						    	$("#" + legend_params.expand_div).show();
						    }
					    } else {
						    $switch_button.addClass("disabled");
						    if (legend_params.expand_div) $("#" + legend_params.expand_div).hide();
						    if (legend_params.category) $switch_button.parents("div:first").find(".mapLegendCategory").trigger("unselect_category");
					    }
					    if (legend_params.switchs[i] && legend_params.setVisibility) {
						    OpenLayers.Function.bind(legend_params.setVisibility, layer)(value, i);
					    } else if (legend_params.switchs[i]) {
						    layer.setVisibility(value);
					    }
					    visibility = value ;
				    };

				    $switch_button.click(
					    function () { setVisibility(!visibility); }
				    );
				    $switch_button.bind('legend_item_activate',
					    function () { setVisibility(true); }
				    );
				    $switch_button.bind('legend_item_deactivate',
					    function () { setVisibility(false); }
				    );
				    $switch_button.attr("unselectable", "on");
				    $switch_button.mousedown(
					    function (e) { e.preventDefault(); }
				    );
				    setVisibility(legend_params.visible);
			    })(i);
            }
        }
    }

	/* manage legend */
	if (!map.is_setup) { // first item : setup
		map_setup(map);
	}

	if (popup) {
		popup_class = $.extend({
			layer: layer,
			map: map,
			reload: function(callback) {
				$.ajax(ajax_params);
			}
		}, Popup);
		popups[name] = $.extend(popup_class, popup);
	}
	return layer ;
}

function map_setup(map) {
    if (!map.is_setup && jQuery("#drawersBar").length) {
        var drawers_panel = new OpenLayers.Control.Panel({
            id: "drawersBar",
            div: document.getElementById("drawersBar"),
            active: false
        });

        DrawerControl = OpenLayers.Class(OpenLayers.Control.Button, {
            type: OpenLayers.Control.TYPE_TOGGLE,
            active: false,
            disabled: false,
            activate: function () {
                if (this.disabled) return false;
                //this.div.style.display = "";
                $(this.div).slideDown(500);
                return OpenLayers.Control.prototype.activate.apply(this, arguments);
            },
            deactivate: function () {
                //this.div.style.display = "none";
				this.set_disabled_class();
                $(this.div).slideUp(500);
                return OpenLayers.Control.prototype.deactivate.apply(this, arguments);
            },
			set_disabled_class: function () {
				// set the class to the panel, since the button itself needs another patch to be customized
				if (this.disabled) {
					$(this.panel_div).parent().addClass(this.id+"_"+"disabled");
				} else {
					$(this.panel_div).parent().removeClass(this.id+"_"+"disabled");
				}
			},
            disable: function () {
                this.disabled = true;
				this.set_disabled_class();
				if (this.active) this.deactivate();
            },
            enable: function () {
                this.disabled = false;
				this.set_disabled_class();
            }
        });

		var controls = [];

		var filterMapPanel = document.getElementById("filterMapPanel");
		if (filterMapPanel) {
			controls.push(new DrawerControl({
				id: "filterMapPanel",
				div: filterMapPanel,
				displayClass: "drawerToggle filterMap "
			}));
		}
		var searchMapPanel = document.getElementById("searchMapPanel");
		if (searchMapPanel) {
			controls.push(new DrawerControl({
				id: "searchMapPanel",
				div: document.getElementById("searchMapPanel"),
				displayClass: "drawerToggle searchMap "
			}));
			$(searchMapPanel).append($("#mapSearchForm"));
		}
		var overviewMapPanel = document.getElementById("overviewMapPanel");
		var overview_control;
		if (overviewMapPanel) {
			overview_control = new DrawerControl({
				id: "overviewMapPanel",
				div: document.getElementById("overviewMapPanel"),
				displayClass: "drawerToggle overviewMap "
			});
			controls.push(overview_control);
			map.addControl(urbisOverview({ div: overviewMapPanel }));
		}
		drawers_panel.addControls(controls);
		map.addControl(drawers_panel);

		if (overview_control) {
			map.events.register("zoomend", map, function () {
				if (this.zoom == 0) {
					overview_control.disable();
				} else {
					overview_control.enable();
				}
			});
			if (map.zoom == 0) overview_control.disable();
		}
	}
	map.is_setup = true;
}

function clusterStyle(nonclustered, clustered, prefix, max) {
	// use "this" to get default values ?
	if (!max) {
		max = 16; // images from 2 to 16 are defined
	}
	var string_attribute = typeof nonclustered == "string" ;

	if (!prefix && string_attribute) {
		prefix = "";
	}

	// hooks will be appended to style context via makeLayers
	return function (feature) {
		if (feature.attributes.count > 1) {
			if (string_attribute) {
				var count = Math.min(feature.attributes.count, 16);
				if (count < 10) count = "0" + count;
				return prefix + clustered.replace("${count}", count);
			} else {
				return clustered;
			}
		} else {
			if (string_attribute) {
				return prefix + nonclustered;
			} else {
				return nonclustered;
			}
		}
	}
}

// allow chaining several callbacks, for example on ajax complete
function dispatch() {
	var me = this;
	var functions = arguments ;
	return function () {
		for (var i=0; i<functions.length; ++i) {
			functions[i].apply(me, arguments);
		}
	}
}

var lastMapUpdate;
function updateLastUpdateDate(data, status, xhr){
	var last_modified ;
	if (xhr) last_modified = getXHRDate(xhr);
	else last_modified = getXHRDate(data);	

	// allow use of this.layer.last_modified in format callback
	this.last_modified = last_modified;
	if (last_modified || window.location.hostname == "127.0.0.1") {
		if (!lastMapUpdate || last_modified > lastMapUpdate) {
			lastMapUpdate = last_modified;

			var day = lastMapUpdate.getDate();
			var month = lastMapUpdate.getMonth() + 1;
			var year = lastMapUpdate.getFullYear();

			var seconds = lastMapUpdate.getSeconds();
			if (seconds < 10) seconds = "0" + seconds;
			var minutes = lastMapUpdate.getMinutes();
			if (minutes < 10) minutes = "0" + minutes;
			var hours = lastMapUpdate.getHours();
			$("#legendUpdate").html(last_update_label + " " + day + "/" + month + "/" + year + "&nbsp;" + hours + ":" + minutes + ":" + seconds);
		}
	}
}

function getXHRDate(data) { // receives xhr or jsonp array
	if (typeof data == "string") {
		// useful if we can't get xhr headers, i.e. jsonp requests
		// then, last update must be found inside the data
		var jsondata = $.parseJSON(data);
		if (jsondata["Last-Modified"]) return new Date(jsondata["Last-Modified"]);
	} else {
		try {
				var last_modified = data.getResponseHeader("Last-Modified");
				return new Date(last_modified);
		} catch (e) {
				// ignore strange ie6 behaviour when testing getResponseHeader
		}
	}
}
function getXHRAge(xhr) {
	var xhrdate = 	getXHRDate(xhr);
	if (xhrdate) {
		return (new Date()).getTime() - xhrdate.getTime();
	}
}


/* map search form */
function getAddressCoordinates() {
	var streetName = $("#searchStreetName").val();
	var number = $("#searchNumber").val();
	var postalCode = $("#searchgPostalCode").val();
	var url = "/urbis/wsgeoloc/services/Localization";
	var pl = new SOAPClientParameters();

	if (!postalCode && !streetName && !number) {
		zoom_to_user_location();
	}
	pl.add("street", streetName);
	pl.add("houseNumber", number);
	pl.add("postCode", postalCode);
	if (lang == "nl") pl.add("language", "nl");
	else pl.add("language", "fr");
	SOAPClient.invoke(url, "getXY", pl, true, getXY_callBack);
}

function getXY_callBack(response) {

	if (response && response.getXYReturn) {
		var adresse = response.getXYReturn.address.streetName + " ";
		if (response.getXYReturn.address.houseNumber) adresse += response.getXYReturn.address.houseNumber + " ";
		adresse += response.getXYReturn.address.postalCode;
		$("#address_result").html(adresse);

		zoomToPoint(response.getXYReturn.point.x, response.getXYReturn.point.y);
	}
	else {
		$("#address_result").html(noresult);
	}
}


function hideTip(feature) {
    if (!feature.geometry) feature = null ; // not a feature, don't take it
	if (feature && feature.cluster) feature = feature.cluster[0];

	if (feature && feature.layer && popups[feature.layer.name]) {
		popups[feature.layer.name].hide(feature) ;
	}
	if ($("#mapTip").data("feature") == feature || !feature) {
		$("#mapTip").css({'visibility' : 'hidden'});
		$("#mapTip").html("");
	}
}

var Popup = {
	tip: "#mapTip",
	formatCluster: function(feature) {
		var content = "";
		for (var i=0;i<Math.min(feature.cluster.length,max_cluster_popup_descriptions);++i) {
			content += this.formatFeature(feature.cluster[i]);
		}
		if (feature.attributes.count > max_cluster_popup_descriptions) {
			// TODO -- we'd better use jsi18n ( see taxiforms for usage )
			content += '<span class="ellipsis">' + (lang == 'nl' ? 'Meer' : 'Suite') + '...</span>' ;
		}
		return content;
	},
	formatFeature: function(feature) {
		var content = this.format;
		if (typeof(this.format) == "function") content = this.format(feature.data);
		
		if (this[lang]) {
			for (key in this[lang]) {
				// map translatable fields
				if (typeof(feature.data[key]) != "undefined") feature.data[this[lang][key]] = feature.data[key];
				
				// replace translatable labels
				content = content.replace("{"+key+"}", this[lang][key]) ;
			}
		}
		if (typeof content == "string") {
			for (key in feature.data) {
				content = content.replace("{"+key+"}", feature.data[key]) ;
			}
		}
		return content ;
	},
	setFeature: function(feature) {
		if (!this.format) return;

		this.feature = feature ;
		if (feature.cluster) this.feature = feature.cluster[0];

		if (feature.cluster && feature.cluster.length > 1) {
			this.content = this.formatCluster(feature);
			this.icon_size = { w: 32, h: 35 } ;
		} else {
			this.content = this.formatFeature(this.feature);
			this.icon_size = { w: 19, h: 23 } ; // can't guess icon size since it resides in style ..
		}
	},
	display: function() {
		return this._display();
	},
	hide: function (feature) {
	},
	_display: function () {
		$tip = $(this.tip);
		$tip.data("feature", this.feature);
		$tip.data("icon_size", this.icon_size);
		$tip.html(this.content);
		if (!$.browser.msie) $tip.corner("keep");      //add round corners to map popups
		resetTipPosition();
		$tip.css({'visibility' : 'visible'});
	}
};

function showTip(feature) {	
    if (!map.dragging &&
        !map.getControl("zoombox_in").handler.dragHandler.started &&
        !map.getControl("zoombox_out").handler.dragHandler.started &&
        !map.getControl("navigation").zoomBox.handler.dragHandler.started) {
        var content = "";
        var popup = popups[feature.layer.name] ;

        if (!popup) return ;

        popup.setFeature(feature);
        popup.display();
    }
}

function resetTipPosition() {
		var lonlat = $("#mapTip").data("feature").geometry.getBounds().getCenterLonLat();
		var icon_size = $("#mapTip").data("icon_size");
		var pos = this.map.getPixelFromLonLat(lonlat);
		var extent = this.map.getExtent();
		var quadrant = extent.determineQuadrant(lonlat)
		$tip.width("");
		$tip.css({left: "", right: "", top: "", bottom: ""});
		if ($tip.width() > 350) {
			$tip.width("350px");
		}

		switch (quadrant) {
			case "tl" : $tip.css({
								'left' : pos.x + icon_size.w / 2,
								'top' : pos.y - $tip.height() / 2
							});
							break;
			case "tr" : $tip.css({
								'left' : pos.x - $tip.width() - icon_size.w - 6,
								'top' : pos.y - $tip.height() / 2
							});
							break;
			case "bl" : $tip.css({
								'left' : pos.x + icon_size.w / 2,
								'top' : pos.y - $tip.height() / 2
							});
							break;
			case "br" : $tip.css({
								'left' : pos.x - $tip.width() - icon_size.w - 6,
								'top' : pos.y - $tip.height() / 2
							});
							break;
		}
}

function printMap(title, layers, layers_wms) {
	var bounds = map.getExtent();
    bounds_str = "&xmin=" + bounds.left + "&ymin=" + bounds.bottom + "&xmax=" + bounds.right + "&ymax=" + bounds.top;
    url = "/map-print?title=" + title + bounds_str + "&layers=" + layers + "&map_width=" + $(map.div).width() + "&map_height=" + $(map.div).height() + "&lang=" + lang;
    var layers_wms_str = "";
    for (var i = 0; i < layers_wms.length; i++) {
        layers_wms_str = layers_wms_str + "&layers" + i + "=" + layers_wms[i].layers + "&CQL_FILTER" + i + "=" + layers_wms[i].CQL_FILTER + "&styles" + i + "=" + layers_wms[i].styles;
    }
    url = url + layers_wms_str;
    var new_window = window.open(encodeURI(url), "print_window");
    new_window.focus();

}

var childLoad = function() {
    this.print();
    this.close();
}

// subclassing OverviewMap does not seem to work as expected,
// this function acts as a factory instead
urbisOverview = function () {
    var layer_name = "urbisFR";
    if (lang == "nl") layer_name = "urbisNL";
    var urbis_overview = new OpenLayers.Layer.WMS.Untiled("urbis wms",
        "http://geoserver.gis.irisnet.be/wms?",
        {
            "layers": layer_name,
            "transparent": true
        },
        {
            isBaseLayer: true
        }
    );

    var options = OpenLayers.Util.extend({
        mapOptions: {
            projection: "EPSG:31370",
            units: "m",
            resolutions: [150.3021759376852],
            maxExtent: new OpenLayers.Bounds(125755.369856309,157893.305693269,175084.491014552,185238.0478827535)
        },
        layers: [urbis_overview],
        size: new OpenLayers.Size(148,100),
        autoPan: true,
        minRectSize: 7
    }, arguments[0]);

    return new OpenLayers.Control.OverviewMap(options);
};

/* custom cluster strategy :
   don't cluster when zoom is maximum */

LimitedClusterStrategy = OpenLayers.Class(OpenLayers.Strategy.Cluster, {
    shouldCluster: function (cluster, feature) {
        if (!this.layer || this.layer.map.zoom >= this.layer.map.resolutions.length -1) return false ;
        return OpenLayers.Strategy.Cluster.prototype.shouldCluster.apply(this, arguments);
    }
});

$.extend({
	getUrlParams: function(){
		var params = [], hash;
		var convert_to_float=["lon","lat"]; convert_to_int=["zoom"];
		var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
		for(var i = 0; i < hashes.length; i++)
		{
			hash = hashes[i].split('=');
			params.push(hash[0]);
			if ($.inArray(hash[0], convert_to_float) > -1) params[hash[0]] = parseFloat(hash[1]);
			else if ($.inArray(hash[0], convert_to_int) > -1) params[hash[0]] = parseInt(hash[1]);
			else params[hash[0]] = hash[1];
		}
		return params;
	}
});



