dojo.require('actijscore.parser');

dojo.provide('gmap.src');

dojo.declare( 'gmap.src', null,
{
    domNode: null,	    // Noeud où placer la carte
    domErr: null,	    // Noeud où afficher les erreurs js (xhr)
    gmap: null,
    county: 75,		    // Numéro du département
    insee: 0,		    // Code insee de la commune
    id: 0,		    // Identifiant du GMapLocation protégé du clustering
    program_id: 0,	    // Identifiant du programme

    ignoreIdle: false,	    // Ignorer ou non l'événement : inactivité de la carte
    firstDisplay: true,	    // Premier affichage des marqueurs
    
    idleHandle: null,
    clickHandle: null,
    xhrBusy: null,	    // En attente de retour de requète au server
    xhrURL: '',
    imgURL: '',
    kmlURL: '',
    baseURL: '',
    
    arrDataMap: [],
    dataActive: null,
    
    boundingPolygon: null,  // La frontière du département

    /**
     * Constructeur
     * @param params Les paramètres à passer au constructeur
     * @param srcNodeRef Le noeud de référence
     */
    constructor: function( params, srcNodeRef )
    {
	// PARAMETRES DE BASE
	this.county = GMapParams.county;
	this.insee = GMapParams.insee;
	this.id = GMapParams.id;
	this.program_id = GMapParams.program_id;
	this.imgURL = GMapParams.imgURL;
	this.kmlURL = GMapParams.kmlURL;
	this.xhrURL = GMapParams.xhrURL;
	this.xhrBusy = false;		
	this.ignoreIdle = false;
	this.firstDisplay = true;	
	this.baseURL = GMapParams.baseURL;
	this.arrDataMap = [];
	
	GMapSrc = this;
	
	// SUPPRIMER LE MESSAGE D'ERREUR PAR DEFAUT ET CREER LE CONTENEUR DE LA CARTE
	dojo.empty( srcNodeRef );
	this.domNode = dojo.create( 'div', {'class': 'GMap'}, srcNodeRef );
	
	// RECUPERER L'ELEMENT DU DOM OU PLACER LES MESSAGES D'ERREUR'
	this.domErr = dojo.query( '.jsXhrError' )[0];

	// CONSTRUIRE LES OPTIONS DE LA CARTE
	var options = {	zoom: parseInt( ezjs.ini( 'GMapSettings', 'Zoom', 'gmap.ini', this.baseURL ) ),
			center: new google.maps.LatLng( GMapParams.lat, GMapParams.lng ),
			mapTypeId: google.maps.MapTypeId[ezjs.ini( 'GMapSettings', 'MapTypeId', 'gmap.ini', this.baseURL )],
			minZoom: 9,
			streetViewControlOptions: { position: google.maps.ControlPosition.TOP }
			};		       
	
	// CONTROLES A UTILISER SUR LA CARTE
	var disableDefaultUI = ezjs.ini( 'GMapControls', 'DisableDefaultUI', 'gmap.ini', this.baseURL );
	if( ( disableDefaultUI == 'true' ) || ( disableDefaultUI == '1' ) )
	{
	    options.disableDefaultUI = true;
	    var arrControl = ezjs.ini( 'GMapControls', 'Controls', 'gmap.ini', this.baseURL );
	    dojo.forEach( arrControl, dojo.hitch( this, function( control )
	    {
		options[control] = true;
	    } ) );
	}
	
	// ACTIVER OU NON LE DRAGGING
	var draggable = ezjs.ini( 'GMapControls', 'Draggable', 'gmap.ini', this.baseURL );
	if( ( draggable == 'false' ) || ( draggable == '0' ) )
	{
	    options.draggable = false;
	}
	
	// ACTIVER OU NON LE SCROLLWHEEL
	var scrollwheel = ezjs.ini( 'GMapControls', 'Scrollwheel', 'gmap.ini', this.baseURL );
	if( ( scrollwheel == 'false' ) || ( scrollwheel == '0' ) )
	{
	    options.scrollwheel = false;
	}
	
	// CONSTRUIRE LA CARTE A L'AIDE DES OPTIONS
	this.gmap = new google.maps.Map( this.domNode, options );
    
	// CONSTRUIRE LA FRONTIERE DU DEPARTEMENT 
	this.boundingPolygon = new google.maps.KmlLayer( this.kmlURL + '/' + this.county + '.kml', {suppressInfoWindows: true} ); // URL DOIT ETRE ACCESSIBLE PUBLIQUEMENT
	this.boundingPolygon.setMap( this.gmap );
	
	// METTRE A JOUR LA CARTE DES QUELLE EST INACTIVE
	this.idleHandle = google.maps.event.addListener( this.gmap, 'idle', dojo.hitch( this, this.xhrGet ) );
	
	// FERMER LES INFOBULLES PAR UN CLIC SUR LA CARTE
	this.clickHandle = google.maps.event.addListener( this.gmap, 'click', dojo.hitch( this, this.closeInfoWindow ) );
	
	// CONTROLES ACCESSIBLES
	var accessibleControls = ezjs.ini( 'GMapControls', 'AccessibleControls', 'gmap.ini', this.baseURL );
	if( ( accessibleControls == 'true' ) || ( accessibleControls == '1' ) )
	{
	    this.controls = new gmap.controls( { gmap: this.gmap, panAmpl: 100, baseURL: this.baseURL, imgURL: this.imgURL, lat: GMapParams.lat, lng: GMapParams.lng }, srcNodeRef );
	}
    },
	
    /**
     * Récupère le résultat d'une requête xhr au server
     * @callback refresh
     * @callback error
     */	
    xhrGet: function()
    {
	if( this.ignoreIdle )
	{
	    this.ignoreIdle = false;
	}
	else
	{
	    var bounds = this.gmap.getBounds();
	    var ne = bounds.getNorthEast();
	    var sw = bounds.getSouthWest();

	    // APPEL A LA VUE xhr DU MODULE gmap
	    var xhrArgs = { url: this.xhrURL + '/' + this.county + '/' + this.insee + '/' + this.program_id + '/' + this.id + '/' + this.gmap.getZoom() + '/' + ne.lat() + '/' + ne.lng() + '/' + sw.lat() + '/' + sw.lng(),
			    handleAs: 'json',
			    preventCache: true,
			    headers: {'Content-Type': 'application/json',
					'Content-Encoding': 'utf-8'
					},
			    load: 	dojo.hitch( this, this.refresh ),
			    error: 	dojo.hitch( this, this.error )
			    };
			    
	    // REQUETE UNIQUEMENT SI PAS DEJA UNE EN COURS
	    if( !this.xhrBusy )
	    {
		this.xhrBusy = true;
		var deferred = dojo.xhrGet( xhrArgs );
	    }
	}
    },
    
    /**
     * Affiche une erreur xhr dans l'élément du dom correspondant
     */	    
    error: function( error ) 
    {
	this.xhrBusy = false;
	this.domErr.innerHTML = '<p>An unexpected error occurred: ' + error + '</p>';
	dojo.addClass( this.domErr, 'alert' );
	dojo.addClass( this.domErr, 'error' );
    },

    /**
     * Met à jour la liste des marqueurs renvoyés par le server
     */	    
    refresh: function( xhrData )
    {	
	// PERMETTRE A NOUVEAU L'ENVOI D'UNE REQUETE
	this.xhrBusy = false;
	
	// SUPPRIMER LES DONNEES ACTUELLES
	this.clearData();
	
	// CREER LES NOUVEAUX MARQUEURS
	for( var i in xhrData.markerList )
	{
	    var xhrMarker = xhrData.markerList[i];
	    this.addMarker( xhrMarker.lat, 
			    xhrMarker.lng, 
			    xhrMarker.title, 
			    xhrMarker.cluster,
			    xhrMarker.content,
			    xhrMarker.id
			    );
	}
	
	// CENTRER LA CARTE AU PREMIER AFFICHAGE
	if( this.firstDisplay && ( xhrData.lat != 0 ) && ( xhrData.lng != 0 ) )
	{
		console.log("centerSet");
	    this.gmap.setCenter( new google.maps.LatLng( xhrData.lat, xhrData.lng ) );
	    this.ignoreIdle = true;
	    if (this.id != 0){
	    	console.log("SetZoom");
	    }
	}
	this.firstDisplay = false;
    },

    /**
     * Supprime les données courantes relatives aux marqueurs
     */	 
    clearData: function()
    {
	var item;
	while( ( item = this.arrDataMap.pop() ) != undefined )
	{
	    item.marker.setMap( null );
	    google.maps.event.removeListener( item.clickHandle );
	    item.infoWindow = null;
	}
    },

    /**
     * Ajoute un marqueur sur la carte et dans la liste
     * @param lat float Latitude
     * @param lng float	Longitude
     * @param title String Titre
     * @param cluster int Nombre de GMapLocation représentés par ce marqueur
     * @param content String Contenu de l'infoWindow
     * @param id int Identifiant du GMapLocation (-1 si cluster > 1)
     */	 
    addMarker: function( lat, lng, title, cluster, content, id )
    {			
	// AJOUTER MARQUEUR SUR LA CARTE
	var marker = new google.maps.Marker({	position: new google.maps.LatLng( lat, lng ), 
						map: this.gmap,
						title: title,
						icon: new google.maps.MarkerImage( this.imgURL + '/' + cluster + '.png' )
						});  

	// CREER INFOBULLE
	var infoWindow = new google.maps.InfoWindow( {  //disableAutoPan: true, // empèche l'auto-rechargement quand l'infobulle entraine le déplacement de la fenêtre
							content: content
							});

	// AJOUTER ECOUTE DU CLIC SUR MARQUEUR
	var clickHandle = new google.maps.event.addListener(    marker, 
								'click', 
								dojo.hitch( this, this.popInfoWindow, marker, infoWindow )
								);
								    
	// OUVRIR INFOBULLE SI CORRESPOND A L'IDENTIFIANT
	if( ( this.id == id ) && ( this.firstDisplay ) )
	{
		console.log("go to pop");
		this.gmap.setCenter( new google.maps.LatLng( lat, lng ) );
		this.gmap.setZoom(15);
	    this.popInfoWindow( marker, infoWindow );
	}

	// AJOUTER DONNEES A LA LISTE
	this.arrDataMap.push({	marker: marker,
				infoWindow: infoWindow,
				clickHandle: clickHandle
				});
    },

    /**
     * Ouvre l'infoWindow d'un marqueur
     */	  
    popInfoWindow: function( marker, infoWindow )
    {
    	console.log("pop la window");
	// REFERMER LES AUTRES INFOWINDOWS
	if( this.dataActive != null)
	{
	    this.dataActive.infoWindow.close();
	    this.dataActive = null;
	}
	
	// CREER UN MARQUEUR TRANSPARENT
	var activeMarker = new google.maps.Marker({ position: marker.getPosition(), 
						    map: this.gmap,
						    icon: new google.maps.MarkerImage( this.imgURL + '/blank.png' )
						    });  
										
	// LE DECLARER COMME ETANT ACTIF
	this.dataActive = { marker: activeMarker,
			    infoWindow: infoWindow
			    };

	// OUVRIR L'INFOWINDOW SUR LE MARQUEUR ACTIF
	infoWindow.open( this.gmap, this.dataActive.marker );
	
	// CONNECTER LA FERMETURE DE L'INFOWINDOW AVEC UNE METHODE
	var closeHandle = new google.maps.event.addListenerOnce( infoWindow, 'closeclick', dojo.hitch( this, this.closeInfoWindow ) );			
    },

    /**
     * Ferme l'infoWindow d'un marqueur
     */	  
    closeInfoWindow: function()
    {
	// NETTOYER LES INFORMATIONS
	if( this.dataActive != null )
	{
	    this.dataActive.marker.setMap( null );
	    this.dataActive.marker = null;
	    this.dataActive.infoWindow = null;
	    this.dataActive = null;
	}
    },
    
    /**
     * Destructeur
     */	    
    destroy: function()
    {
	// SUPPRIME LES MARQUEURS
	this.clearData();
	
	// SUPPRIME LES CONTROLES ACCESSIBLES SI ILS SONT ACTIVES
	if( this.controls != null )
	{
	    dojo.destroy( this.controls );
	}
    }
});

actiJSCoreParser.addDefinition(	'.jsGMap', gmap.src, {} );
