/**
 * @class Gere la carto du Voyazine
 * 
 * @author Jerome Vieilledent
 * @requires jquery 1.2.1
 * @requires themes.js
 * @requires Query plugin 1.1.1 for JQuery
 * @requires VirtualEarth v.6.1
 * @constructor
 */
function VzMap() {
	/*
	 * Proprietes
	 */
	this.idDivMap = 'virtualEarth';
	this.VEMap = null;
	this.currentShape = null;
	this.VELayer = null;
	
	// Controles de la carte
	this.zoomControl = $(VzMap.Params.Controls.ZoomControl);
	this.typeControl = $(VzMap.Params.Controls.StyleControl);
	
	// Coordonnees
	this.defaultLat = 48.52;
	this.defaultLon = 2.20;
	this.defaultZoom = 4;
	this.coord = {latitude: 0, longitude:0, zoom:0}; // Objet destine a recevoir la latitude, longitude et le niveau de zoom demandes
	
	// Parametres pour construction URL
	this.themeDestAll = 'all';
	this.aThemesDest = [];
	this.aThemesInspi = [];
	
	// Parametres passes dans l'URL
	this.paramPushProduit = $.query.get('push');
	this.getPushedDestinations(); // On n'affiche pas les memes destinations dans le menu en fonction du push inspi qui est passe
	this.paramOrdre = $.query.get('ordre');
	if (this.paramOrdre === true || !this.paramOrdre) // Fix bug Jquery.query quand le param vaut 0
		this.paramOrdre = 0;
	this.paramDest = $.query.get('dest');
	this.paramEtat = $.query.get('etat') != undefined ? $.query.get('etat') : VzMap.Params.URL.paramEtatDefaut;
	if (this.paramEtat == VzMap.Params.URL.paramEtatFull) // Affichage du moteur d'inspiration
		$(VzMap.Params.Selectors.pathMoteurInspiration).show();

	this.paramThemeDest = $.query.get('themedest');
	if (this.paramThemeDest) { // On ajoute les themes destination passes en parametre au tableau des themes destination
		var aParamsThemeDest = this.paramThemeDest.split(',');
		for (var i=0; i<aParamsThemeDest.length; i++) {
			this.aThemesDest.push(aParamsThemeDest[i]);
		}
	} else { // Pas de theme passe en parametre, on pousse le theme par defaut
		this.aThemesDest.push('top');
	}
	this.checkThemesDest();
	
	this.paramThemeInsp = $.query.get('themeinsp');
	if (this.paramThemeInsp) { // On ajoute les themes destination au tableau des themes destination
		var aParamsThemeInsp = this.paramThemeInsp.split(',');
		this.checkThemesInspi(aParamsThemeInsp);
	}
	
	/*
	 * Traitement du constructeur
	 */
	// Recuperation des coordonnees demandees
	this.coord = this.GetLatLonZoom();
	var LatLong = new VELatLong(this.coord.latitude, this.coord.longitude);
	this.VEMap = new VEMap(this.idDivMap);
	this.dispatchEvents();
	
	// Recuperation du token d'identification VE. Une fois recupere, on charge la carte
	var inst = this; // Resolution de portee de this
	$.get(VzMap.Params.URL.urlToken, function(token) {
		
		inst.VEMap.SetClientToken(token); // Implementation du token
		inst.VEMap.HideDashboard();
		inst.VEMap.LoadMap(LatLong, inst.coord.zoom, VEMapStyle.Aerial);
		inst.VEMap.SetScaleBarDistanceUnit(VEDistanceUnit.Kilometers);
		
		$(document).trigger(VzMap.Params.Events.MapLoaded); // Evenement indiquant que la carte est bien chargee
		delete inst;
	});
}

/**
 * Prototype
 */
VzMap.prototype = {
	dispatchEvents: function() {
		var inst = this;
		
		// Carte chargee
		$(document).one(VzMap.Params.Events.MapLoaded, function() {
			/* ##### ZOOM CONTROL ##### */
			inst.zoomControl.css({top: '2px', left: '22px'});
			inst.VEMap.AddControl(inst.zoomControl.get(0));
			inst._displayZoomLevel(inst.VEMap.GetZoomLevel()); // Initialisation du niveau de zoom
			
			// Clic sur les controles de zoom
			$(VzMap.Params.Selectors.pathZoomPlus).click(function() {
				var zoomLevel = inst.VEMap.GetZoomLevel();
				if (zoomLevel >= VzMap.Params.Misc.MaxZoomLevel) // Aucune action si zoom max
					return;
				
				inst._displayZoomLevel(inst.VEMap.GetZoomLevel()+1);
				inst.VEMap.ZoomIn();
			});
			$(VzMap.Params.Selectors.pathZoomMoins).click(function() {
				var zoomLevel = inst.VEMap.GetZoomLevel();
				if (zoomLevel <= 0) // Aucune action si zoom min
					return;
					
				inst._displayZoomLevel(inst.VEMap.GetZoomLevel()-1);
				inst.VEMap.ZoomOut();
			});
			
			
			/* ##### TYPE DE CARTE ##### */
			inst.typeControl.css({top: '1px', left: '285px'});
			inst.VEMap.AddControl(inst.typeControl.get(0), 10);
			
			// Clic sur un onglet
			$(VzMap.Params.Selectors.pathOngletType).click(function() {
				if ($(this).hasClass('selected')) // Onglet deja selectionne, on ne fait rien
					return;
					
				// On supprime la classe selected pour tous les liens puis on la rajoute sur le lien clique
				$(VzMap.Params.Selectors.pathOngletType).each(function() {
					$(this).removeClass('selected');
				});
				$(this).addClass('selected');
				
				var mapStyle;
				switch($(this).attr('rel')) {
					case 'road': mapStyle = VEMapStyle.Shaded; break;
					case 'aerial': mapStyle = VEMapStyle.Aerial; break;
					case 'hybrid': mapStyle = VEMapStyle.Hybrid; break;
					default: mapStyle = VEMapStyle.Shaded; break;
				}
				inst.VEMap.SetMapStyle(mapStyle);
			});
		});
	},
	
	_displayZoomLevel: function(zoomLevel) {
		$(VzMap.Params.Selectors.pathZoomLevel).attr('class', 'zoom'+zoomLevel);
	},
	
	/**
	 * Recupere les coordonnees demandees dans l'URL
	 * Les parametres d'URL attendus sont lat, lon et z
	 * Si l'un de ceux-ci n'est pas present, on prend la valeur par defaut definie plus haut.
	 */
	GetLatLonZoom: function() {
		var queryLat = parseFloat($.query.get('lat'));
		var queryLon = parseFloat($.query.get('lon'));
		var queryZoom = parseInt($.query.get('z'));
		var coord = {};
		coord.latitude = (!isNaN(queryLat)) ? queryLat : this.defaultLat;
		coord.longitude = (!isNaN(queryLon)) ? queryLon : this.defaultLon;
		coord.zoom = (!isNaN(queryZoom)) ? queryZoom : this.defaultZoom;
		
		return coord;
	},
	
	/**
	 * Pour chaque theme destination selectionne on coche la case correspondante
	 * Si une destination est passe dans l'URL, on ne coche rien 
	 */
	checkThemesDest: function() {
		if (!this.paramDest) {
			for(var i=0; i<this.aThemesDest.length; i++) {
				$('#'+this.aThemesDest[i]).attr('checked', 'checked');
			}
		}
	},
	
	checkThemesInspi: function(aThemes) {
		for(var i=0; i<aThemes.length; i++) {
			var curInput = $('#'+aThemes[i]);
			curInput.attr('checked', 'checked');
			this.gestionInspi(curInput);
		}
	},
	
	/**
	 * Gestion des themes (apparition, ajout de layer sur la carte VE...)
	 * 
	 * @param JqueryDOMObject elementDOM
	 */
	gestionTheme: function(elementDOM) {  	
	  	var id = null;
	  	var elToShow = null;
	  	var inputElement = null;
	  	
		id = elementDOM.attr('id');
  		elToShow = elementDOM.parent().attr('id').split('-')[1];
  		inputElement = elementDOM;
  		elementDOM.parent().toggleClass('expand');
	  	
	  	// On montre le sous-menu
	  	$("#submenutheme-" + elToShow).toggle();
	  	
		classePinCSS = 'pinType'+elToShow; // La classe CSS du pushpin
	},
	
	/**
	 * Gestion du moteur d'inspiration
	 * 
	 * @param JqueryDOMObject curInput Element <input> checkbox sur laquelle on a clique
	 */
	gestionInspi: function(curInput) {
		var themeProduit = curInput.attr('id');
		var checked = curInput.attr('checked');
	  	// Un theme produit est coche, on met a jour le tableau des themes produit
		if (checked) {
			this.aThemesInspi.push(themeProduit);
			
		} else { // Theme produit decoche, on le supprime du tableau des themes produit
			var index = $.inArray(themeProduit, this.aThemesInspi);
			if (index != -1)
				this.aThemesInspi.splice(index, 1);
		}
	
		/*
		 * On recupere l'attribut class de chaque lien destination et on le compare avec chaque element du tableau des themes produit
		 * S'il manque au moins une classe (match == false), on cache le lien destination courant
		 */
		var instance = this;
		$(VzMap.Params.Selectors.pathSubmenuCartoLien).each(function() {			
			var match = false;
			var curEl = $(this);
			$.each(instance.aThemesInspi, function(i, v) {
				// On verifie que le lien courant possede la classe correspondant au theme produit
				if (curEl.hasClass(this)) {
					match = true;
					return false;
				}
			});
			
			match = instance.aThemesInspi.length ? match : true; // Si le tableau des themes inspi est vide, match doit valoir true car aucune demande de theme
			var bPushedDestination = instance.checkPushedDestination(curEl);
			if (!match || !bPushedDestination) { // Pas de theme produit correspondant ou la desti ne doit pas etre affichee (push).
				$(this).parent().hide();
			} else {
				$(this).parent().show();
			}
		});
		
	},
	
	/**
	 * Gere l'affichage des destinations dans le menu en fonction du push inspi qui est passe
	 * Verifie sur chaque destination dans le menu les attributs "hotel" et "sejour" et les compare au push passe
	 */
	getPushedDestinations: function() {
		var aDestinations = $(VzMap.Params.Selectors.pathSubmenuCartoLien);
		var hotel = false;
		var sejour = false;
		var hotelSejour = false;
		switch (this.paramPushProduit) {
			case VzMap.Params.URL.paramProduitSejHot:
				hotel = true;
				sejour = true;
				hotelSejour = true;
				break;
			case VzMap.Params.URL.paramProduitSej:
				sejour = true;
				break;
			case VzMap.Params.URL.paramProduitHot:
				hotel = true;
				break;
		}
		
		aDestinations.each(function() {
			// On compare les attributs "hotel" et "sejour" avec le push
			// Si pas conforme, on masque le parent (<li>) du lien
			if (hotelSejour && $(this).attr('hotel') == 'false' && $(this).attr('sejour') == 'false')
				$(this).parent().hide();
			else if (sejour && !hotelSejour && $(this).attr('sejour') == 'false')
				$(this).parent().hide();
			else if (hotel && !hotelSejour && $(this).attr('hotel') == 'false')
				$(this).parent().hide();
		}); 
	},
	
	/**
	 * Idem que getPushedDestinations mais verifie pour un element en particulier
	 * 
	 * @param JQueryDOMObject el
	 * @return bool
	 */
	checkPushedDestination: function(el) {
		//var aDestinations = $(VzMap.Params.Selectors.pathSubmenuCartoLien);
		var hotel = false;
		var sejour = false;
		var hotelSejour = false;
		switch (this.paramPushProduit) {
			case VzMap.Params.URL.paramProduitSejHot:
				hotel = true;
				sejour = true;
				hotelSejour = true;
				break;
			case VzMap.Params.URL.paramProduitSej:
				sejour = true;
				break;
			case VzMap.Params.URL.paramProduitHot:
				hotel = true;
				break;
		}
		
		// On compare les attributs "hotel" et "sejour" avec le push
		// Si pas conforme, on masque le parent (<li>) du lien
		if (hotelSejour && el.attr('hotel') == 'false' && el.attr('sejour') == 'false')
			return false;
		else if (sejour && !hotelSejour && el.attr('sejour') == 'false')
			return false;
		else if (hotel && !hotelSejour && el.attr('hotel') == 'false')
			return false;
		else
			return true;
	},
	
	/**
	 * Recupere les POI a placer sur la carte
	 */
	getPOIs: function() {		
		urlPOI = this.getGeoRSSURL();
		// Appel du GeoRSS pour placer les pins sur la carte
		this.RemoveVELayer();
		this.AddVELayerFromGeoRSS(urlPOI/*, classePinCSS*/);
	},
	
	getGeoRSSURL: function() {
		var urlPOI = VzMap.Params.URL.urlPOI;
		var aUrlParams = [];
		
		// On vide le tableau des themes
		this.aThemesDest.splice(0, this.aThemesDest.length);
		
		// Themes destination
		var aThemesCoches = $(VzMap.Params.Selectors.pathCheckboxesThemeDest+':checked');
		if (aThemesCoches.length > 0) { // On a des themes coches, on les recupere et on les pousse dans le tableau des themes destination
			for (i=0; i<aThemesCoches.length; i++) {
				var theme = $(aThemesCoches[i]).attr('id');
				this.aThemesDest.push(theme);
			}
		}
		aUrlParams.push(VzMap.Params.URL.paramThemeDest+'='+this.aThemesDest.join(','));
		
		// Themes inspiration
		if (this.aThemesInspi.length)
			aUrlParams.push(VzMap.Params.URL.paramThemeProduit+'='+this.aThemesInspi.join(','));
			
		// Push produits
		if (this.paramPushProduit)
			aUrlParams.push(VzMap.Params.URL.paramProduit+'='+this.paramPushProduit);
			
		// Ordre produits
		if (this.paramOrdre != undefined)
			aUrlParams.push(VzMap.Params.URL.paramOrdre+'='+this.paramOrdre);
		
		// Destination
		if (this.paramDest != undefined)
			aUrlParams.push(VzMap.Params.URL.paramPOICode+'='+this.paramDest);
		
		// Construction de l'URL
		if (aUrlParams.length)
			urlPOI += '?'+aUrlParams.join('&');
		
		return urlPOI;
	},
	
	
	/*
	 * METHODES VIRTUALEARTH
	 */
	 
	/**
	 * Charge un fichier GeoRSS et ajoute un layer a la carte avec les POI issus du GeoRSS dessus
	 * @param	string	type			Type de POI (categorie). Permet de referencer le layer dans le Hash veLayers
	 * @param	string	geoRSSFile		Adresse du fichier GeoRSS
	 * @param	string	classCSSPushpin	Classe CSS qui sera utilisee pour les pushpin
	 */
	AddVELayerFromGeoRSS: function(geoRSSFile/*, classeCSSPushpin*/) {
		this.VELayer = new VEShapeLayer();
		//VzMap.Static.CSSClassPushpin = classeCSSPushpin;
		var veLayerSpecCollection = new VEShapeSourceSpecification(VEDataType.GeoRSS, geoRSSFile, this.VELayer);
		this.VEMap.ShowMessageBox = false;
		this.VEMap.ImportShapeLayerData(veLayerSpecCollection, VzMap.Static.onFeedLoad, false);
	},
	
	/**
	 * Suppression d'un layer VE
	 * @param	string	type	La categorie de POI concernee par la suppression
	 */
	RemoveVELayer: function() {
		if (this.VELayer != null) {
			this.VEMap.HideInfoBox();
			try {
				this.VEMap.DeleteShapeLayer(this.VELayer);
			} catch(e) {
				
			}
			this.VELayer = null;
		}
	},
	
	/**
	 * Affichage du detail d'un POI
	 * Centre la carte sur le POI et declenche un evenement pour afficher son infoBox
	 * @param	string		id	Identifiant de la destination (dest-%nodeID%)
	 * @param	bool		bFromSelectPays		Indique si on appelle cette methode depuis le menu deroulant des pays (facultatif)
	 * @throws	VzMapException
	 */
	affichePOI: function (destID, bFromSelectPays) {
		bFromSelectPays = bFromSelectPays == undefined ? false : bFromSelectPays;
		
		try {
			VzMap.Static.CurrentShape = VzMap.Static.Shapes[destID];
			// On bouge la carte pour afficher le POI et on affiche sa mini-fiche
			this.VEMap.AttachEvent('onchangeview', VzMap.Static.showInfoBox);
			this.VEMap.SetCenter(VzMap.Static.CurrentShape.GetPoints()[0]);
			
		} catch(e) { // Il est possible qu'on ne trouve pas l'id donne dans le layer
			
			// Si on vient du menu deroulant des pays, on verifie si le pays selectionne dans le menu pays peut etre affiche en fonction du push produit
			if (bFromSelectPays) {
				if(this.checkPushedDestination($(VzMap.Params.Selectors.pathPaysSelected))) {
					this.uncheckThemesDest();
					this.paramDest = destID; // On fait en sorte de passer l'id de la destination courante lors de l'appel au GeoRSS
					this.getPOIs();
					
					var inst = this;
					VzMap.Static.CurrentShapeID = destID;
					// On ecoute l'evenement feedLoaded pour afficher l'infobulle du POI
					$(document).one(VzMap.Params.Events.FeedLoaded, function(evt) {
						VzMap.Static.CurrentShape = VzMap.Static.Shapes[VzMap.Static.CurrentShapeID];
						inst.VEMap.SetCenter(VzMap.Static.CurrentShape.GetPoints()[0]);
					});
				} else { // Le push produit ne permet pas d'afficher le POI
					throw new VzMapException('Le POI selectionne ne peut etre affiche car le push produit ne le permet pas');
				}
			}
		}
		
	},
	
	GotoAndZoom: function(lat, lon, zoom) {
		var LatLong = new VELatLong(lat, lon);
		this.VEMap.SetCenterAndZoom(LatLong, parseInt(zoom));
		
	},
	
	/**
	 * Decoche tous les themes destination deja coches
	 */
	uncheckThemesDest: function() {
		var aThemesCoches = $(VzMap.Params.Selectors.pathCheckboxesThemeDest+':checked');
		var inst = this;
		aThemesCoches.each(function() {
			$(this).removeAttr('checked');
			inst.gestionTheme($(this));
		});
	}
	
};


/**
 * Methodes statiques
 * Stocker ici notamment les fonctions de callback a utiliser avec VE
 */
VzMap.Static = {
	// Variables membres statiques
	CSSClassPushpin: null,
	Shapes: {}, // Hash destine a contenir les POIs sous forme d'objet VEShape. L'id est celui de la destination correspondante (dest-%nodeID%)
	CurrentShape: null, // POI dont on veut afficher l'infobulle
	CurrentShapeID: null,
	ShapeToShowID: null,
	
	
	// Methodes statiques
	/**
	 * Fonction de callback appelee une fois le GeoRSS charge
	 * Va notamment permettre de donner un icone personnalisee pour le pushpin
	 * !!! Attention !!! this fait ici reference au layer VE
	 * @param	VEShapeLayer	shapeLayer	Le shapeLayer cree par VE.
	 */
	onFeedLoad: function(shapeLayer) {
		VzMap.Static.Shapes = {}; // On vide le hash de POI
		// On boucle sur les POIs presents sur le layer
		for (var i=0; i<shapeLayer.GetShapeCount();i++) {
			var shape = shapeLayer.GetShapeByIndex(i);
			
			// Dans le <title> sont passes egalement le theme destination et le theme produit du POI, necessaires pour recuperer le picto du pushpin
			var aShapeTitle = shape.GetTitle().split(VzMap.Params.Misc.GeoRSSTitleSeparator);
			var pushpinTitle = aShapeTitle[0];
			var pushpinPOICode = aShapeTitle[1]; // Le nodeID de la destination, pour identifier le POI et le relier avec le menu de gauche
			var pushpinThemeDest = aShapeTitle[2] != undefined ? aShapeTitle[2] : '';
			var pushpinThemeInspi = aShapeTitle[3] != undefined ? aShapeTitle[3] : '';
			var pushpinImgSrc = null;
			
			if (pushpinThemeDest && pushpinThemeInspi) // On a le theme destination et le theme inspi, on construit le nom du picto correspondant
				pushpinImgSrc = VzMap.Params.Misc.DossierImagesPushpin+'carto_'+pushpinThemeDest+'_'+pushpinThemeInspi+'.png';
			else // Picto par defaut du theme destination
				pushpinImgSrc = VzMap.Params.Misc.DossierImagesPushpin+'carto_'+pushpinThemeDest+'_nul.png';
			
			var iconPushpin = '<div class="pinDestination"><img src="'+pushpinImgSrc+'" alt="'+pushpinTitle+'" /></div>';
			shape.SetCustomIcon(iconPushpin);
			shape.SetTitle('');
			
			// On stocke le POI dans le hash
			VzMap.Static.Shapes[pushpinPOICode] = shape;
		}
		
		setTimeout("$('#virtualEarth').pngFix();", 200); // Patch pour le PNG 24 sous IE6
		$(document).trigger(VzMap.Params.Events.FeedLoaded);
		return false;
	},
	
	/**
	 * Affichage de l'infoBox d'un POI
	 * Declenche par un evenement
	 * @param	event	e	Evenement qui a declenche la fonction
	 */
	showInfoBox: function(e) {
		Map.VEMap.HideInfoBox();
		setTimeout("Map.VEMap.ShowInfoBox(VzMap.Static.CurrentShape)", 400);
		Map.VEMap.DetachEvent('onchangeview', VzMap.Static.showInfoBox);
	}
};

/**
 * Parametres de configuration
 */
VzMap.Params = {
	URL: {
		urlPOI: '/voyazine/searchPoisGeoloc.do',
		urlToken: '/voyazine/getVirtualEarthToken.do',
		paramProduit: 'produit',
		paramProduitSej: 'SEJ',
		paramProduitHot: 'HOT',
		paramProduitSejHot: 'SEJ_HOT',
		paramThemeDest: 'poiThemes',
		paramThemeProduit: 'produitThemes',
		paramPOICode: 'poiCode',
		paramOrdre: 'ordre',
		paramEtatStandard: 'std',
		paramEtatFull: 'full',
		paramEtatDefaut: 'std'
	},
	
	Selectors: {
		pathSubmenuCarto: '#carto .submenu-carto',
  		pathSubmenuCartoLien: '#carto .submenu-carto li a',
  		pathNimporteOu: '#nimporte_ou',
  		pathTousThemes: '#tous-inspiration',
  		pathMoteurInspiration: '#carto #moteur-inspiration',
  		pathCheckboxesThemeDest: '#carto input.checkboxTheme',
  		pathPaysSelected: '#select-pays option:selected',
  		pathZoom: '#zoom',
  		pathZoomLevel: '#zoom #zoomLevel',
  		pathZoomPlus: '#zoom #zoom_plus',
  		pathZoomMoins: '#zoom #zoom_moins',
  		pathType: '#virtualEarth #type',
  		pathOngletType: '.ongletTypeCarte'
	},
	
	Misc: {
		GeoRSSTitleSeparator: ' ~ ',
		DossierImagesPushpin: '/extension/noven_voyazine/design/voyazine/images/carto/',
		MaxZoomLevel: 19
	},
	
	Events: {
		MapLoaded: 'mapLoaded',
		FeedLoaded: 'feedLoaded'
	},
	
	Controls: {
		ZoomControl: '<div id="zoom"><div>' +
				'<p class="niveaux"><a href="javascript:;" id="zoom_moins"><img src="/extension/noven_voyazine/design/voyazine/images/carto/zoom_moins.gif" class="moins" alt="moins" /></a><span class="zoom4" id="zoomLevel">&nbsp</span><a href="javascript:;" id="zoom_plus"><img src="/extension/noven_voyazine/design/voyazine/images/carto/zoom_plus.gif" class="plus" alt="plus" /></a></p>' +
				'<p class="vue"><a href="javascript:;"><img src="/extension/noven_voyazine/design/voyazine/images/carto/zoom_petite_carto.gif" alt="" /></a>Vue g&eacute;n&eacute;rale</p>' +
				'</div></div>',
		StyleControl: '<div id="type">' +
				'<a href="javascript:;" class="ongletTypeCarte" rel="road">Routes</a><a href="javascript:;" class="centre selected ongletTypeCarte" rel="aerial">A&eacute;rien</a><a href="javascript:;" class="ongletTypeCarte" rel="hybrid">Hybride</a>' +
				'</div>'
	}
}

/**
 * Exceptions
 */
function VzMapException(message) {
	this.message = message;
	this.name = 'VzMapException';
}


// Referencement de l'objet Map pour y acceder dans les autres scripts lies
var Map = null;
$(document).ready(function() {
	setTimeout('Map = new VzMap();', 300);
});