

/**
 *    Classe permettant de gérer unee goolgleMAP.
 *    Version nouvelle du fichier gmapME afin de pouvoir gérer de maniere générique les évenements sur les markers.
 *       + suppression des variables globales JS.
 *
 *
 *       var mapPointsArray=normalizeJSONArray(
 *         [
 *           {"lat": 48.85656, "lng": 2.350966, "nameVille" : "Paris", "idVille" : "5580", "champ": "departAllerData"},
 *           {"lat": 37.080002, "lng": 25.15, "nameVille" : "Paros", "idVille" : "5581", "champ": "departAllerData"},
 *           {"lat": 43.110703, "lng": 12.389172, "nameVille" : "Perouse", "idVille" : "5654", "champ": "departAllerData"},
 *         ]
 *       );
 */
(function() {
	var window = this,
			ev = window.ev,
			document = window.document,
			Math = window.Math;

	if (!ev) { throw 'mev.searchHistoryManager#<init>: Needs ev.core module!'; }
	if (!ev.mev) {ev.mev = {};}
	ev.mev.gmapMEV = [];

	/* Variable interne conteannt les lieux à afficher sur la map */
	var mapPointsArray;

	/**
	 * Méthode à appeler avant tout utilisation. Permet d'initialiser la variable interne contenant tous les points a afficher sur la map.
	 * @param {Object} _mapPointsArray
	 */
	ev.mev.gmapMEV.init = function(_mapPointsArray) {
		mapPointsArray = _mapPointsArray;
	};


	/**
	 * Object permettant de stocker un intervalle de valeurs sous forme d'une paire numérique
	 * valeur minimale et valeur maximale.
	 */
	function MinMax(_min,_max) {
		var min = _min,
				max = _max;

		this.getMean = function() {
			return (min + max) / 2.0;
		};
		this.getDelta = function() {
			return max - min;
		};
	}

	/**
	 * Cette fonction permet de calculer les latitudes min et max des points listés dans la variable
	 * globale mapPointsArray stockées dans une structure MinMax. Dans le cas où cette variable ne
	 * contiendrait aucun point, la fonction retourne les latitudes -90 à 90.
	 */
	ev.mev.gmapMEV.getLatMinMax = function() {
		// Si mapPointsArray est vide
		if (!mapPointsArray.length) { return new MinMax(-90.0, 90.0); }
		// toute valeur de latitude (par définition inférieure à 90) diminuera
		var latMin = 90, i;
		for (i = 0; i < mapPointsArray.length; i++) {
			if (mapPointsArray[i].lat < latMin) {
				latMin = mapPointsArray[i].lat;
			}
		}
		// Même principe pour latMax que pour latMin
		var latMax = -90;
		for (i = 0; i < mapPointsArray.length; i++) {
			if (mapPointsArray[i].lat > latMax) {
				latMax = mapPointsArray[i].lat;
			}
		}
		// Si le tableau mapPointsArray était vide latMin=90, latMax=-90, et la moyenne vaut bien zéro.
		return new MinMax(latMin, latMax);
	};

	function triNum(a,b) {
		return a - b;
	}

	/**
	 * Cette fonction permet de calculer les longitudes min et max des points listés dans la variable
	 * globale mapPointsArray stockées dans une structure MinMax. Dans le cas où cette variable ne
	 * contiendrait aucun point, la fonction retourne les latitudes -180 à 180.
	 */
	ev.mev.gmapMEV.getLngMinMax = function() {
		if (!mapPointsArray.length) { return new MinMax(-180, 180); }
		if (mapPointsArray.length === 1) { return new MinMax(mapPointsArray[0].lng, mapPointsArray[0].lng); }
		var lngSortedArray = [], i;
		for (i = 0; i < mapPointsArray.length; i++) {
			lngSortedArray.push(mapPointsArray[i].lng);
		}
		lngSortedArray.sort(triNum);
		// On va chercher l'index du delta maximal, i.e. le point dont l'élongation angulaire est
		// maximale avec son prédécesseur.
		var indexDeltaMax = 0,
				deltaMax = lngSortedArray[0] - lngSortedArray[lngSortedArray.length - 1] + 360,
				delta;
		for (i = 1; i < lngSortedArray.length; i++) {
			delta = lngSortedArray[i] - lngSortedArray[i - 1];
			if (delta > deltaMax) {
				deltaMax = delta;
				indexDeltaMax = i;
			}
		}
		var lngMin = lngSortedArray[indexDeltaMax],
				lngMax;
		if (indexDeltaMax) {
			lngMax = lngSortedArray[indexDeltaMax - 1];
		}
		else {
			lngMax = lngSortedArray[lngSortedArray.length - 1];
		}
		if (lngMin > lngMax) {
			lngMax += 360;
		}
		return new MinMax(lngMin, lngMax);
	};

	/**
	 * Cette fonction permet de définir le zoom optimal en fonction de l'écart des
	 * longitudes maximums et minimums
	 */
	function getZoomX(lngMinMax) {
		var width = document.getElementById('map').style.width;
		width = width.substring(0, 3);
		return Math.log(width * 180 / 40.93 / lngMinMax.getDelta() / Math.PI) / Math.LN2;
	}

	/**
	 * Cette fonction permet de définir le zoom optimal en fonction de l'écart des
	 * latitudes maximums et minimums
	 */
	function getZoomY(latMinMax) {
		var height = document.getElementById('map').style.height;
		height = height.substring(0, 3);
		return Math.log(height * 180 * Math.cos(latMinMax.getMean() * Math.PI / 180) / 40.93 / latMinMax.getDelta() / Math.PI) / Math.LN2;
	}

	/**
	 * Cette fonction définit le niveau de zoom en prenant la plus petite valeur entre
	 * les zooms optimaux des longitudes et latitudes, et un niveau de zoom maximum.
	 * Valeurs indicatives pour le zoomMax : 3 pour un continent, 5/6 pays, 7/8 region,
	 * 9/10/11 agglo, 11/12/13 ville, 14/15 quartier, 16/17 Rue.
	 */
	function getZoomMax(lngMinMax,latMinMax,zoomMax) {
		var Zx = getZoomX(lngMinMax),
				Zy = getZoomY(latMinMax);
		zoomMax = Math.max(1, Math.min(17, zoomMax));
		return Math.floor(Math.min(Zx, Zy, zoomMax));
	}

	/**
	 * Cette fonction définit le niveau de zoom en prenant la plus petite valeur entre
	 * les zooms optimals des longitudes et latitudes
	 * fait appel à la fonction getZoom(lngMinMax,latMinMax,zoomMax)
	 * préréglé sur un niveau de zoomLMax=17 ( vue sur une rue )
	 */
	ev.mev.gmapMEV.getZoom = function(lngMinMax,latMinMax) {
		return getZoomMax(lngMinMax, latMinMax, 17);
	};

	/**
	 * Construicteur de Marker.
	 *
	 * @constructor
	 * @param {Object} gpoint coordonnées du point.
	 * @param {Object} nameVille nom de l'évenement. ( générifier ....).
	 * @param {Object} imgMarker image à utiliser pour la representation du point.
	 * @param {Object} codeVille code iata du lieu  ( générifier .... ).
	 * @param {Object} id id du lieu. (générifier ....).
	 * @param {Object} GMAP_MARKER_EVTS tableau associatif contenant des pointers de fonction.
	 *            var exemple = [{'click':doOnclick},{'mouseover':onMouseover}].
	 *
	 */
	function Marker(gpoint, nameVille, imgMarker,codeVille,id,GMAP_MARKER_EVTS) {
		var parent = this,
				self = new window.GMarker(this.gpoint, {icon: imgMarker, draggable: false, bouncy: false, dragCrossMove: false});

		parent.gpoint = gpoint;
		parent.nameVille = nameVille;
		parent.codeVille = codeVille;
		parent.idLieu = id;
		parent.gmarker = self;

		/**
		 * Listener sur l'évenement onclick du marker de la googleMap.
		 *
		 */
		window.GEvent.addListener(self, 'click', function() {
			if (GMAP_MARKER_EVTS.click) {
				GMAP_MARKER_EVTS.click(parent);
			}
		});

		/**
		 * Cette fonction permet lors du passage du curseur sur un marqueur d'afficher dans une
		 * div le nom de la ville correspondate
		 */
		window.GEvent.addListener(self, 'mouseover', function() {
			document.getElementById('infoBox').innerHTML = nameVille;
			document.getElementById('infoBox').style.display = 'block';
			if (GMAP_MARKER_EVTS.mouseover) {
				GMAP_MARKER_EVTS.mouseover(parent);
			}
		});

		/**
		 * Cette fonction permet lors du mouseout sur le marqueur de faire disparaitre
		 * la div précédement affichée
		 */
		window.GEvent.addListener(self, 'mouseout', function() {
			document.getElementById('infoBox').style.display = 'none';
			if (GMAP_MARKER_EVTS.mouseout) {
				GMAP_MARKER_EVTS.mouseout(parent);
			}
		});
	}

	/**
	 * Cette fonction permet de créer et de positionner des marqueurs sur la carte
	 */
	ev.mev.gmapMEV.transfertLatLngToElement = function(map, markers, latLngArray, imgMarker, GMAP_MARKER_EVTS) {
		for (var i = 0; i < latLngArray.length; i++) {
			markers[i] = new Marker(new window.GLatLng(latLngArray[i].lat, latLngArray[i].lng), latLngArray[i].nameVille, imgMarker, latLngArray[i].codeVille, latLngArray[i].idVille, GMAP_MARKER_EVTS);
			map.addOverlay(markers[i].gmarker);
		}
	};
}());

