/** Global variables */
var maps = new Array();

var reasons=[];
reasons[G_GEO_SUCCESS]            = "Success";
reasons[G_GEO_MISSING_ADDRESS]    = "Missing Address: The address was either missing or had no value.";
reasons[G_GEO_UNKNOWN_ADDRESS]    = "Unknown Address:  No corresponding geographic location could be found for the specified address.";
reasons[G_GEO_UNAVAILABLE_ADDRESS]= "Unavailable Address:  The geocode for the given address cannot be returned due to legal or contractual reasons.";
reasons[G_GEO_BAD_KEY]            = "Bad Key: The API key is either invalid or does not match the domain for which it was given";
reasons[G_GEO_TOO_MANY_QUERIES]   = "Too Many Queries: The daily geocoding quota for this site has been exceeded.";
reasons[G_GEO_SERVER_ERROR]       = "Server error: The geocoding request could not be successfully processed.";

function Map(containerId, mapTypes) {
	this.initialize(containerId, mapTypes);
}

Map.prototype = {
	initialize: function(containerId, mapTypes){
		maps[containerId] = this;
		this.containerId = containerId;
		
		this.nbMarkers = 0;
		
		this.n = -90;
		this.s = 90;
		this.e = -180;
		this.w = 180;
		
		this.maxBounds = new GLatLngBounds(new GLatLng(this.s, this.w), new GLatLng(this.n, this.e));
		
		if (typeof mapTypes != "undefined"){
			this.map = new GMap2($(containerId), mapTypes);
			this.map.addControl(new GMapTypeControl());
		} else this.map = new GMap2($(containerId));

		this.map.savePosition();

		this.setDefaultCenter();
		
		this.markers = new Array();
		this.index = new Array();
		this.markerManager = new MarkerManager(this.map);
		
		this.controls = new Array();
		this.getDefaultOptions();
		
		/* Listeners */
		GEvent.addListener(this.map, "click", this.onMapClick);
		//GEvent.addListener(this.map, "singlerightclick", this.contextMenu);
		GEvent.bind(this.map, "zoomend", this, this.zoomChanged);
		GEvent.bind(this.map, "dragend", this, this.dragChanged);
		
		/* Menu */
		this.menuContainer = document.createElement("div");
		this.menuContainer.id = "mapMenu";
		this.map.getContainer().appendChild(this.menuContainer);
		
		//getMenu('mapMenu', this.menuContainer);
		
		/* Geocoding */
		this.geocoder = new Geocoder(this);
	},

	/*****************************************************/
	/** Dialogs */
	printMessage: function (messageHTML, append) {
		alert(messageHTML);
	},
	
	debug: function (message, color) { 
		GLog.write(message, color)
	},
	
	/*****************************************************/
	/** Defaults */
	getDefaultOptions: function () {
		this.map.enableScrollWheelZoom();
		this.addControl(new GLargeMapControl());
		//this.addControl(new GPolylineControl(this));
		//this.addControl(new GPolygonControl(this));
		//this.addControl(new GMarkerControl(this));
		//this.addControl(new GPositionInfo(this));
		//this.addControl(new GZoomInfo(this));
	},
	
	setDefaultCenter: function () {
		this.map.setCenter(new GLatLng(48, 6), 14);
	},
	
	/*****************************************************/
	/** Methods */
	createMarker: function (lat, lng, icon) {
        return new Marker(this, lat, lng, icon);
	},
	
	addMarker: function (marker, clear, center) {
		if (clear)
			this.clear();
	
		marker.id = this.markers.length;
        this.markers[this.markers.length] = marker;
        this.nbMarkers ++;

		this.setBounds(marker);

		if (center){
			//if (this.markers.length == 1)
				this.map.setCenter(marker.marker.getPoint(), 14);
			//else this.adaptedZoom();
		}

        this.map.addOverlay(marker.marker);

        this.printMessage("");
        marker.getCoordinates();
	},
	
	addManagedMarker: function (marker, zoomMin, zoomMax) {
		this.index[marker.id] = this.markers.length;
        this.markers[this.markers.length] = marker;
        this.nbMarkers ++;
        if (zoomMin == null) zoomMin = 0;
        if (zoomMax == null) zoomMax = 17;
		this.markerManager.addMarker(marker.marker, zoomMin, zoomMax);
	},
	
	removeMarker: function (marker){
		this.markers[marker.id] = null;
		this.nbMarkers --;
		this.map.removeOverlay(marker.marker);
	},
	
	getNbMarkers: function (){
		return this.nbMarkers;
	},
	
	getMarker: function (markerId){
		//return this.markers[markerId];
		return this.markers[this.index[markerId]];
	},
	
	listMarkers: function() {
		this.debug("nb markers = " + this.nbMarkers + "<br/>");
		for (var i=0; i<this.markers.length; i++){
			if (this.markers[i] != null){
				this.debug(this.markers[i].debug() + "<br/>", true);
			}
		}
	},
	
	addControl: function (control) {
		this.controls.push(control);
		this.map.addControl(control);
	},
	
	deactivateControls: function (control) {
		this.debug(this.controls.length);
		for (var i=0; i<this.controls.length; i++){
			if (this.controls[i] != control && this.controls[i].clicked && this.controls[i].monitored){
				this.debug("i = " + i);
				this.controls[i].doClick();
			}
		}
	},
	
	clear: function () {
		this.map.clearOverlays();
		this.markers = new Array();
		this.nbMarkers = 0;
		
		this.n = -90;
		this.s = 90;
		this.e = -180;
		this.w = 180;
		
		this.markerManager = new GMarkerManager(this.map);
	},
	
	setBounds: function (marker) {
		var lat = marker.marker.getPoint().lat();
		var lng = marker.marker.getPoint().lng();
		
		if (lat > this.n)
			this.n = lat;
		if (lat < this.s)
			this.s = lat;
			
		if (lng > this.e)
			this.e = lng;
		if (lng < this.w)
			this.w = lng;
	},
	
	setMaxBounds: function (maxBounds) {
		this.maxBounds = maxBounds;
		this.geocoder.geocoder.setViewport(this.maxBounds);
	},
	
	setCenter: function (lat, lng, zoom){
		if (typeof zoom != "undefined")
			this.map.setCenter(new GLatLng(lat, lng), zoom);
		else this.map.panTo(new GLatLng(lat, lng));
	},
	
	adaptedZoom: function () {
		var sw = new GLatLng(this.s, this.w);
		var ne = new GLatLng(this.n, this.e);
		
		var center = new GLatLng(this.s + (this.n - this.s)/2, this.w + (this.e - this.w)/2);
		
		this.map.setZoom(this.map.getBoundsZoomLevel(new GLatLngBounds(sw, ne)));
		this.map.setCenter(center);
	},
	
	onMapClick: function (overlay,point){
		//hideMenu();
		if (overlay) {
			// overlay is the GMarker object clicked by the user.
			//alert(overlay); // do something to or with the marker
		} else if (point) {
			// point is bare map mouse click location
			//alert(point); // do something with the clicked point
		} else {
    	// never happens
		}
	},
	
	contextMenu: function (point, src, overlay){
		menuContextuel('menucontextuel1', point.x, point.y);
	},
	
	zoomChanged: function (oldLevel, newLevel){
		if (typeof this.maxZoom != "undefined" && newLevel > this.maxZoom){
			this.map.setZoom(oldLevel);
		}
		if (typeof this.minZoom != "undefined" && newLevel < this.minZoom){
			this.map.setZoom(oldLevel);
		}
		this.map.savePosition();
	},
	
	dragChanged: function (){
		if (! this.maxBounds.containsBounds(this.map.getBounds()))
			this.map.returnToSavedPosition();
		else this.map.savePosition();
	}
}

function getMap(containerId) {
	return maps[containerId];
}
