/**
* Fichier	: marqueurs.js
* Contenu	: Code javascript contenant les fonctions liées au geocoding et aux marqueurs
* Date		: 24/08/10
* @author	Gael Sauvanet
* @version	1.0
*/

var geocoder = null;		// objet de géocodage de google maps
var totalBounds;		// bounds gmaps sur lequel le geocoder travaille
var nbEtapes = 0;		// nombre d'étapes dans l'itinéraire
var markerDepart, markerArrivee;		// Marqueur départ et arrivée
var defItineraire = new Object();
defItineraire.ListemarkerEtape=new Array();		// Liste des marqueurs étape
defItineraire.lat1=MARKER1_LAT;
defItineraire.lat2=MARKER2_LAT;
defItineraire.lon1=MARKER1_LON;
defItineraire.lon2=MARKER2_LON;				// Positions des marqueurs
var ancienItineraire = defItineraire;	// Ancien itinéraire
var derniereAdresse = '';			// Valeur de la dernière adresse entrée
var defItineraireAutre = new Object();
defItineraireAutre.lat1=0;
defItineraireAutre.lat2=0;
defItineraireAutre.lon1=0;
defItineraireAutre.lon2=0;
defItineraireAutre.etapes=new Array();

/** 
* Drag & drop des étapes en jquery
*/
function initialiserDragAndDrop()
{
	$j(function() {

		$j("#etapes2").sortable({
			revert: true,
			axis: 'y', 
			opacity: 0.6, 
			placeholder: 'ui-state-highlight', 
			items: '.draggable',
			containment: 'parent'
		});

		$j( "#etapes2" ).sortable({
			change: function(event, ui) {
				id=$j(ui.item).attr('id'); 
				num=parseInt(id.substring(5,6)); 
				pos2=event.pageY; 
				if (pos2-pos1>0) switchEtape(num,num+1);
				else switchEtape(num,num-1);
				pos1=pos2;
			}
		});

		$j( "#etapes2" ).sortable({
			start: function(event, ui) {
				pos1=event.pageY;
			}
		});


		$j( "#etapes2" ).sortable({
			update: function(event, ui) {
				demandeServer(); 
			}
		});
		
	});
}

/**
 * Fonction pour activer l'autocomplétion sur un champs texte
 */
function activerAutoCompletion(champs,num)
{
	$j(function() {
		champs.autocomplete({
			//This bit uses the geocoder to fetch address values
			source: function(request, response)
			{
				geocoder.geocode( {'region': 'FR', 'bounds':totalBounds , 'address': 'france, ' + ZONE_GEOCODING + ', ' + request.term}, function(results, status)
				{
					response($j.map(results, function(item)
					{
				    		if((item.geometry.location.lat() <= MAX_LAT) && (item.geometry.location.lat() >= MIN_LAT) && (item.geometry.location.lng() <= MAX_LON) && (item.geometry.location.lng() >= MIN_LON))
				    			return {
							      label: item.formatted_address,
							      value: item.formatted_address
				    			}
				  	}));
				})
			},
			//This bit is executed upon selection of an address
			select: function(event, ui) {
					voirAdresse(champs.val(),num);
			}
		});
	});
}

/**
 * Initialise l'outil de géocodage
 */
function initialiserGeocoder()
{
	// Initialisation de l'outil de géocodage de Google Maps
	geocoder = new google.maps.Geocoder();

	// Initialisation Drag&Drop des étapes
	initialiserDragAndDrop();

	// Test autocompletion
	totalBounds = new google.maps.LatLngBounds();
	var startPoint = new google.maps.LatLng(MIN_LAT, MIN_LON);
	var endPoint = new google.maps.LatLng(MAX_LAT, MAX_LON);

	totalBounds.extend(startPoint);
	totalBounds.extend(endPoint);

	initialiserAutoCompletion();
}

function initialiserAutoCompletion()
{
	activerAutoCompletion($j("#adresseDepart"),-2);
	activerAutoCompletion($j("#adresseArrivee"),-1);
	activerAutoCompletion($j("#adresseEtape1"),1);
	activerAutoCompletion($j("#adresseEtape2"),2);
	activerAutoCompletion($j("#adresseEtape3"),3);
}


/**
 * Recherche l'adresse du point de départ
 */
function geocoderPosition(lat,lon,type,numEtape)
{
	var champTexte,champStatique;
	if(type== 'depart')
	{
		champTexte ="#adresseDepart";
		champStatique = "#adresse_depart";
	}
	else if(type== 'arrivee')
	{
		champTexte ="#adresseArrivee";
		champStatique = "#adresse_arrivee";
	}
	else if(type == 'etape')
	{
		champTexte ="#adresseEtape"+numEtape;
		champStatique = "#adresse_etape"+numEtape;
	}	

    if (geocoder) {
      var latlng = new google.maps.LatLng(lat, lon);
      geocoder.geocode({'latLng': latlng}, function(results, status) {

        if (status == google.maps.GeocoderStatus.OK) {

          if (results[0]) {
			
			var result = results[0].formatted_address;
			if(dynamic){
				$j(champTexte).val(result);
				$j("#etape"+numEtape).addClass("draggable");
				$j(champStatique).html(result);
			}
			else
			{
				$j(champStatique).val(result);
				$j(champStatique).html(result);
			}
          }
        } else {
          alert("Geocoder failed due to: " + status + "\nlat = "+lat+"\nlon = "+lon);
        }
      });
    }
    cacherAstuce();
}

/**
 * Positionne un marqueur sur une étape à l'adresse indiquée
 * 
 * @param address l'adresse
 * @param numEtape le numéro de l'étape
 */
function voirAdresse(address,numEtape) {
	address = address.toLowerCase();
	if(address.indexOf(ZONE_GEOCODING) == -1)
		address += " " + ZONE_GEOCODING;

	if (geocoder) {
		geocoder.geocode( { 'address': address}, function(results, status) {
			if (status == google.maps.GeocoderStatus.OK) {
				place = results[0];

				// On récupère la position géographique du premier résultat
				point = place.geometry.location;

				// Supprimer les itinéraires						
				supprimerItineraires();
				// On lance la fonction xajax de sélection de noeud
				if(numEtape == -2)
					xajax_selectionnerNoeud(point.lng(),point.lat(),'depart');
				else if(numEtape == -1)
					xajax_selectionnerNoeud(point.lng(),point.lat(),'arrivee');
				else
					xajax_selectionnerNoeud(point.lng(),point.lat(),'etape',numEtape);
				
				var nomElt;
				if(numEtape == -2)
					nomElt = "adresseDepart"
				else if(numEtape == -1)
					nomElt = "adresseArrivee"
				else
					nomElt = "adresseEtape"+numEtape;
				var nouvelleAdresse = "";
				nouvelleAdresse = place.formatted_address;
				document.getElementById(nomElt).value = nouvelleAdresse;
			} else {
          			alert("Geocode was not successful for the following reason: " + status);
        		}
      		});
    	}
}

/**
 * Affiche le div astuce
 */
function voirAstuce(num)
{
	$j('#divastuce').show();
	for(var i = 0; i < 4; i++)
	{
		if(num == i)
			$j("#astuce-texte"+i).show();
		else
			$j("#astuce-texte"+i).hide();		
	}
}

/**
 * Cache le div astuce
 */
function cacherAstuce()
{
	$j('#divastuce').hide(); 
}

/**
 * Calcul d'un itinéraire retour
 */
function itineraireRetour()
{
	// Inversion départ et arrivée
	arrivee=$j("#adresseDepart").val(); // ancienne valeur de départ
	depart=$j("#adresseArrivee").val(); // ancienne valeur d'arrivée
	$j("#adresseDepart").val(depart); // L'ancien arrivée devient le départ
	$j("#adresseArrivee").val(arrivee); // L'ancien départ devient l'arrivée

	lonlatD = new OpenLayers.LonLat(markerDepart.geometry.x,markerDepart.geometry.y); // Position de l'ancien marker de départ
	lonlatA = new OpenLayers.LonLat(markerArrivee.geometry.x,markerArrivee.geometry.y); // Position de l'ancien marker d'arrivée
	lattemp=defItineraire.lat1;
	lontemp=defItineraire.lon1;
	defItineraire.lat1=defItineraire.lat2;
	defItineraire.lon1=defItineraire.lon2;
	defItineraire.lat2=lattemp;
	defItineraire.lon2=lontemp;

	markerDepart.geometry.move((lonlatA.lon-lonlatD.lon),(lonlatA.lat-lonlatD.lat)); // La position de départ devient l'ancienne position d'arrivée
	markerArrivee.geometry.move((lonlatD.lon-lonlatA.lon),(lonlatD.lat-lonlatA.lat)); // La position d'arrivée devient l'ancienne position de départ
	layerMarkers.drawFeature(markerDepart); // On redessine le marker départ
	layerMarkers.drawFeature(markerArrivee); // On redessine le marker arrivée

	// Si il y a des étapes, il faut inverser leur ordre (ex:1 2 3 -> 3 2 1)
	if (defItineraire.ListemarkerEtape!=null)
	{
		// on retourne la liste des étapes
		var markersEtapes = Array();
		for(var i = 0; i < nbEtapes; i++)markersEtapes[i+1] = defItineraire.ListemarkerEtape[nbEtapes-i];
		defItineraire.ListemarkerEtape = markersEtapes;
		for(var i = 1; i <= nbEtapes; i++)
		{
			defItineraire.ListemarkerEtape[i].attributes.nom = 'etape'+(i); 
			defItineraire.ListemarkerEtape[i].style = iconEtape[i];
			layerMarkers.addFeatures(defItineraire.ListemarkerEtape[i]);
		}
		// on échange les valeurs des champs texte
		var adressesEtapes = Array();
		for(var i = 0; i < nbEtapes; i++)adressesEtapes.push($j("#adresseEtape"+(i+1)).val());
		for(var i = 0; i < nbEtapes; i++)$j("#adresseEtape"+(i+1)).val(adressesEtapes[nbEtapes-1-i]);
	}	

	// Calcul du nouvel itinéraire
	demandeServer();
}


/**
 * Ajout d'une étape dans l'interface (colonne de gauche)
 * 
 */
function ajouterEtape(num)
{
	if (nbEtapes<NB_ETAPES_MAX) // On limite pour le moment le nombre d'étapes à 5
	{
		if (nbEtapes==0 || (dynamic && nbEtapes>0 && $j("#adresseEtape"+nbEtapes).val()!=""))
		{		
			nbEtapes+=1;
			if (dynamic)
			{
				$j("#etape"+nbEtapes).show(); // on affiche un formulaire supplémentaire
				$j("#etape"+nbEtapes).addClass("vide");
				$j("#adresseEtape"+nbEtapes).focus();
				if (nbEtapes==NB_ETAPES_MAX) 
				{
					$j("#myMenu").disableContextMenuItems('#etape');
					$j("#etapes_ajout1").hide();
					$j("#etapes_ajout2").hide();
				}
			}
		}
		return true;
	}
	else
		return false;
}

/**
 * Ajout d'une étape à partir des coordonnées du point
 * @param lon longitude du point
 * @param lat latitude du point
 */
function ajouterEtapeCoord(lon,lat)
{
	ajout=ajouterEtape(0);
	if (ajout)
		xajax_selectionnerNoeud(lon,lat,'etape',nbEtapes);
	else
		messageModal("Impossible d'ajouter une étape supplémentaire.");
}

/**
 * Interversion de deux étapes. Utilisé pour le drag and drop des étapes
 * 
 * @param i Le numéro de l'étape que l'on déplace
 * @param j Le numéro de l'étape que l'on va remonter ou descendre pour laisser la place à i
 */
function switchEtape(i,j)
{
	// Switch des markers
	var EtapeTemp=defItineraire.ListemarkerEtape[i]; // Buffer contenant l'étape i
	defItineraire.ListemarkerEtape[i]=defItineraire.ListemarkerEtape[j];
	defItineraire.ListemarkerEtape[i].attributes.nom='etape'+(i);
	defItineraire.ListemarkerEtape[i].style = iconEtape[i];
	defItineraire.ListemarkerEtape[j]=EtapeTemp;
	defItineraire.ListemarkerEtape[j].attributes.nom='etape'+(j);
	defItineraire.ListemarkerEtape[j].style = iconEtape[j];
	layerMarkers.redraw();
	// Switch des blocs dans l'interface. (ex: on avait bloc1, bloc2. On a bloc2,bloc1)

	// On remet les ID dans l'ordre
	$j("#etape"+j).attr("id","etapetemp"); // On retire l'ID du block contenant l'étape j dans l'interface
	$j("#etape"+i).attr("id","etape"+j); // Comme il n'existe plus de bloc ayant l'ID "etapej", on peut donner ce nom au block contenant l'adresse de i
	$j("#etapetemp").attr("id","etape"+i); // Comme il n'existe plus de bloc "etapei", on l'affecte au bloc contenant l'adresse de j
	
	// Sauvegarde des adresses
	Adresse1=$j("#adresseEtape"+i).val(); // On sauvegarde l'adresse de i
	Adresse2=$j("#adresseEtape"+j).val(); // On sauvegarde l'adresse de j

	// Le bloc2 est devenu bloc1 mais il contient toujours des name ou des fonctions du type "validerEtape2".
	// On lui donne le contenu de l'ancien bloc1
	temp=$j("#etape"+j).html(); // On sauvegarde le contenant du bloc "etapej" qui a cet instant contient les infos de l'ancien bloc "etapei"
	$j("#etape"+j).html($j("#etape"+i).html()); // On lui affecte les infos de l'ancien bloc "etapej"
	$j("#etape"+i).html(temp); // On affecte au nouveau bloc "etapei" les informations de l'ancien bloc "etapei"

	// On réaffecte les valeurs du champs adresse qui est perdu avec l'utilisation de innerHTML
	$j("#adresseEtape"+i).val(Adresse2); 
	$j("#adresseEtape"+j).val(Adresse1);

	initialiserAutoCompletion();
	demandeServer();
}



/**
 * Suppression d'une étape dans l'interface	
 * @param num le numéro de l'étape à supprimer
 */
function supprimerEtape(num)
{
	var relancerCalcul = true;
	if (nbEtapes==NB_ETAPES_MAX)
	{
		$j("#myMenu").enableContextMenuItems('#etape');
		$j("#etapes_ajout1").show();
		$j("#etapes_ajout2").show();
	}

	$j("#etape"+nbEtapes).hide(); // On cache le bloc de l'étape
	$j("#etape"+nbEtapes).removeClass("vide");

	if($j("#adresseEtape"+num).val() == "")
		relancerCalcul = false;

	// Si ce n'est pas la dernière étape qu'on supprime, on shift toutes les étapes suivantes d'un cran vers la gauche (ex: etape3 -> etape2)
	if (num!=nbEtapes)
		for (i=num;i<nbEtapes;i++)
		{
			$j("#adresseEtape"+i).val($j("#adresseEtape"+(i+1)).val());
			defItineraire.ListemarkerEtape[i+1].attributes.nom = 'etape'+(i);
			defItineraire.ListemarkerEtape[i+1].style = iconEtape[i];
			layerMarkers.addFeatures(defItineraire.ListemarkerEtape[i+1]);
		}

	// On supprime de l'interface une étape et on efface la rue concernée
	$j("#adresseEtape"+nbEtapes).val("");
	nbEtapes--;

	// la fonction splice permet de supprimer un élément d'une liste (ou une sous-liste d'une liste) puis compacte la liste résultat
	layerMarkers.removeFeatures(defItineraire.ListemarkerEtape[num]); // Suppression du marker étape X sur le calque
	defItineraire.ListemarkerEtape.splice(num,1); // Suppression du marker étape X dans la liste des markers

	if(relancerCalcul)
		demandeServer() // On calcule le nouvel itinéraire
}


/**
 * Positionne le marqueur de départ sur un noeud
 */
function setPositionDepart(latitude,longitude,requete)
{
	lonlat = new OpenLayers.LonLat(longitude,latitude);
	ll2 = new OpenLayers.LonLat(markerDepart.geometry.x,markerDepart.geometry.y);
	ll = LonLatToM(lonlat);

	markerDepart.geometry.move((ll.lon-ll2.lon),(ll.lat-ll2.lat));
	layerMarkers.drawFeature(markerDepart);

	defItineraire.lat1 = latitude;
	defItineraire.lon1 = longitude;

	// Positionner la carte
	bounds_itineraire = map.getExtent();
	if(!(bounds_itineraire.containsLonLat(ll2)))
	{
		bounds_itineraire = new OpenLayers.Bounds();
		bounds_itineraire.extend(lonlat);
		bounds_itineraire.extend(LonLatToM(new OpenLayers.LonLat(defItineraire.lon2,defItineraire.lat2)));
		map.zoomToExtent(bounds_itineraire);
	}

	// On cherche l'adresse correspondant au point géographique
	geocoderPosition(defItineraire.lat1,defItineraire.lon1,'depart');
	if(requete)demandeServer();
}

/**
 * Positionne le marqueur d'arrivée sur un noeud
 */
function setPositionArrivee(latitude,longitude,requete)
{
	lonlat = new OpenLayers.LonLat(longitude,latitude);
	ll2 = new OpenLayers.LonLat(markerArrivee.geometry.x,markerArrivee.geometry.y);
	ll = LonLatToM(lonlat);

	markerArrivee.geometry.move((ll.lon-ll2.lon),(ll.lat-ll2.lat));
	layerMarkers.drawFeature(markerArrivee);

	defItineraire.lat2 = latitude;				
	defItineraire.lon2 = longitude;

	// Positionner la carte
	bounds_itineraire = map.getExtent();
	if(!(bounds_itineraire.containsLonLat(ll2)))
	{
		bounds_itineraire = new OpenLayers.Bounds();
		bounds_itineraire.extend(lonlat);
		bounds_itineraire.extend(LonLatToM(new OpenLayers.LonLat(defItineraire.lon1,defItineraire.lat1)));
		map.zoomToExtent(bounds_itineraire);
	}

	// On cherche l'adresse correspondant au point géographique
	geocoderPosition(defItineraire.lat2,defItineraire.lon2,'arrivee');
	if(requete)demandeServer();
}

/**
 * Positionne le marqueur d'etape numero X sur un noeud
 */
function setPositionEtape(latitude,longitude,numero,requete)
{
	var latE = latitude;				
	var lonE = longitude;
	// On récupère la nouvelle position
	lonlat = new OpenLayers.LonLat(longitude,latitude);

	if (typeof(defItineraire.ListemarkerEtape[numero]) == 'undefined' || defItineraire.ListemarkerEtape[numero] == null) // Si cette étape n'a pas encore été définie, on créé
	{
		// Création du marker
		defItineraire.ListemarkerEtape[numero] = new OpenLayers.Feature.Vector(LonLatToPoint(LonLatToM(new OpenLayers.LonLat(lonE,latE))),null,iconEtape[numero]);
		defItineraire.ListemarkerEtape[numero].attributes.nom = 'etape'+numero;

		// Ajout du marker au calque
		layerMarkers.addFeatures(defItineraire.ListemarkerEtape[numero]);
	}
	else
	{
		ll2 = new OpenLayers.LonLat(defItineraire.ListemarkerEtape[numero].geometry.x,defItineraire.ListemarkerEtape[numero].geometry.y);
		ll = LonLatToM(lonlat);

		// On deplace le marqueur sur le calque
		defItineraire.ListemarkerEtape[numero].geometry.move((ll.lon-ll2.lon),(ll.lat-ll2.lat));
		// Positionner la carte
		bounds_itineraire = map.getExtent();
		if((!bounds_itineraire.containsLonLat(ll2)))
		{
			bounds_itineraire = new OpenLayers.Bounds();
			bounds_itineraire.extend(lonlat);
			bounds_itineraire.extend(LonLatToM(new OpenLayers.LonLat(lonE,latE)));
			map.zoomToExtent(bounds_itineraire);
		}
	}
	layerMarkers.drawFeature(defItineraire.ListemarkerEtape[numero]);
	
	$j.ajax( {
		type : "GET",
		url : "get_poi.php",
		data : {
			'lon' : lonE,
			'lat' : latE,
			'nearifexists':1
		},
		success : function(msg) {
			var reader = new OpenLayers.Format.KML();
			data = reader.read(msg);
			if(data.length == 1)
			{
				defItineraire.ListemarkerEtape[numero].attributes.poi = data[0].attributes.nom;
				$j("#label_etape_fdr_"+numero).html(data[0].attributes.nom);
			}
			else
			{
				defItineraire.ListemarkerEtape[numero].attributes.poi = "";
			}
		}
	});

	$j("#etape"+numero).show();

	// On cherche l'adresse correspondant au point géographique
	geocoderPosition(latE,lonE,'etape',numero);
	if(requete)demandeServer();
}


function xajax_selectionnerNoeud(lon,lat,type,numEtape)
{
	if(type == 'depart')
		setPositionDepart(lat,lon,true)
	else if(type == 'arrivee')
		setPositionArrivee(lat,lon,true)
	else if(type == 'etape')
		setPositionEtape(lat,lon,numEtape,true);
}

/**
 * Basculer entre defItineraire et defItineraireAutre
 */
function swapItineraire()
{
	var temp = sauver();
	restaurer(defItineraireAutre);
	defItineraireAutre = temp;
}

