/**
 * Classe gMap - Affiche une Google map
 * Permet d'ajouter/supprimer des points sur la carte
 * Turbulent Media - janvier 2010
 * @author frederic GINIOUX
 */

/**
 * Constructeur de la classe gMap
 * @param {Object} container HTML de la carte
 * @param {Object} coords lat-lng du ou des points sur la carte : {lat: , lng: } ou [{lat: , lng: }, {lat: , lng: }, {lat: , lng: }]
 * @param {Object} options - overwrite les options par defaut
 */
function gMap(container, coords, options){
	this.options = {zoomLevel: 13, control: {display: true, type: 'small'}, scrollWheelZoom: false, defaultLat: 37, defaultLng: -122, draggable: false, rendered: true};
	$.extend(this.options, options);
	this.container = $('#' + container);
	this.gMap = null; /* Instance de la google Map */
	this.gMarkers = new Array(); /* Tableau des markers GMarker */
	this.dragged = null; /* Instance du dernier GMarker deplacee */
	return this.initialize(coords);
};

gMap.prototype = {
	/**
	 * Initialize la carte
	 */
	initialize: function(){
		try {
			if(!GBrowserIsCompatible()) return this;
		} catch(e) { alert('API Google n\'est pas accessible. Verifiez : l\'API Key & les inclusions des fichiers JS dependants.'); return this; }
		(arguments.length)? this.setPoints(arguments[0]) : this.setPoints([{lat: this.options.defaultLat, lng: this.options.defaultLng}])
		
		return this.renderMap();
	}, 
	
	/**
	 * Enregistre les coordonnees dans la propriete : gMarkers - Objets Google GMarker
	 * @param {Object} coords
	 */
	setPoints: function(coords){
		this.gMarkers = ($.isArray(this.gMarkers))? this.gMarkers : new Array();
		var coords = ($.isArray(coords))? coords : [coords];
		for(var i = 0; i < coords.length; i++){
			var coord = coords[i];
			this.addPoint(new GLatLng(coord.lat, coord.lng));
		}
		return this;
	},
	
	/**
	 * Retrouve un point dans la propriete : gMarkers - Object GMarker
	 * @param {Object} gLatLng
	 */
	getPoint: function(gLatLng){
		var marker = null, gMarker = new GMarker(gLatLng);
		for(var i = 0; i < this.gMarkers.length; i++){
			if(gMarker.getLatLng() != this.gMarkers[i].getLatLng()) continue;
			else {
				marker = this.gMarkers[i];
				break;
			}	
		}
		return marker;
	}, 
	
	/**
	 * Ajoute un GMarker dans la propriete gMarkers + ajout un gestionnaire evenement dragend
	 * @param {Object} gLatLng
	 */
	addPoint: function(gLatLng){
		if(this.getPoint(gLatLng)) return;
		var options = (!this.options.draggable)? {} : {draggable: true};
		var gMarker = new GMarker(gLatLng, options);
		GEvent.addListener(gMarker, 'dragend', function(){
			this.dragged = arguments[0];
			$(this).trigger('dragend');
		}.bind(this, gMarker));
		this.gMarkers.push(gMarker);
		return this;		
	}, 
	
	/**
	 * Supprime un GMarker dans la propriete gMarkers
	 * @param {Object} gLatLng
	 */
	removePoint: function(gLatLng){
		if(!this.getPoint(gLatLng)) return;
		var gMarker = new GMarker(gLatLng), markers = new Array(), start = null;
		for(var i = 0; i < this.gMarkers.length; i++){
			if(gMarker.getLatLng() != this.gMarkers[i].getLatLng()) continue;
			else {
				start = i + 1;
				break;
			}
		}
		if(start) this.gMarkers.splice(start-1, 1);
		return this;		
	}, 
	
	/**
	 * Render de la carte avec les GMarkers enregistres
	 */
	renderMap: function(){
		if(!this.options.rendered) return this;
		if(!this.gMap){
			this.gMap = new GMap2(document.getElementById(this.container.attr('id')));
			if(!this.gMap.scrollWheelZoomEnabled() && this.options.scrollWheelZoom){
				this.gMap.enableScrollWheelZoom();
			}
			var that = this;
			GEvent.addListener(this.gMap, 'load', function(){
				$(this).trigger('gMapReady');
			}.bind(this));
		}
		return this._renderMap();
	}, 
	
	_renderMap: function(){
		this.gMap.addControl(this.getControl());
		$(this.gMarkers).each(function(){
			var marker = arguments[1] || new GMarker(new GLatLng(this.options.defaultLat, this.options.defaultLng));
			this.gMap.addOverlay(marker);
		}.bind(this));
		this.gMap.setCenter(this.getMapCenter(), this.getOptimalZoom());
		return this;
	},
	
	/**
	 * Retourne le niveau de zoom optimum pour les GMarkers affiches sur la carte
	 */
	getOptimalZoom: function(){
		var mapBounds = new GLatLngBounds(), markers = (arguments[0])? [arguments[0]] : this.gMarkers;
		for(var i = 0; i < markers.length; i++){
			var gLatLngObj = markers[i].getLatLng();
			mapBounds.extend(gLatLngObj);
		}
		var zoomLevel = this.gMap.getBoundsZoomLevel(mapBounds);
		return (markers.length && (zoomLevel < this.options.zoomLevel))? zoomLevel - 1 : this.options.zoomLevel;	
	},
	
	/**
	 * Retourne le centre de la carte en fonction des GMarkers affiches
	 */
	getMapCenter: function(){
		var mapBounds = new GLatLngBounds(), markers = (arguments[0])? [arguments[0]] : this.gMarkers;
		for(var i = 0; i < markers.length; i++){
			var gLatLngObj = markers[i].getLatLng();
			mapBounds.extend(gLatLngObj);
		}
		return mapBounds.getCenter();		
	},
	
	/**
	 * Retourne le control Google map
	 */
	getControl: function(){
		var control = new GSmallMapControl();
		switch(this.options.control.type){
			case '3D': 
				control = new GSmallZoomControl3D();
			break;
			case 'large3D':
				control = new GLargeMapControl3D();
			break;
			case 'large':
				control = new GLargeMapControl();
			break;
		}
		return control;
	}
};
