Subversion Repositories eFlore/Applications.cel

Rev

Rev 2910 | Blame | Compare with Previous | Last modification | View Log | RSS feed

package org.tela_botanica.client.vues.observation;

// TODO Detecter redim et supprimer ajuster

import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.tela_botanica.client.CarnetEnLigneMediateur;
import org.tela_botanica.client.i18n.Msg;
import org.tela_botanica.client.interfaces.Rafraichissable;
import org.tela_botanica.client.modeles.dao.ImageInformationRepartitionAsynchroneDAO;
import org.tela_botanica.client.modeles.dao.ListeReferentielChampsEtendusDAO;
import org.tela_botanica.client.modeles.dao.ListeReferentielLocaliteAsynchroneDAO;
import org.tela_botanica.client.modeles.dao.ListeReferentielNomAsynchroneDAO;
import org.tela_botanica.client.modeles.dao.ListeReferentielPersoAsynchroneDAO;
import org.tela_botanica.client.modeles.objets.ChampEtendu;
import org.tela_botanica.client.modeles.objets.Configuration;
import org.tela_botanica.client.modeles.objets.EntiteGeographiqueObservation;
import org.tela_botanica.client.modeles.objets.ListeObservation;
import org.tela_botanica.client.modeles.objets.Observation;
import org.tela_botanica.client.modeles.objets.Ontologies;
import org.tela_botanica.client.modeles.objets.ReferentielLocalite;
import org.tela_botanica.client.modeles.objets.ReferentielNom;
import org.tela_botanica.client.modeles.objets.ListeReferentielPerso.TypesReferentiels;
import org.tela_botanica.client.observation.ObservationMediateur;
import org.tela_botanica.client.util.ChampSaisieEtendu;
import org.tela_botanica.client.util.FormulaireSaisieChampEtendu;
import org.tela_botanica.client.util.Util;
import org.tela_botanica.client.util.autocompletion.AutoCompletionComboBox;

import com.google.gwt.core.client.Callback;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.http.client.Response;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.PopupPanel;
import com.gwtext.client.core.EventCallback;
import com.gwtext.client.core.EventObject;
import com.gwtext.client.core.Ext;
import com.gwtext.client.core.ExtElement;
import com.gwtext.client.core.ListenerConfig;
import com.gwtext.client.core.Position;
import com.gwtext.client.widgets.BoxComponent;
import com.gwtext.client.widgets.Button;
import com.gwtext.client.widgets.Container;
import com.gwtext.client.widgets.DatePicker;
import com.gwtext.client.widgets.Panel;
import com.gwtext.client.widgets.ToolTip;
import com.gwtext.client.widgets.event.ButtonListenerAdapter;
import com.gwtext.client.widgets.event.ContainerListenerAdapter;
import com.gwtext.client.widgets.event.DatePickerListenerAdapter;
import com.gwtext.client.widgets.event.PanelListenerAdapter;
import com.gwtext.client.widgets.form.ComboBox;
import com.gwtext.client.widgets.form.DateField;
import com.gwtext.client.widgets.form.Field;
import com.gwtext.client.widgets.form.FormPanel;
import com.gwtext.client.widgets.form.Label;
import com.gwtext.client.widgets.form.MultiFieldPanel;
import com.gwtext.client.widgets.form.TextArea;
import com.gwtext.client.widgets.form.TextField;
import com.gwtext.client.widgets.form.event.ComboBoxListenerAdapter;
import com.gwtext.client.widgets.form.event.TextFieldListenerAdapter;
import com.gwtext.client.widgets.layout.AnchorLayoutData;
import com.gwtext.client.widgets.layout.ColumnLayout;
import com.gwtext.client.widgets.layout.ColumnLayoutData;
import com.gwtext.client.widgets.layout.FormLayout;
import com.gwtext.client.widgets.layout.RowLayout;
import com.gwtext.client.data.Record;

/**
 * Panneau contenant les infos, les métadonnées et l'arbre des mots clés, il implémente l'interface rafraichissable
 * @author aurelien
 *
 */
public class FormulaireSaisieObservationVue extends Panel implements Rafraichissable  {


        /**
         * Le médiateur associé à la vue
         */
        private ObservationMediateur    observationMediateur            = null;

        FormPanel panneauFormulaire = null;

        private DateField date = null;
        private AutoCompletionComboBox lieudit = null;
        private AutoCompletionComboBox station = null;
        private AutoCompletionComboBox milieu = null;
        private TextField comment = null;
        private AutoCompletionComboBox  localite = null;
        
        private String codeLocalite = null;
        private String pays = null;
        
        private AutoCompletionComboBox  espece = null;
        private Map<String, ReferentielNom> referentielNom = null;
        private Map<String, ReferentielLocalite> referentielLocalite = null;
        
        private String numeroNom = null;
        private String numeroOrdre = null;
        private String referentielTaxo = null;
        private String referentielGeo = null;
        
        private Map<String, String> avertissementPresence = new HashMap<String, String>();
        private boolean enRequeteChrologie = false;

        // Pour remise a zero partielle lors d'une validation

        private enum Champs {
            DATE, LIEUDIT, STATION, MILIEU, COMMENT, LOCALITE, ESPECE, TOUT, LATITUDE, LONGITUDE, ALTITUDE, ABONDANCE, CERTITUDE, REFERENTIELTAXO, PHENOLOGIE;

            @Override
                public String toString() {
            
                switch(this) {
                case DATE:
                        return "date";
            
                case LOCALITE:
                        return "localite";
            
                case LIEUDIT:
                        return "lieu dit";
            
                case STATION:
                        return "station";
            
                case MILIEU:
                        return "milieu";
            
                case COMMENT:
                        return "notes";
            
                case ESPECE:
                        return "espèce";
            
                case LATITUDE:
                        return "latitude";
            
                case LONGITUDE:
                        return "longitude";
            
                case ALTITUDE:
                        return "altitude";
            
                case ABONDANCE:
                        return "abondance";
            
                case CERTITUDE:
                        return "identification";
            
                case REFERENTIELTAXO:
                        return "referentiel";
            
                case PHENOLOGIE:
                        return "phenologie";
            
                case TOUT:
                        return "date, localite, lieu dit, station, milieu, espèce, notes, latitude, longitude, altitude, abondance, identification, referentiel, phenologie";
                }
                        return TOUT.toString();
            }
        };

        private String formatDate = null ;
        private Button boutonOK = new Button(Msg.get("creer"));
        private Button boutonModifier = new Button(Msg.get("modifier"));
        private Button boutonSupprimer = new Button(Msg.get("supprimer"));
        private Button boutonReinitialiser = new Button(Msg.get("reinitialiser"));

        private boolean selectionlocalite=false;
        private boolean selectionEspece=false;
        private boolean selectionAbondance = false;
        private boolean selectionCertitude = false;
        private boolean selectionPhenologie = false;

        private final String VALEURS_MULTIPLES = "("+Msg.get("valeurs-multiples")+")";
        private final String modeleMessageModif = "localite:lieu-dit:station:milieu:latitude:longitude:altitude:date:espece:notes:abondance:identification:referentiel:phenologie";
        private boolean localiteModifiee = false;
        private boolean lieuDitModifie = false;
        private boolean stationModifiee = false;
        private boolean milieuModifie = false;
        private boolean dateModifiee = false;
        private boolean especeModifiee = false;
        private boolean commModifie = false;
        private boolean abondanceModifiee = false;
        private boolean certitudeModifiee = false;
        private boolean referentielTaxoModifie = false;
        private boolean phenologieModifiee = false;;

        private final int KEY_ALT = 18;
        private final int KEY_BACKSPACE = 8;
        private final int KEY_CTRL = 17;
        private final int KEY_DELETE = 46;
        private final int KEY_DOWN = 40;
        private final int KEY_END = 35;
        private final int KEY_ENTER = 13;
        private final int KEY_ESCAPE = 27;
        private final int KEY_HOME = 36;
        private final int KEY_LEFT = 37;
        private final int KEY_PAGEDOWN = 34;
        private final int KEY_PAGEUP = 33;
        private final int KEY_RIGHT = 39;
        private final int KEY_SHIFT = 16;
        private final int KEY_TAB = 9;
        private final int KEY_UP = 38;

        /**
         * Booleen d'instanciation
         */
        boolean estInstancie = false ;

        private Panel panneauIntermediaire;

        private Panel panneauPremierColonne;

        private Panel panneauSecondeColonne;

        private TextField longitude;

        private TextField latitude;

        private TextField altitude;

        private MultiFieldPanel htmllocalitePanel = null;

        private MultiFieldPanel coordPanel;

        private TextField coordonnees;

        private Label lienSelectionlocalite = null;

        private HTML afficherFormulaireLatLon;

        private HTML basculerverscarto;

        private boolean longlatAjoutee;

        private boolean latModifiee;

        private boolean longModifiee;

        private boolean altModifiee;

        protected boolean recherchelocaliteEnCours = false;

        private Timer tCoord;

        private ComboBox selecteurAbondance = null;

        private ComboBox selecteurCertitude = null;

        private ComboBox selecteurReferentielTaxo = null;

        private ComboBox selecteurStadePheno = null;

        private boolean selectionMultiple = false;

        private HTML lienAfficherChampsEtendus = null;
        private HTML lienAjouterChampsEtendus = null;

        Panel conteneurChampEtenduGauche = null;
        Panel conteneurChampEtenduDroite = null;

        private boolean afficherChampsEtendus = false;
        private boolean afficherLienAjoutChampsEtendus = false;
        private boolean premierAffichage = true;

        private PopupPanel popUpAjoutChampEtendu = new PopupPanel();
        
        private Map<String, ChampSaisieEtendu> listeChampsEtendus;

        /**
         * Constructeur sans argument (privé car ne doit pas être utilisé)
         */
        @SuppressWarnings("unused")
        private FormulaireSaisieObservationVue()
        {
                super() ;
        }

        /**
         * Constructeur avec argument
         * @param im
         */
        public FormulaireSaisieObservationVue(ObservationMediateur obs)
        {
                super(Msg.get("saisie"));
                // on associe le médiateur
                observationMediateur = obs ;

                referentielTaxo = obs.getRefTaxSelectionne().getCode();
             
                panneauFormulaire = new FormPanel(Position.RIGHT);
                panneauFormulaire.setBorder(false);

                // Panneau intermediaire qui contient deux colonnes de formulaire
                panneauIntermediaire = new Panel();

                if (Window.getClientWidth()> Window.getClientHeight()) {
                        panneauIntermediaire.setLayout(new ColumnLayout());
                }
                else {
                        panneauIntermediaire.setLayout(new RowLayout());
                }

                panneauIntermediaire.setBorder(false);

                //création du panneau formulaire de gauche auquels on ajoute les champs
                panneauPremierColonne = new Panel();
                panneauPremierColonne.setLayout(new FormLayout());
                panneauPremierColonne.setBorder(false);

                //création du panneau formulaire de droite
            panneauSecondeColonne = new Panel();
                panneauSecondeColonne.setLayout(new FormLayout());
                panneauSecondeColonne.setBorder(false);

                this.setPaddings(5) ;

                // Accesskey pour debugging
                localite = new AutoCompletionComboBox(Msg.get("localite"), ListeReferentielLocaliteAsynchroneDAO.getUrlReferentielLocalites()) {                        
                        @Override
                        protected Map<String, String> parserResultatRequete(Response response) {
                                referentielLocalite = Util.parserRetourReferentielLocaliteIndexeParNom(response);
                                return Util.convertirListeReferentielLocaliteVersMap(referentielLocalite);
                        }
                        
                        @Override
                        public void onSelectionValeur() {
                                localiteModifiee = true;
                                surSelectionLocalite();
                                verifierPresenceTaxonSaisi();
                        }
                        
                        @Override
                        protected void onModificationValeur() {
                                localiteModifiee = true;        
                                verifierPresenceTaxonSaisi();
                        }

                        @Override
                        public void onValidationSaisie() {
                                validerSaisie(Champs.LOCALITE);
                        }
                };


                //création du lien "Accès carto" dans le formulaire;
                basculerverscarto = new HTML(" <a id=\"lien_carto\" title=\""+Msg.get("aide-lien-localiser")+"\" href=\"#\" tabindex=\"2\">"+Msg.get("localiser-zone")+"</a>");
                basculerverscarto.addStyleName("lien_actif");

                //création info bulle sur le lien "accès carto"
                ToolTip tip2 = new ToolTip();
                tip2.setHtml(Msg.get("aide-lien-localiser"));
                tip2.applyTo(basculerverscarto.getElement());

                //Sur une meme ligne, ajout de plusieurs champs
                htmllocalitePanel = new MultiFieldPanel();

                int largeurlocalite = Window.getClientWidth()/4;
                htmllocalitePanel.addToRow(localite, largeurlocalite);
                htmllocalitePanel.addToRow(basculerverscarto, 160);

                htmllocalitePanel.setBorder(false);
                htmllocalitePanel.setId("x-localite-panel");

                panneauPremierColonne.add(htmllocalitePanel);

            station = new AutoCompletionComboBox(Msg.get("station"), ListeReferentielPersoAsynchroneDAO.getUrlReferentielPerso(TypesReferentiels.REFERENTIEL_STATION)) {                        
                        @Override
                        protected Map<String, String> parserResultatRequete(Response response) {
                                return Util.parserRetourReferentielPerso(response);
                        }
                        
                        @Override
                        public void onSelectionValeur() {
                                stationModifiee = true;
                        }
                        
                        @Override
                        protected void onModificationValeur() {
                                stationModifiee = true; 
                        }

                        @Override
                        public void onValidationSaisie() {
                                validerSaisie(Champs.STATION);
                        }

                        @Override
                        protected String preTraiterUrlRequete(String urlRequete, String valeur) {
                                return ListeReferentielPersoAsynchroneDAO.formaterUrlRequeteAutoCompletionPerso(urlRequete, valeur);
                        }  
                };
            panneauPremierColonne.add(station, new AnchorLayoutData("95%"));

                latitude = new TextField(Msg.get("lat"), "lat");
                latitude.setGrowMax(70);
                latitude.setAllowBlank(true);

            longitude = new TextField(Msg.get("lon"), "lon");
            longitude.setGrowMax(70);
                longitude.setAllowBlank(true);

                altitude = new TextField(Msg.get("alt"), "alt");
                altitude.setGrowMax(70);
                altitude.setAllowBlank(true);

                lienSelectionlocalite = new Label("");


                lienSelectionlocalite.setId("conteneur_selection_localite");
                lienSelectionlocalite.setStyleName("conteneur_selection_localite");
                lienSelectionlocalite.addStyleName("lien_actif");

                // Panneau de type plusieurs champs de formulaire sur une meme ligne, où seront renseignés Lat/Lon
                coordPanel = new MultiFieldPanel();
                coordPanel.setPaddings(0, 0, 0, 10);
                coordPanel.setVisible(false);

                final double largeur ;
                largeur = 120;

                coordPanel.addToRow(latitude, new ColumnLayoutData(largeur));
                coordPanel.addToRow(longitude, new ColumnLayoutData(largeur));
                coordPanel.addToRow(lienSelectionlocalite, new ColumnLayoutData(largeur));
                lienSelectionlocalite.addClass("lien_decale");
                coordPanel.setBorder(false);

                coordPanel.addToRow(altitude, new ColumnLayoutData(largeur));

                  //création du champs coordonnées
                referentielGeo = Configuration.getReferentielGeo();

                coordonnees = new TextField(Msg.get("coordonnees"), "", 0);
                coordonnees.setMaxLength(0);
                coordonnees.setReadOnly(true);
                coordonnees.setCls("fieldname");

                //création du lien "saisie X/Y" dans le formulaire
                afficherFormulaireLatLon = new HTML("<span style=\"padding-left:30px;\" class=\"conteneur_lien_afficher_lat_lon\">" +
                                "<a title=\""+Msg.get("indication-formulaire-lat-lon")+"\" class=\"lien_actif\" id=\"lien_coord\" href=\"#\" tabindex=\"6\">"+Msg.get("saisie-lat-lon")+" ("+referentielGeo+")</a>" +
                                "<span><span style=\"padding-left:20px\" class=\"conteneur_lien_localiser_lat_lon\">"+
                                "<a title=\""+Msg.get("indication-formulaire-localiser")+"\" class=\"lien_actif\" id=\"lien_carto_coord\" href=\"#\" tabindex=\"7\">"+Msg.get("localiser-la-carte")+"</a>"+
                                "</span>");

                        //ajout d'un listener sur le lien "saisie X/Y"
                        coordPanel.addListener(new PanelListenerAdapter() {

                                @Override
                                public void onAfterLayout(Container c) {
                                        surPremierAffichageCoordPanel(largeur);
                                }
                        });

                //Sur une meme ligne, ajout de plusieurs champs
                final MultiFieldPanel htmlPanel = new MultiFieldPanel();

                htmlPanel.addToRow(coordonnees, 100);
                htmlPanel.addToRow(afficherFormulaireLatLon, new ColumnLayoutData(0.9));
                htmlPanel.setBorder(false);
                htmlPanel.setId("x-coord-panel");

                panneauPremierColonne.add(htmlPanel);
                panneauPremierColonne.add(coordPanel);

            date = new DateField(Msg.get("date"), "date", 250);
            date.setAllowBlank(true);
            formatDate = "d/m/Y";
            date.setFormat(formatDate);
            date.setTitle(Msg.get("indication-format-date"));
            date.setMaxValue(new Date());
            //date.setTabIndex(5);
            panneauPremierColonne.add(date, new AnchorLayoutData("55%"));
 

            final String champsListeTpl = "<div class=\"x-combo-list-item search-item-tpl\" title=\"{label}\">{label}</div>";
 
            // Selection d'un référentiel par défaut (le premier spécifié dans la config)
            referentielTaxo = Configuration.getReferentielsDispos().get(0).getCode();
            selecteurReferentielTaxo = new ComboBox();
            selecteurReferentielTaxo.setCls("champ-separation");
            selecteurReferentielTaxo.setLabel(Msg.get("referentiel"));
            selecteurReferentielTaxo.setStore(Ontologies.getValeursReferentiel());
            selecteurReferentielTaxo.setValue(referentielTaxo);
            selecteurReferentielTaxo.setDisplayField("label") ;
            selecteurReferentielTaxo.setValueField("valeur");
            selecteurReferentielTaxo.setEditable(false);
            selecteurReferentielTaxo.setHideTrigger(false);
            selecteurReferentielTaxo.setForceSelection(true);
            selecteurReferentielTaxo.setTpl(champsListeTpl);
            
                espece = new AutoCompletionComboBox(Msg.get("espece"), ListeReferentielNomAsynchroneDAO.getBaseUrlReferentielNom()) {                   
                        @Override
                        protected Map<String, String> parserResultatRequete(Response response) {
                                // TODO: bien penser à l'unicité des clés, ici on suppose que 
                                // genre espèce auteur suffit mais quelquefois on peut avoir des doublons
                                referentielNom = Util.parserRetourReferentielNomIndexeParNom(response);
                                return Util.convertirListeReferentielNomVersMap(referentielNom);
                        }
                        
                        @Override
                        public void onSelectionValeur() {
                                especeModifiee = true;
                                surSelectionEspece();
                                verifierPresenceTaxonSaisi();
                        }
                        
                        @Override
                        protected void onModificationValeur() {
                                especeModifiee = true;  
                                // Pour éviter qu'un mauvais nn ne soit gardé lors d'une modification
                                // vers un nom ne faisant pas partie du référentiel
                                numeroNom = null;
                                if(referentielNom.containsKey(espece.getText())) {
                                        numeroNom = referentielNom.get(espece.getText()).getNumeroNom();
                                }
                                verifierPresenceTaxonSaisi();
                        }

                        @Override
                        public void onValidationSaisie() {
                                validerSaisie(Champs.ESPECE);
                        }  
                        
                        @Override
                        protected String preTraiterUrlRequete(String urlRequete, String valeur) {
                                return ListeReferentielNomAsynchroneDAO.formaterUrlAutoCompletionReferentielNom(urlRequete, referentielTaxo, valeur);
                        }
                        
                        @Override
                        protected String preTraiterValeurAvantAffichage(String valeur) {
                                ReferentielNom nomValeur = referentielNom.get(valeur);
                                String valeurAffichee = nomValeur.getNom();
                                // Pour afficher les noms retenus en gras
                                if (nomValeur.estRetenu()) {
                                        valeurAffichee = "<span class=\"nomRetenu\">"+nomValeur.getNom().trim()+"</span>";
                                }
                                return valeurAffichee;
                        }
            };

            Panel panelSeparationPp = new Panel();
            panelSeparationPp.setHeight(15);
            panelSeparationPp.setBorder(false);

            panneauPremierColonne.add(panelSeparationPp);
            panneauPremierColonne.add(selecteurReferentielTaxo, new AnchorLayoutData("85%"));
            panneauPremierColonne.add(espece, new AnchorLayoutData("95%"));

            selecteurAbondance = new ComboBox();
            selecteurAbondance.setCls("champ-separation");
            selecteurAbondance.setLabel(Msg.get("abondance"));
            selecteurAbondance.setStore(Ontologies.getValeursAbondance());
            selecteurAbondance.setDisplayField("label") ;
            selecteurAbondance.setValueField("valeur");
            selecteurAbondance.setEditable(true);
            selecteurAbondance.setHideTrigger(false);
            selecteurAbondance.setForceSelection(false);
            selecteurAbondance.setTpl(champsListeTpl);
            panneauPremierColonne.add(selecteurAbondance,  new AnchorLayoutData("95%"));
            
            lieudit = new AutoCompletionComboBox(Msg.get("lieu-dit"), ListeReferentielPersoAsynchroneDAO.getUrlReferentielPerso(TypesReferentiels.REFERENTIEL_LIEU_DIT)) {                      
                        @Override
                        protected Map<String, String> parserResultatRequete(Response response) {
                                return Util.parserRetourReferentielPerso(response);
                        }
                        
                        @Override
                        public void onSelectionValeur() {
                                lieuDitModifie = true;
                        }
                        
                        @Override
                        protected void onModificationValeur() {
                                lieuDitModifie = true;  
                        }

                        @Override
                        public void onValidationSaisie() {
                                validerSaisie(Champs.LIEUDIT);
                        }  
                        
                        @Override
                        protected String preTraiterUrlRequete(String urlRequete, String valeur) {
                                return ListeReferentielPersoAsynchroneDAO.formaterUrlRequeteAutoCompletionPerso(urlRequete, valeur);
                        }
                };
            panneauSecondeColonne.add(lieudit,  new AnchorLayoutData("95%"));
               
            milieu = new AutoCompletionComboBox(Msg.get("milieu"), ListeReferentielPersoAsynchroneDAO.getUrlReferentielPerso(TypesReferentiels.REFERENTIEL_MILIEU)) {                   
                        @Override
                        protected Map<String, String> parserResultatRequete(Response response) {
                                return Util.parserRetourReferentielPerso(response);
                        }
                        
                        @Override
                        public void onSelectionValeur() {
                                milieuModifie = true;
                        }
                        
                        @Override
                        protected void onModificationValeur() {
                                milieuModifie = true;   
                        }

                        @Override
                        public void onValidationSaisie() {
                                validerSaisie(Champs.MILIEU);
                        }  
                        
                        @Override
                        protected String preTraiterUrlRequete(String urlRequete, String valeur) {
                                return ListeReferentielPersoAsynchroneDAO.formaterUrlRequeteAutoCompletionPerso(urlRequete, valeur);
                        }
            };
            panneauSecondeColonne.add(milieu,  new AnchorLayoutData("95%"));

            comment = new TextArea(Msg.get("notes"), "comment");
            comment.setAllowBlank(true);
            comment.setHeight(50);

            panneauSecondeColonne.add(comment, new AnchorLayoutData("95%") );

            Panel panelSeparationPs = new Panel();
            panelSeparationPs.setHeight(39);
            panelSeparationPs.setBorder(false);

            panneauSecondeColonne.add(panelSeparationPs);

            selecteurCertitude = new ComboBox();
            selecteurCertitude.setLabel(Msg.get("identification"));
            selecteurCertitude.setStore(Ontologies.getValeursCertitude());
            selecteurCertitude.setDisplayField("label") ;
            selecteurCertitude.setValueField("valeur");
            selecteurCertitude.setEditable(true);
            selecteurCertitude.setHideTrigger(false);
            selecteurCertitude.setForceSelection(false);
            selecteurCertitude.setTpl(champsListeTpl);
            panneauSecondeColonne.add(selecteurCertitude, new AnchorLayoutData("95%"));

            selecteurStadePheno = new ComboBox();
            selecteurStadePheno.setLabel(Msg.get("phenologie"));
            selecteurStadePheno.setStore(Ontologies.getValeursPhenologie());
            selecteurStadePheno.setDisplayField("label") ;
            selecteurStadePheno.setValueField("valeur");
            selecteurStadePheno.setEditable(true);
            selecteurStadePheno.setHideTrigger(false);
            selecteurStadePheno.setForceSelection(false);
            selecteurStadePheno.setTpl(champsListeTpl);
            panneauSecondeColonne.add(selecteurStadePheno, new AnchorLayoutData("95%"));

            if (Window.getClientWidth() > Window.getClientHeight() || Window.getClientWidth() < 800) {
                        panneauIntermediaire.add(panneauPremierColonne, new ColumnLayoutData(.5));
                        panneauIntermediaire.add(panneauSecondeColonne, new ColumnLayoutData(.5));
            }
            else {
                        panneauIntermediaire.add(panneauPremierColonne);
                        panneauIntermediaire.add(panneauSecondeColonne);   
            }

                panneauFormulaire.add(panneauIntermediaire);
                
                if (Ext.isIE()) {
                        panneauPremierColonne.setButtonAlign(Position.RIGHT);
                        panneauPremierColonne.addButton(boutonOK);
                        panneauPremierColonne.addButton(boutonModifier);
                        panneauPremierColonne.addButton(boutonSupprimer);
                        panneauSecondeColonne.setButtonAlign(Position.LEFT);
                        panneauPremierColonne.addButton(boutonReinitialiser);
                }
                else {
                        panneauFormulaire.addButton(boutonOK);
                        panneauFormulaire.addButton(boutonModifier);
                        panneauFormulaire.addButton(boutonSupprimer);
                        panneauFormulaire.addButton(boutonReinitialiser);
                }

                this.add(panneauFormulaire) ;

                this.setAutoScroll(true);


                panneauFormulaire.addListener(new PanelListenerAdapter() {
                @Override
                        public void onResize(BoxComponent component, int adjWidth, int adjHeight, int rawWidth, int rawHeight) {
                        panneauIntermediaire.setWidth(rawWidth);
                        panneauIntermediaire.setHeight(rawHeight);
                
                        panneauPremierColonne.doLayout();
                        panneauSecondeColonne.doLayout();
                                        
                        htmllocalitePanel.doLayout();
                        htmlPanel.doLayout();
                        
                                redimensionnerChampsEtendus();
                
                        doLayout();
                }
            });

                lienAfficherChampsEtendus = new HTML(Msg.get("afficher-champs-etendus"));
                lienAfficherChampsEtendus.setStyleName("img-curseur-depl");
                lienAfficherChampsEtendus.setStyleName("lienAfficherChampsEtendus");
                lienAfficherChampsEtendus.setVisible(false);

                lienAfficherChampsEtendus.addClickHandler(new ClickHandler() {
                        @Override
                        public void onClick(ClickEvent event) {
                                if(afficherChampsEtendus) {
                                        afficherChampsEtendus = false;
                                        if(conteneurChampEtenduGauche != null && conteneurChampEtenduDroite != null) {
                                                conteneurChampEtenduGauche.hide();
                                                conteneurChampEtenduDroite.hide();
                                        }
                                        lienAfficherChampsEtendus.setText(Msg.get("afficher-champs-etendus"));

                                } else {
                                        afficherChampsEtendus = true;
                                        if(conteneurChampEtenduGauche != null && conteneurChampEtenduDroite != null) {
                                                conteneurChampEtenduGauche.show();
                                                conteneurChampEtenduDroite.show();
                                                redimensionnerChampsEtendus();
                                        }
                                        lienAfficherChampsEtendus.setText(Msg.get("cacher-champs-etendus"));
                                }
                        }
                });
                
                if(Configuration.saisieChampsEtendusActivee()) {
                        // Chargement du cache des correspondances cles/labels du catalogue
                        ListeReferentielChampsEtendusDAO lrceDao = new ListeReferentielChampsEtendusDAO(null);
                        lrceDao.obtenirGroupesChampsEtendus(this);
                        lrceDao.obtenirCatalogueChampsEtendus(this);
                        
                        lienAjouterChampsEtendus = new HTML(Msg.get("ajouter-champ-etendu"));
                        lienAjouterChampsEtendus.addStyleName("lienAjouterChampEtendu");
                        lienAjouterChampsEtendus.setVisible(true);
                        panneauPremierColonne.add(lienAjouterChampsEtendus);
                        gererLienAjoutChampsEtendus();
                }
                
                panneauPremierColonne.add(lienAfficherChampsEtendus);
                panneauPremierColonne.addListener(new PanelListenerAdapter() {
                        @Override
                        public void onAfterLayout(Container c) {
                                if(premierAffichage) {
                                        lienAfficherChampsEtendus.setVisible(false);
                                        premierAffichage = false;
                                }
                        }
                });

                ajouterListeners() ;
                ajouterToolTipsBoutons();
                saisieTabindex();
        }
        
        protected void surSelectionEspece() {
                ReferentielNom nom = referentielNom.get(espece.getText());
                numeroNom = nom.getNumeroNom();
                selectionEspece = true;
                observationMediateur.obtenirImageInformationExternes(referentielTaxo, numeroNom);
        }
        
        protected void surSelectionLocalite() {
                ReferentielLocalite infosLoc = referentielLocalite.get(localite.getText());
        codeLocalite = infosLoc.getCodeLocalite();
        selectionlocalite=true;
        }

        private void gererLienAjoutChampsEtendus() {    
                popUpAjoutChampEtendu.setStylePrimaryName("popup_champ_etendu");
                lienAjouterChampsEtendus.addClickHandler(new ClickHandler() {
                        @Override
                        public void onClick(ClickEvent event) {
                                FormulaireSaisieChampEtendu formChamp = new FormulaireSaisieChampEtendu() {     
                                        
                                        @Override
                                        public void surValidation(ChampSaisieEtendu champ) {
                                                ajouterChampEtenduAuFormulaire(champ, true);
                                                popUpAjoutChampEtendu.clear();
                                                popUpAjoutChampEtendu.hide();
                                        }
                                        
                                        @Override
                                        public void surAjout(ChampSaisieEtendu champ) {
                                                ajouterChampEtenduAuFormulaire(champ, false);
                                        }

                                        @Override
                                        public void surAnnulation() {
                                                popUpAjoutChampEtendu.clear();
                                                popUpAjoutChampEtendu.hide();
                                        }

                                        @Override
                                        public void surAjoutMultiple(List<ChampSaisieEtendu> champs) {
                                                for (Iterator<ChampSaisieEtendu> iterator = champs.iterator(); iterator.hasNext();) {
                                                        ChampSaisieEtendu champSaisieEtendu = (ChampSaisieEtendu) iterator.next();
                                                        ajouterChampEtenduAuFormulaire(champSaisieEtendu, false);
                                                }
                                        }

                                        @Override
                                        public void surValidationMultiple(List<ChampSaisieEtendu> champs) {
                                                for (Iterator<ChampSaisieEtendu> iterator = champs.iterator(); iterator.hasNext();) {
                                                        ChampSaisieEtendu champSaisieEtendu = (ChampSaisieEtendu) iterator.next();
                                                        ajouterChampEtenduAuFormulaire(champSaisieEtendu, false);
                                                }
                                                popUpAjoutChampEtendu.clear();
                                                popUpAjoutChampEtendu.hide();
                                        }
                                };
                                popUpAjoutChampEtendu.add(formChamp);
                                popUpAjoutChampEtendu.center();         
                                popUpAjoutChampEtendu.setModal(true);
                                popUpAjoutChampEtendu.show();
                                formChamp.redimensionner(popUpAjoutChampEtendu.getOffsetWidth() - 13);
                        }
                });
        }
        
        private void ajouterChampEtenduAuFormulaire(ChampSaisieEtendu nChamp, boolean fermerPopup) {
                ChampEtendu chet = new ChampEtendu(nChamp.getCle(), nChamp.getLabel(), "");
                Map<String, ChampEtendu> champsEt = getValeursChampsEtendus();
                if(!champsEt.containsKey(chet.getCle())) {
                        champsEt.put(chet.getCle(), chet);
                        afficherChampsEtendus = true;
                        if(fermerPopup) {
                                afficherChampsEtendus(champsEt, chet);
                                popUpAjoutChampEtendu.clear();
                                popUpAjoutChampEtendu.hide();
                        } else {
                                afficherChampsEtendus(champsEt, null);
                        }
                } else {
                        String[] stParams = {chet.getLabel()};
                        Window.alert(Msg.get("indication-champ-etendu-existe-deja", stParams));
                }
        }

        private void ajouterToolTipsBoutons() {
                boutonOK.setTitle(Msg.get("indication-bouton-creer-obs"));
                boutonModifier.setTitle(Msg.get("indication-bouton-modifier-obs"));
                boutonSupprimer.setTitle(Msg.get("indication-bouton-supprimer-obs"));
                boutonReinitialiser.setTitle(Msg.get("indication-bouton-reinitialiser-obs"));
        }

        private void surPremierAffichageCoordPanel(final double largeur) {
                ExtElement lienCoord = Ext.get("lien_coord");
                lienCoord.removeAllListeners();
                lienCoord.addListener("click", new EventCallback() {
                        @Override
                        public void execute(EventObject e) {

                                coordPanel.setVisible(!coordPanel.isVisible());

                                if(Ext.isIE()) {
                                        latitude.focus();
                                }

                                CarnetEnLigneMediateur.fireResize();
                        }
                }) ;

                ExtElement lienCartoCoord = Ext.get("lien_carto_coord");
                lienCartoCoord.removeAllListeners();
                lienCartoCoord.addListener("click", new EventCallback() {
                        @Override
                        public void execute(EventObject e) {
                                obtenirInformationCoord();
                        }
                }) ;

                ExtElement lienCarto = Ext.get("lien_carto");
                lienCarto.removeAllListeners();
                lienCarto.addListener("click", new EventCallback() {

                        @Override
                        public void execute(EventObject e) {

                                if(localite.getText() != null && !localite.getText().equals("")) {
                                        obtenirInformationLocalite();
                                        longlatAjoutee = true;
                                } else {
                                        Window.alert(Msg.get("indication-localite-vide-invalide"));
                                }
                        }
                });

                if(!Ext.isIE() && Window.getClientWidth() < 1200) {

                        int largeurN = (int)largeur;

                        latitude.setWidth(largeurN+"px");
                        longitude.setWidth(largeurN+"px");
                        lienSelectionlocalite.setWidth(largeurN+"px");
                }
        }

        private void ajouterListeners()
        {
                // Listener completion communne
                final Rafraichissable r = this;
                  
                ListenerConfig listenerConfiglocalite=new ListenerConfig();
                listenerConfiglocalite.setDelay(200);
                listenerConfiglocalite.setStopPropagation(false);
                listenerConfiglocalite.setStopEvent(false);

            date.addListener(new DatePickerListenerAdapter() {

                        @Override
                        public void onSelect(DatePicker dataPicker, Date date) {
                                dateModifiee = true;
                        }
            });

            ListenerConfig listenerConfigAutocompletion=new ListenerConfig();
            listenerConfigAutocompletion.setDelay(200);
            listenerConfigAutocompletion.setStopPropagation(false);
            listenerConfigAutocompletion.setStopEvent(false);

                ListenerConfig listenerConfigEspece=new ListenerConfig();
                listenerConfigEspece.setDelay(10);
                listenerConfigEspece.setStopPropagation(false);
                listenerConfigEspece.setStopEvent(false);

                tCoord = new Timer() {

                        @Override
                        public void run() {
                        double[] coord = coordonneesValides();
                        if(!recherchelocaliteEnCours && coord != null && (longModifiee || latModifiee)) {
                                recherchelocaliteEnCours = true;
                                Ext.get(lienSelectionlocalite.getElement()).mask(Msg.get("recherche"));
                                observationMediateur.obtenirInformationCoord(r,coord[0], coord[1]);
                        }
                        }

                };

            ajouterListenerChampEvenementsClavier(date);
                ajouterListenerChampEvenementsClavier(selecteurReferentielTaxo);
                ajouterListenerChampEvenementsClavier(comment);
                ajouterListenerChampEvenementsClavier(latitude);
                ajouterListenerChampEvenementsClavier(longitude);
                ajouterListenerChampEvenementsClavier(altitude);
                ajouterListenerChampEvenementsClavier(selecteurAbondance);
                ajouterListenerChampEvenementsClavier(selecteurCertitude);
                ajouterListenerChampEvenementsClavier(selecteurStadePheno);
                ajouterListenerChampsCombobox();

                boutonOK.addListener(new ButtonListenerAdapter() {
                        @Override
                        public void onClick(Button button, EventObject e) {
                                ajouterObservation();
                        }
                });

                boutonModifier.addListener(new ButtonListenerAdapter() {
                        @Override
                        public void onClick(Button button, EventObject e) {
                                if(selectionMultiple) {
                                        modifierObservationEnMasse();
                                } else {
                                        modifierObservation() ;
                                }
                        }
                });

                boutonSupprimer.addListener(new ButtonListenerAdapter() {
                        @Override
                        public void onClick(Button button, EventObject e) {
                                if(!selectionMultiple) {
                                        supprimerObservation();
                                } else {
                                        observationMediateur.supprimerObservations();
                                }
                        }
                });

                boutonReinitialiser.addListener(new ButtonListenerAdapter() {
                        @Override
                        public void onClick(Button button, EventObject e) {
                                        setSelectionMultiple(false);
                                        raz();
                        }
                });

                this.addListener(new ContainerListenerAdapter() {
                        @Override
                        public void onAfterLayout(Container self) {
                                localite.focus();
                        }
                });
        }

        private void ajouterListenerChampsCombobox() {
                selecteurReferentielTaxo.addListener(new ComboBoxListenerAdapter() {
             @Override
                        public void onSelect(ComboBox comboBox, Record record, int index) {
                 referentielTaxo = record.getAsString("valeur");
                 observationMediateur.setRefTaxSelectionne(index);
                 referentielTaxoModifie = true;
             }
         });

                selecteurAbondance.addListener(new ComboBoxListenerAdapter() {
                        @Override
                        public void onSelect(ComboBox comboBox, Record record, int index) {
                 selectionAbondance=true;
                 abondanceModifiee = true;
             }
         });

                selecteurCertitude.addListener(new ComboBoxListenerAdapter() {

                        @Override
                        public void onSelect(ComboBox comboBox, Record record, int index) {
                 selectionCertitude=true;
                 certitudeModifiee = true;
             }
         });

                selecteurStadePheno.addListener(new ComboBoxListenerAdapter() {
                        @Override
                        public void onSelect(ComboBox comboBox, Record record, int index) {
                 selectionPhenologie=true;
                 phenologieModifiee = true;
             }
         });
        }

        private void ajouterListenerChampEvenementsClavier(final TextField champ) {
                champ.addKeyPressListener(new EventCallback() {
                        @Override
                        public void execute(EventObject e) {
                                surEvenementClavier(e, champ);
                        }
            });
        }

        private void ajouterListenerChampEvenementsClavier(final TextField champ, final ListenerConfig config) {
                champ.addKeyPressListener(new EventCallback() {
                        @Override
                        public void execute(EventObject e) {
                                surEvenementClavier(e, champ);
                        }
            }, config);
        }

        private void surEvenementClavier(EventObject e, TextField champ) {
                switch(e.getKey()) {
                        case KEY_ALT:
                        case KEY_CTRL:
                        case KEY_DOWN:
                        case KEY_END:
                        case KEY_ESCAPE:
                        case KEY_HOME:
                        case KEY_LEFT:
                        case KEY_PAGEDOWN:
                        case KEY_PAGEUP:
                        case KEY_RIGHT:
                        case KEY_SHIFT:
                        case KEY_TAB:
                        case KEY_UP:
                break;

                    case KEY_ENTER:
                        surEvenementClavierToucheEntree(champ);
                        break;

                default:
                        gererEvenementClavierDefaut(champ);
                break;
                }
        }

        private void surEvenementClavierToucheEntree(TextField champ) {
                //TODO: faire un switch ou une enum
                if(champ.equals(selecteurStadePheno)) {
                        if(!selectionPhenologie) {
                        validerSaisie(Champs.PHENOLOGIE); 
                } else {
                        selectionPhenologie = false;
                }
                }

                if(champ.equals(selecteurCertitude)) {
                        if(!selectionCertitude) {
                                validerSaisie(Champs.CERTITUDE); 
                } else {
                        selectionCertitude = false;
                }
                }

                if(champ.equals(selecteurAbondance)) {
                        if(!selectionAbondance) {
                        validerSaisie(Champs.ABONDANCE); 
                } else {
                        selectionAbondance = false;
                }
                }

                if(champ.equals(longitude)) {
                        validerSaisie(Champs.LONGITUDE);
                }

                if(champ.equals(latitude)) {                
                validerSaisie(Champs.LATITUDE);
                }

                if(champ.equals(altitude)) {                
                validerSaisie(Champs.ALTITUDE);
                }

                if(champ.equals(espece)) {
                        if(selectionEspece) {
                        especeModifiee = true;
                        selectionEspece=false;
                }
                else {
                        validerSaisie(Champs.ESPECE);               
                }
                }

                if(champ.equals(selecteurReferentielTaxo)) {
                        validerSaisie(Champs.REFERENTIELTAXO);
                }

                if(champ.equals(date)) {
                        validerSaisie(Champs.DATE);
                }

                if(champ.equals(localite)) {
                        if(champ.equals(localite)) {
                                if (selectionlocalite) {
                                 localiteModifiee= true;
                                 selectionlocalite=false;
                         }
                        else {
                                validerSaisie(Champs.LOCALITE);
                         }
                        }
                }
        }

        private void gererEvenementClavierDefaut(TextField champ) {
                //TODO: faire un switch ou une enum
                if(champ.equals(selecteurStadePheno)) {
                        selecteurStadePheno.setRawValue(selecteurStadePheno.getRawValue());
                        selecteurStadePheno.setValue(selecteurStadePheno.getRawValue());
                        phenologieModifiee = true;
                        selectionPhenologie = false;
                }

                if(champ.equals(selecteurCertitude)) {
                        selecteurCertitude.setRawValue(selecteurCertitude.getRawValue());
                selecteurCertitude.setValue(selecteurCertitude.getRawValue());
                certitudeModifiee = true;
                selectionCertitude = false;
                }

                if(champ.equals(selecteurAbondance)) {
                        selecteurAbondance.setRawValue(selecteurAbondance.getRawValue());
                selecteurAbondance.setValue(selecteurAbondance.getRawValue());
                abondanceModifiee = true;
                selectionAbondance = false;
                }

                if(champ.equals(longitude)) {
                        longModifiee = true;
                tCoord.cancel();
                tCoord.schedule(250);
                }

                if(champ.equals(latitude)) {                
                        latModifiee = true;
                tCoord.cancel();
                tCoord.schedule(250);
                }

                if(champ.equals(altitude)) {                
                        altModifiee = true;  
                }

                if(champ.equals(comment)) {
                        commModifie = true;
                }

                if(champ.equals(espece)) {
                        numeroNom="";
                especeModifiee = true;
                }

                if(champ.equals(selecteurReferentielTaxo)) {
                        referentielTaxoModifie = true;
                }

                if(champ.equals(date)) {
                        dateModifiee = true;
                }

                if(champ.equals(localite)) {
                        codeLocalite="";
                localite.collapse();
                localiteModifiee= true;
                }
        }

        /**
         * Validation de la saisie
         */

        private void validerSaisie(Champs champs) {
                if(!selectionMultiple) {
                        ajouterObservation();
                        raz(champs);
                } else {
                        modifierObservationEnMasse();
                }
        }

        /**
         * Desactive visuellement ce panneau
         */
        public void desactiverPanneau()
        {
                this.setDisabled(true) ;
        }

        /**
         * Active visuellement ce panneau
         */
        public void activerPanneau()
        {
                this.setDisabled(false) ;
        }

        @Override
        public void rafraichir(Object nouvelleDonnees, boolean repandreRaffraichissement) {

                // On recoit une observation dont on veut afficher le detail
                if(nouvelleDonnees instanceof Observation)
                {
                        Observation obs = (Observation)nouvelleDonnees ;
                        setSelectionMultiple(false);
                        afficherDetailsObservation(obs) ;
                }

                if(nouvelleDonnees instanceof ListeObservation) {

                        ListeObservation listeObs = (ListeObservation)nouvelleDonnees;
                        setSelectionMultiple(true);
                        calculerAfficherDifferences(listeObs);
                }

                if(nouvelleDonnees instanceof String)
                {
                        String str = (String)nouvelleDonnees ;
                        observationMediateur.obtenirNombreObservation() ;
                }

                if(nouvelleDonnees instanceof String[]) {
                        String[] anumNom = (String[])nouvelleDonnees ;
                        numeroNom = anumNom[1];
                        espece.setValue(anumNom[0]);
                }

                if(nouvelleDonnees instanceof EntiteGeographiqueObservation)
                {
                        EntiteGeographiqueObservation infosComm = (EntiteGeographiqueObservation)nouvelleDonnees ;
                        if(recherchelocaliteEnCours) {
                                afficherIndicationlocalite(infosComm);
                        } else {
                                rafraichirlocaliteEtCoord(infosComm);
                        }
                }
        }

        private void afficherIndicationlocalite(
                        final EntiteGeographiqueObservation infosCom) {

                String nlocalite = "";
                if(infosCom != null && infosCom.getZoneGeo() != null && !infosCom.getZoneGeo().trim().isEmpty()) {
                        nlocalite += infosCom.getZoneGeo();
                        if(infosCom.getIdZoneGeo() != null && !infosCom.getIdZoneGeo().trim().isEmpty()) {
                                if(Util.estUnDepartement(infosCom.getIdZoneGeo())) {
                                        nlocalite += " ("+Util.convertirChaineZoneGeoVersDepartement(infosCom.getIdZoneGeo())+")";
                                } else if(infosCom.getPays() != null && !infosCom.getPays().trim().isEmpty()) {
                                        nlocalite += " ("+infosCom.getPays()+")";
                                }
                        } else if(infosCom.getPays() != null && !infosCom.getPays().trim().isEmpty()) {
                                nlocalite += " ("+infosCom.getPays()+")";
                        }

                        lienSelectionlocalite.setHtml("<a id=\"lien_selection_localite\" tabindex=\"9\">"+nlocalite+"</a>");
                        lienSelectionlocalite.setStyleName("img-curseur-depl");

                        Ext.get("lien_selection_localite").addListener("click",new EventCallback() {
                                @Override
                                public void execute(EventObject e) {
                                        rafraichirlocalite(infosCom);
                                }
                        });

                        Ext.get("lien_selection_localite").addListener("keypress",new EventCallback() {
                                @Override
                                public void execute(EventObject e) {
                                        if(e.getCharCode() == KEY_ENTER) {
                                                rafraichirlocalite(infosCom);
                                        }
                                }
                        });

                        Ext.get("lien_selection_localite").addListener("focus",new EventCallback() {
                                @Override
                                public void execute(EventObject e) {
                                        Ext.get("lien_selection_localite").toggleClass("lien_sel");
                                }
                        });

                        Ext.get("lien_selection_localite").addListener("blur",new EventCallback() {
                                @Override
                                public void execute(EventObject e) {
                                        Ext.get("lien_selection_localite").toggleClass("lien_sel");
                                }
                        });

                } else {
                        if(recherchelocaliteEnCours) {
                                lienSelectionlocalite.setHtml("<span id=\"aucune_selection_localite\"> "+Msg.get("erreur-localisation")+" </span>");
                        } else {
                                lienSelectionlocalite.setHtml("<span id=\"aucune_selection_localite\"> </span>");
                        }
                }

                Ext.get(lienSelectionlocalite.getElement()).unmask();
                recherchelocaliteEnCours = false;
        }

        private void rafraichirlocalite(EntiteGeographiqueObservation infosCom) {
                String nlocalite = "";

                if(infosCom.getZoneGeo() != null && !infosCom.getZoneGeo().equals("")) {
                        nlocalite += infosCom.getZoneGeo();
                }
                
                if(infosCom.getIdZoneGeo() != null && Util.estUnDepartement(infosCom.getIdZoneGeo())) {
                        String codeGeoFormate = Util.convertirChaineZoneGeoVersDepartement(infosCom.getIdZoneGeo());
                        nlocalite += " ("+codeGeoFormate+")";
                        codeLocalite = Util.convertirChaineZoneGeoVersDepartement(infosCom.getIdZoneGeo());
                } else if(infosCom.getPays() != null && !infosCom.getPays().trim().isEmpty()) {
                        nlocalite += " ("+infosCom.getPays()+")";
                }
                
                if (!nlocalite.isEmpty()) {
                        // Vide ou null, on remplace !
                        if(localite.getText() == null || localite.getText().trim().isEmpty()) {
                                localite.setValue(nlocalite);
                        } else {
                                // Afin de pas effacer un pays précédemment saisi, si on a déjà saisi une localité
                                // avec le même nom mais avec un pays, on ne remplace rien
                                if(localite.getText() != null && !localite.getText().contains(nlocalite)) {
                                        localite.setValue(nlocalite);
                                }
                        }

                        localiteModifiee = true;
                }
        }

        // Se déclenche au retour de la "localisation sur la carte"
        private void rafraichirlocaliteEtCoord(EntiteGeographiqueObservation infosCom) {
                
                rafraichirlocalite(infosCom);
                if(infosCom.getLat() != null && !infosCom.getLat().equals("")) {
                        latitude.setValue(Util.tronquerNombrePourAffichage("" + infosCom.getLat(), 5));
                }

                if(infosCom.getLon() != null && !infosCom.getLon().equals("")) {
                        longitude.setValue(Util.tronquerNombrePourAffichage("" + infosCom.getLon(), 5));
                }

                latModifiee = true;
                longModifiee = true;

                coordPanel.setVisible(true);
        }

        public void ajouterObservation() {

                if(date.getRawValue() != null && !date.getRawValue().equals("") && !Util.verifierDateFormatCel(date.getRawValue())) {
                        Window.alert(Msg.get("indication-date-invalide"));
                        date.setInvalidText(Msg.get("date-invalide"));
                        return;
                }

                affecterCodeLocaliteOuPays();

                String dateObs = Util.remplacerSeparateursDateFormatCel(date.getRawValue());

                Observation obs=new Observation(espece.getText(),numeroNom,localite.getText(),codeLocalite,lieudit.getText(),station.getText(),milieu.getText(), comment.getText(),dateObs);

                String[] coords = getValeurCoordonnees();
                obs.setPays(pays);
                obs.setLatitude(coords[0]);
                obs.setLongitude(coords[1]);
                obs.setAltitude(altitude.getText());

                obs.setAbondance(getAbondance());
                obs.setCertitude(getCertitude());
                obs.setPhenologie(getPhenologie());

                obs.setReferentielTaxo(Ontologies.getInfosReferentielNomParCode(referentielTaxo).getCodeVersionComplet());
                obs.setChampsEtendus(getValeursChampsEtendus());

                observationMediateur.ajouterObservation(obs);
        }

        private void modifierObservation() {
                if(!Window.confirm(Msg.get("question-modifier-observation")+" ?")) {
                        return;
                }

                if(date.getRawValue() != null && !date.getRawValue().equals("") && !Util.verifierDateFormatCel(date.getRawValue())) {
                        Window.alert(Msg.get("indication-date-invalide"));
                        date.setInvalidText(Msg.get("date-invalide"));
                        return;
                }

                affecterCodeLocaliteOuPays();
                
                String dateObs = Util.remplacerSeparateursDateFormatCel(date.getRawValue());

                Observation obs=new Observation(espece.getText(),numeroNom,localite.getText(),codeLocalite,lieudit.getText(),station.getText(),milieu.getText(), comment.getText(),dateObs);
                obs.setNumeroOrdre(numeroOrdre);

                String[] coords = getValeurCoordonnees();

                obs.setPays(pays);
                obs.setLatitude(coords[0]);
                obs.setLongitude(coords[1]);
                obs.setAltitude(altitude.getText());

                obs.setAbondance(getAbondance());
                obs.setCertitude(getCertitude());
                obs.setPhenologie(getPhenologie());
                obs.setReferentielTaxo(getReferentielTaxo());
                obs.setChampsEtendus(getValeursChampsEtendus());

                observationMediateur.modifierObservation(obs);
        }

        private void affecterCodeLocaliteOuPays() {
                
                codeLocalite = "";
                pays = "";
                
                // Soit un numéro de département, soit un code de pays à deux lettres
                String[] codeCom = localite.getText().split(" ");
                if(codeCom.length > 1 && ressembleAUnCodePaysOuDepartement(codeCom[codeCom.length - 1])) {
                        String codeLoc = codeCom[codeCom.length - 1].replace('(', ' ');
                        codeLoc = codeLoc.replace(')', ' ').trim().replace('\\',' ').trim();

                        if(Util.estUnDepartement(codeLoc)) {
                                codeLocalite = codeLoc ;
                        } else {
                                pays = codeLoc.toUpperCase();
                        }
                }
        }
        
        private boolean ressembleAUnCodePaysOuDepartement(String s) {   
                String sP = s.replace("(", "").replace(")", "").trim();
                
                boolean contientDesParentheses = s.contains("(") && s.contains(")");
                boolean estUnCodePays = !Util.estUnNombre(sP) && (sP.length() == 2);
                boolean estUnCodeDepartement = Util.estUnNombre(sP) && (sP.length() >= 1 && sP.length() <= 5);
                
                return contientDesParentheses && (estUnCodePays || estUnCodeDepartement);
        }

        private void modifierObservationEnMasse() {

                //TODO: factoriser
                String paysM = null;
                String localiteM = null;
                String codeLocaliteM = null;
                String numNomSelM = null;
                String lieuDitM = null;
                String stationM = null;
                String milieuM = null;
                String dateM = null;
                String especeM = null;
                String commM = null;
                String latM = null;
                String longM = null;
                String altM = null;
                String abondanceM = null;
                String certitudeM = null;
                String referentielTaxoM = null;
                String phenologieM = null;

                String champs = modeleMessageModif;

                if(localiteModifiee && ! localite.getRawValue().equals(VALEURS_MULTIPLES)) {
                        
                        localiteM = localite.getText(); 
                        
                        // Soit un numéro de département, soit un code de pays à deux lettres
                        String[] codeCom = localite.getText().split(" ");
                        if(codeCom.length > 1) {
                                String codeLoc = codeCom[1].replace('(', ' ');
                                codeLoc = codeLoc.replace(')', ' ').trim().replace('\\',' ').trim();

                                if(Util.estUnDepartement(codeLoc)) {
                                        codeLocaliteM = codeLoc ;
                                } else {
                                        paysM = codeLoc;
                                }
                        }
                }
                else {
                        champs = champs.replaceAll("localite", "");
                }

                if(lieuDitModifie && ! lieudit.getRawValue().equals(VALEURS_MULTIPLES)) {
                        lieuDitM = lieudit.getText();
                } else {
                        champs = champs.replaceAll(":lieu-dit", "");
                }

                if(stationModifiee && ! station.getRawValue().equals(VALEURS_MULTIPLES)) {
                        stationM = station.getText();
                } else {
                        champs = champs.replaceAll(":station", "");
                }

                if(milieuModifie && ! milieu.getRawValue().equals(VALEURS_MULTIPLES)) {
                        milieuM = milieu.getText();
                } else {
                        champs = champs.replaceAll(":milieu", "");
                }

                if(dateModifiee && ! date.getRawValue().equals(VALEURS_MULTIPLES)) {
                        dateM = date.getRawValue();
                        dateM = Util.remplacerSeparateursDateFormatCel(dateM);
                } else {
                        champs = champs.replaceAll(":date", "");
                }

                if(especeModifiee && ! espece.getRawValue().equals(VALEURS_MULTIPLES)) {
                        especeM = espece.getText();
                        numNomSelM = numeroNom;
                } else {
                        champs = champs.replaceAll(":espece", "");
                }

                if(commModifie && ! comment.getRawValue().equals(VALEURS_MULTIPLES)) {
                        commM = comment.getText();
                } else {
                        champs = champs.replaceAll(":notes", "");
                }

                if(latModifiee && ! latitude.getRawValue().equals(VALEURS_MULTIPLES)) {
                        latM = latitude.getText();
                } else {
                        champs = champs.replaceAll(":latitude", "");
                }

                if(altModifiee && ! altitude.getRawValue().equals(VALEURS_MULTIPLES)) {
                        altM = altitude.getText();
                } else {
                        champs = champs.replaceAll(":altitude", "");
                }

                if(longModifiee && ! longitude.getRawValue().equals(VALEURS_MULTIPLES)) {
                        longM = longitude.getText();
                } else {
                        champs = champs.replaceAll(":longitude", "");
                }

                if(abondanceModifiee && !selecteurAbondance.getRawValue().equals(VALEURS_MULTIPLES)) {
                        abondanceM = getAbondance();
                } else {
                        champs = champs.replaceAll(":abondance", "");
                }

                if(certitudeModifiee && !selecteurCertitude.getRawValue().equals(VALEURS_MULTIPLES)) {
                        certitudeM = getCertitude();
                } else {
                        champs = champs.replaceAll(":identification", "");
                }

                if(referentielTaxoModifie && !selecteurReferentielTaxo.getRawValue().equals(VALEURS_MULTIPLES)) {
                        referentielTaxoM = getReferentielTaxo();
                } else {
                        champs = champs.replaceAll(":referentiel", "");
                }

                if(phenologieModifiee && !selecteurStadePheno.getRawValue().equals(VALEURS_MULTIPLES)) {
                        phenologieM = getPhenologie();
                } else {
                        champs = champs.replaceAll(":phenologie", "");
                }
                
                // TODO : trouver un meilleur système que ça pour gérer le message
                // affiché
                String[] champsSt = champs.split(":");
                String champsTraduits = "";
                for (int i = 0; i < champsSt.length; i++) {
                        // TODO: vérifier pourquoi des fois la chaîne est vide
                        // ou faire mieux, trouver un meilleur système comme écrit au dessus !
                        if(!champsSt[i].trim().isEmpty()) {
                                champsTraduits += Msg.get(champsSt[i]);
                                champsTraduits += (i != champsSt.length - 1) ? ", " : "";
                        }
                }

                String[] stParams = {champsTraduits};
                String message = Msg.get("question-modifier-champs-observation", stParams)+" ?" ;

                if(champs.trim().equals("")) {
                        Window.alert(Msg.get("indication-aucun-champ-modifie"));
                } else {
                        Observation obs = new Observation(especeM,numNomSelM,localiteM,codeLocaliteM,lieuDitM,stationM,milieuM, commM,dateM);
                        obs.setPays(paysM);
                        obs.setNumeroOrdre(numeroOrdre);
                        obs.setLatitude(latM);
                        obs.setLongitude(longM);
                        obs.setAltitude(altM);
                        obs.setAbondance(abondanceM);
                        obs.setCertitude(certitudeM);
                        // Afin de transmettre un ensemble cohérent on force aussi
                        // l'envoi du référentiel en cas de maj de l'espèce
                        if(especeModifiee) {
                                referentielTaxoM = getReferentielTaxo();
                        }
                        obs.setReferentielTaxo(referentielTaxoM);
                        obs.setPhenologie(phenologieM);
                        if(Window.confirm(message)) {
                                observationMediateur.modifierObservationEnMasse(obs);
                                reinitialiserValeurModifiees();
                        }
                }
        }

        private void supprimerObservation() {
                observationMediateur.supprimerObservation(this, numeroOrdre);
        }

        public void afficherDetailsObservation(Observation obs)
        {
                raz() ;
                String idLoc ;
                if(obs.getIdentifiantLocalite() != VALEURS_MULTIPLES) {
                        idLoc = obs.getIdentifiantLocalite().replaceAll(" ","/");
                        idLoc = idLoc.replaceAll("%","");
                        idLoc = idLoc.replaceAll("\"","");
                        idLoc = idLoc.replace('\\',' ');
                        idLoc = idLoc.trim();
                        if(idLoc.length() == 5) {
                                idLoc = idLoc.substring(0,2);
                        }
                } else {
                        idLoc = obs.getIdentifiantLocalite();
                        if(idLoc.length() == 5) {
                                idLoc = idLoc.substring(0,2);
                        }
                }
                
                if(obs.getIdentifiantLocalite().isEmpty() && !obs.getPays().isEmpty()) {
                        idLoc = obs.getPays();
                }

                if(!obs.getDate().equals("null") && !obs.getDate().equals("000null") && !obs.getDate().equals(VALEURS_MULTIPLES)) {
                        String[] dateEtHeure = obs.getDate().split(" ", 2);
                        if(verifierFormatDate(dateEtHeure[0])) {
                                date.setValue(dateEtHeure[0]) ;
                        }
                        else
                        {
                                date.setRawValue("");
                        }
                } else {
                        date.setRawValue(VALEURS_MULTIPLES);
                        date.clearInvalid();
                }
                if(!obs.getLieudit().equals("null") && !obs.getLieudit().equals("000null")) {
                        lieudit.setValue(obs.getLieudit()) ;
                }
                if(!obs.getStation().equals("null") && !obs.getStation().equals("000null")) {
                        station.setValue(obs.getStation()) ;
                }
                if(!obs.getMilieu().equals("null") && !obs.getMilieu().equals("000null")) {
                        milieu.setValue(obs.getMilieu()) ;
                }
                if(!obs.getCommentaire().equals("null") && !obs.getCommentaire().equals("000null")) {

                        comment.setRawValue(Util.remplacerSautsDeligneMalEncodes(obs.getCommentaire()));

                }
                if(!obs.getLocalite().equals("null") && !obs.getLocalite().equals("000null")) {
                        if(!idLoc.equals("000null") && !idLoc.equals("")) {
                                if(!idLoc.equals(VALEURS_MULTIPLES)) {
                                        localite.setValue(obs.getLocalite()+" ("+idLoc+")") ;
                                } else {
                                        localite.setValue(VALEURS_MULTIPLES);
                                }
                        }
                        else
                        {
                                localite.setValue(obs.getLocalite());
                        }
                }
                if(!obs.getIdentifiantLocalite().equals("null") && !obs.getIdentifiantLocalite().equals("000null")) {
                        codeLocalite = idLoc;
                }
                if(!obs.getNomSaisi().equals("null") && !obs.getNomSaisi().equals("000null")) {
                        espece.setValue(obs.getNomSaisi()) ;
                }
                if(!obs.getNumeroNomenclaturalSaisi().equals("null") && !obs.getNumeroNomenclaturalSaisi().equals("000null")) {
                        numeroNom = obs.getNumeroNomenclaturalSaisi() ;
                }
                if(!obs.getNumeroOrdre().equals("null") && !obs.getNumeroOrdre().equals("000null")) {
                        numeroOrdre = obs.getNumeroOrdre() ;
                }

                if(doitAfficherLatLon(obs)) {
                        latitude.setValue(Util.formaterNombre(obs.getLatitude())) ;
                        longitude.setValue(Util.formaterNombre(obs.getLongitude())) ;
                }

                if(!obs.getAltitude().isEmpty() && !obs.getAltitude().equals("null") && !obs.getAltitude().equals("000null")) {
                        altitude.setValue(Util.formaterNombre(obs.getAltitude())) ;
                }

                selecteurAbondance.getStore().load();
                selecteurAbondance.setValue(obs.getAbondance());

                selecteurCertitude.getStore().load();
                selecteurCertitude.setValue(obs.getCertitude());

                selecteurStadePheno.getStore().load();
                selecteurStadePheno.setValue(obs.getPhenologie());

                selecteurReferentielTaxo.getStore().load();
                if(obs.getReferentielTaxo() != VALEURS_MULTIPLES) {
                        referentielTaxo = obs.getCodeCourtReferentielTaxo();
                        if(referentielTaxo == null || referentielTaxo.isEmpty()) {
                            referentielTaxo = Configuration.getReferentielsDispos().get(0).getCode();
                        }
                        selecteurReferentielTaxo.setValue(referentielTaxo);
                } else {
                        referentielTaxo = "";
                        selecteurReferentielTaxo.setRawValue(VALEURS_MULTIPLES);
                }

                afficherChampsEtendus(obs.getChampsEtendus(), null);
        }

        private boolean doitAfficherLatLon(Observation obs) {
                return !obs.getLatitude().isEmpty() &&
                                !obs.getLatitude().equals("null") &&
                                !obs.getLatitude().equals("000null") &&
                                !Util.estZero(obs.getLatitude()) &&
                                !obs.getLongitude().isEmpty() &&
                                !obs.getLongitude().equals("null") &&
                                !obs.getLongitude().equals("000null") &&
                                !Util.estZero(obs.getLongitude());
        }

        private void viderChampsEtendus() {
                if(listeChampsEtendus != null) {
                        for (Iterator<String> it = listeChampsEtendus.keySet().iterator(); it.hasNext();) {
                                ChampSaisieEtendu champEtendu = listeChampsEtendus.get(it.next());
                                champEtendu.destroy();
                        }
                        if(conteneurChampEtenduGauche != null && conteneurChampEtenduDroite != null) {
                                conteneurChampEtenduGauche.clear();
                                conteneurChampEtenduDroite.clear();
                                panneauPremierColonne.remove(conteneurChampEtenduGauche);
                                panneauSecondeColonne.remove(conteneurChampEtenduDroite);
                        }
                        listeChampsEtendus = null;
                }
        }

        private void afficherChampsEtendus(Map<String, ChampEtendu> champsEtendus, ChampEtendu champsAFocus) {
                champsEtendus = Util.trierListeChampsEtendus(champsEtendus);
                viderChampsEtendus();

                FormLayout flmd = new FormLayout();
                flmd.setLabelWidth(150);

                FormLayout flmg = new FormLayout();
                flmg.setLabelWidth(150);

                conteneurChampEtenduGauche = new Panel();
                conteneurChampEtenduGauche.setLayout(flmg);
                conteneurChampEtenduDroite = new Panel();
                conteneurChampEtenduDroite.setLayout(flmd);

                conteneurChampEtenduGauche.setAutoWidth(true);
                conteneurChampEtenduGauche.setStyle("conteneurChampsEtendus");
                conteneurChampEtenduGauche.setBodyBorder(false);
                conteneurChampEtenduDroite.setAutoWidth(true);
                conteneurChampEtenduDroite.setStyle("conteneurChampsEtendus");
                conteneurChampEtenduDroite.setBodyBorder(false);

                // pour corriger le décalage sur le panneau induit par le lien d'affichage
                conteneurChampEtenduDroite.setPaddings(42, 0, 0, 0);

                if(champsEtendus != null && champsEtendus.size() > 0) {
                        lienAfficherChampsEtendus.setVisible(true);
                        listeChampsEtendus = new HashMap<String, ChampSaisieEtendu>(champsEtendus.size());
                        HashMap<String, String> correspondancesClesLabel = ListeReferentielChampsEtendusDAO.cacheClesLabels;
                        boolean gauche = true;
                        for (Iterator<String> iterator = champsEtendus.keySet().iterator(); iterator.hasNext();) {
                                
                                String id = iterator.next();
                                ChampEtendu champ = champsEtendus.get(id);
                                
                                String valeur = champ.getValeur();
                                String label = id;
                                
                                // Si le champ possède un clé déjà définie par le catalogue, elle lui sera affectée
                                // sinon on la formate en la "déchamotant" et en ajoutant des espaces
                                if(correspondancesClesLabel.containsKey(id)) {
                                        label = correspondancesClesLabel.get(id);
                                } else {
                                        label = Util.formaterCleChampsEtenduPourAffichage(label);
                                }

                                ChampSaisieEtendu champTexteEtendu = new ChampSaisieEtendu(label, id, ListeReferentielChampsEtendusDAO.getUrlRequeteValeursChampEtendu(id));
                                if(champ.equals(champsAFocus)) {
                                        champTexteEtendu.focus();
                                }
                                
                                champTexteEtendu.setId(id);
                                champTexteEtendu.setValue(valeur);
                                if(gauche) {
                                        conteneurChampEtenduGauche.add(champTexteEtendu);
                                } else {
                                        conteneurChampEtenduDroite.add(champTexteEtendu);
                                }
                                listeChampsEtendus.put(id, champTexteEtendu);
                                gauche = !gauche;
                        }

                        panneauPremierColonne.add(conteneurChampEtenduGauche);
                        panneauSecondeColonne.add(conteneurChampEtenduDroite);

                        if(!afficherChampsEtendus) {
                                conteneurChampEtenduGauche.setVisible(false);
                                conteneurChampEtenduDroite.setVisible(false);
                        } else {
                                redimensionnerChampsEtendus();
                        }
                } else {
                        lienAfficherChampsEtendus.setVisible(false);
                }
                doLayout();
        }
        
        private void redimensionnerChampsEtendus() {
                int largeur = conteneurChampEtenduGauche.getWidth();
                if(largeur <= 0) {
                        Timer t = new Timer() {         
                                @Override
                                public void run() {
                                        redimensionnerChampsEtendus();
                                }
                        };
                        t.schedule(150);
                } else {
                        for (Iterator<String> iterator = listeChampsEtendus.keySet().iterator(); iterator
                                        .hasNext();) {
                                ChampSaisieEtendu ch = listeChampsEtendus.get(iterator.next());
                                ch.redimensionner(largeur - 15);        
                                if(ch.getFieldWidth() < ch.getLabelWidth()) {
                                        ch.addClass("panneauModePetiteLargeur");
                                        ch.agrandirChamp(largeur - 82);
                                } else {
                                        //ch.removeClass("panneauModePetiteLargeur");
                                }
                        }
                }
        }

        private Map<String, ChampEtendu> getValeursChampsEtendus() {
                Map<String, ChampEtendu> valeursChampsEtendus = new HashMap<String, ChampEtendu>();
                if(listeChampsEtendus != null) {
                        for (Iterator<String> it = listeChampsEtendus.keySet().iterator(); it.hasNext();) {
                                String cle = it.next();
                                ChampSaisieEtendu champTexteEtendu = listeChampsEtendus.get(cle);
                                String label = champTexteEtendu.getLabel();
                                String valeur = champTexteEtendu.getRawValue();
                                ChampEtendu champEtendu = new ChampEtendu(cle, label, valeur);
                                valeursChampsEtendus.put(cle, champEtendu);
                        }
                }
                return valeursChampsEtendus;
        }

        public void raz()
        {
                raz(Champs.TOUT);

        }
        public void raz(Champs champs)
        {
                switch (champs) {
                        case DATE:
                                date.reset() ;
                                break;

                        case LIEUDIT:
                                lieudit.reset() ;
                                break;

                        case STATION:
                                station.reset() ;
                                break;

                        case MILIEU:
                                milieu.reset() ;
                                break;

                        case COMMENT:
                                comment.reset() ;
                                break;

                        case LOCALITE:
                                localite.reset() ;
                                codeLocalite ="";
                                pays="";
                                latitude.reset();
                                longitude.reset();
                                break;

                        case ESPECE:
                                espece.reset();
                                numeroNom = "" ;
                                numeroOrdre = "";
                                break;

                        case LATITUDE:
                                latitude.reset();
                                afficherIndicationlocalite(null);
                                break;

                        case LONGITUDE:
                                longitude.reset();
                                afficherIndicationlocalite(null);
                                break;

                        case ALTITUDE:
                                altitude.reset();
                                break;

                        case ABONDANCE:
                                selecteurAbondance.setValue("");
                                break;

                        case CERTITUDE:
                                selecteurCertitude.setValue("");
                                break;

                        case REFERENTIELTAXO:
                                selecteurReferentielTaxo.setValue("");
                                break;

                        case PHENOLOGIE:
                                selecteurStadePheno.setValue("");
                                break;

                        case TOUT:
                                localite.reset();
                                date.reset() ;
                                lieudit.reset() ;
                                station.reset() ;
                                milieu.reset() ;
                                comment.reset() ;
                                milieu.reset() ;
                                latitude.reset();
                                longitude.reset();
                                altitude.reset();
                                pays="";
                                codeLocalite ="";
                                espece.reset();
                                selecteurAbondance.clearValue();
                                selecteurCertitude.clearValue();
                                selecteurReferentielTaxo.clearValue();
                                selecteurStadePheno.clearValue();
                                referentielTaxo = "";
                                numeroNom = "" ;
                                numeroOrdre = "";
                                afficherIndicationlocalite(null);
                                break;

                }

        }

        public boolean verifierFormatDate(String date) {

                String regex = "[1-9][0-9]{3}-[0-9]{2}-[0-9]{2}" ;
                if(date.matches(regex) && !date.equals("0000-00-00")) {
                        return true ;
                }
                else {
                        return false;
                }
        }

        public void setSelectionMultiple(boolean selectionMultiple) {
                this.selectionMultiple = selectionMultiple;
                if(!selectionMultiple) {
                        boutonReinitialiser.enable();
                        boutonOK.enable();
                } else {
                        boutonReinitialiser.disable();
                        boutonOK.disable();
                }
        }

        public boolean getSelectionMultiple() {
                return selectionMultiple;
        }

        private void calculerAfficherDifferences(ListeObservation listeObs) {

                String codeLocalite = null;
                String pays = null;
                String localite = null;
                String lieuDit = null;
                String station = null;
                String milieu = null;
                String espece = null;
                String date = null;
                String notes = null;
                String lat = null;
                String lon = null;
                String alt = null;
                String abondance = null;
                String certitude = null;
                String referentielTaxo = null;
                String phenologie = null;

                String ordreObs = "";

                for(Iterator<String> it = listeObs.keySet().iterator();it.hasNext();) {
                        Observation obsEnCours = listeObs.get(it.next());
                        pays = comparerDifferencesChamps(pays, obsEnCours.getPays());
                        codeLocalite = comparerDifferencesChamps(codeLocalite, obsEnCours.getIdentifiantLocalite());
                        localite = comparerDifferencesChamps(localite, obsEnCours.getLocalite());
                        lieuDit = comparerDifferencesChamps(lieuDit, obsEnCours.getLieudit());
                        station = comparerDifferencesChamps(station, obsEnCours.getStation());
                        milieu = comparerDifferencesChamps(milieu, obsEnCours.getMilieu());
                        espece = comparerDifferencesChamps(espece, obsEnCours.getNomSaisi());
                        date = comparerDifferencesChamps(date, obsEnCours.getDate());
                        notes = comparerDifferencesChamps(notes, obsEnCours.getCommentaire());
                        lat = comparerDifferencesChamps(lat, obsEnCours.getLatitude());
                        lon = comparerDifferencesChamps(lon, obsEnCours.getLongitude());
                        alt = comparerDifferencesChamps(alt, obsEnCours.getAltitude());
                        abondance = comparerDifferencesChamps(abondance, obsEnCours.getAbondance());
                        certitude = comparerDifferencesChamps(certitude, obsEnCours.getCertitude());
                        referentielTaxo = comparerDifferencesChamps(referentielTaxo, obsEnCours.getReferentielTaxo());
                        phenologie = comparerDifferencesChamps(phenologie, obsEnCours.getPhenologie());

                        ordreObs += obsEnCours.getNumeroOrdre()+",";
                }

                Observation obs=new Observation(espece,numeroNom,localite,codeLocalite,lieuDit,station,milieu, notes,date);
                obs.setPays(pays);
                obs.setNumeroOrdre(ordreObs);
                obs.setLatitude(lat);
                obs.setLongitude(lon);
                obs.setAltitude(alt);
                obs.setAbondance(abondance);
                obs.setCertitude(certitude);
                obs.setReferentielTaxo(referentielTaxo);
                obs.setPhenologie(phenologie);
                afficherDetailsObservation(obs);
        }

        private String comparerDifferencesChamps(String valeurActuelle, String nouvelleValeur) {

                String retour = "";

                        if(valeurActuelle == null) {
                                retour = nouvelleValeur;
                        } else {
                                if(valeurActuelle.equals(nouvelleValeur)) {
                                        retour = valeurActuelle;
                                } else {
                                        retour = VALEURS_MULTIPLES;
                                }
                        }
                return retour;
        }

        private void reinitialiserValeurModifiees() {
                localiteModifiee = false;
                lieuDitModifie = false;
                stationModifiee = false;
                milieuModifie = false;
                dateModifiee = false;
                especeModifiee = false;
                commModifie = false;
                latModifiee = false;
                longModifiee = false;
                altModifiee = false;
                abondanceModifiee = false;
                certitudeModifiee = false;
                referentielTaxoModifie = false;
                phenologieModifiee = false;
        }

        public void saisieTabindex()
        {
                localite.setTabIndex(1);
                lieudit.setTabIndex(3);
                station.setTabIndex(4);
                milieu.setTabIndex(5);
                coordonnees.setTabIndex(-1);
                coordonnees.addListener(new TextFieldListenerAdapter() {

                        @Override
                        public void onFocus(Field field) {
                                if(coordPanel.isVisible()) {
                                        latitude.focus();
                                } else {
                                        Ext.get("lien_carto").focus();
                                }
                        }
                });

                latitude.setTabIndex(8);
                longitude.setTabIndex(9);
                altitude.setTabIndex(10);
                comment.setTabIndex(11);
                date.setTabIndex(12);
                espece.setTabIndex(13);
                selecteurCertitude.setTabIndex(14);
                selecteurAbondance.setTabIndex(15);
                selecteurStadePheno.setTabIndex(16);
                boutonOK.setTabIndex(17);
                boutonReinitialiser.setTabIndex(18);

        }

        private void obtenirInformationCoord() {
                if(coordonneesValides() != null) {
                        observationMediateur.obtenirInformationCoord(coordonneesValides()[0],coordonneesValides()[1]);
                } else {
                        // Centrage de la carte sur une zone correspondant plus ou moins au référentiel.
                        // En dur car la config est tellement mal foutue que j'ai envie de me pendre.
                        String referentiel = this.getReferentielTaxo();
                        String referentielRacine = referentiel.substring(0, referentiel.indexOf(':'));
                        Double lat = null, lon = null;
                        int zoom = 6;
                        switch(referentielRacine) {
                                case "bdtre" :
                                        lat = -21.10;
                                        lon = 55.30;
                                        zoom = 7;
                                break;
                                case "isfan" :
                                        lat = 29.28358;
                                        lon = 10.21884;
                                        zoom = 5;
                                        break;
                                case "apd" :
                                        lat = 8.75624;
                                        lon = 1.80176;
                                        zoom = 5;
                                        break;
                                case "bdtxa" :
                                        lat = 14.6;
                                        lon = -61.08334;
                                        zoom = 7;
                                        break;
                                case "lbf" :
                                        lat = 33.53;
                                        lon = 35.30;
                                        zoom = 7;
                                        break;
                                case "florical" :
                                        lat = -21.40722;
                                        lon = 165.4541;
                                        zoom = 7;
                                        break;
                                case "aublet" :
                                        lat = 3.80287;
                                        lon = -53.09692;
                                        zoom = 7;
                                        break;
                                case "bdtfx" :
                                default:
                                        lat = 47.0504;
                                        lon = 2.2347;
                                        zoom = 6;
                        }
                        if (lat != null && lon != null) {
                                // centrage sur la zone
                                EntiteGeographiqueObservation infos = new EntiteGeographiqueObservation();
                                infos.setLon("" + lon);
                                infos.setLat("" + lat);
                                infos.setZoom(zoom);
                                observationMediateur.rafraichirFenetreCartoSurPoint(infos);
                        } else {
                                // affichage par défaut au cas où on n'aurait pas trouvé de coordonnées pour centrer
                                observationMediateur.afficherFenetreCarto();
                        }
                }
        }

        private void obtenirInformationLocalite() {
                String idLoc = obtenirIdLocalite();
                observationMediateur.obtenirInformationLocalite(getlocaliteSansIdLoc(), idLoc);
        }
        
        private String obtenirIdLocalite() {
                String idLoc = "";
                
                // Soit un numéro de département, soit un code de pays à deux lettres
                String[] codeCom = localite.getText().split(" ");
                if(codeCom.length > 1 && ressembleAUnCodePaysOuDepartement(codeCom[codeCom.length - 1])) {
                        String codeLoc = codeCom[codeCom.length - 1].replace('(', ' ');
                        codeLoc = codeLoc.replace(')', ' ').trim().replace('\\',' ').trim();

                        if(Util.estUnNombre(codeLoc)) {
                                idLoc = codeLoc ;
                        } else {
                                idLoc = codeLoc.toUpperCase();
                        }
                }
                
                return idLoc;
        }

        public double[] coordonneesValides() {
                try {

                        double lat = Double.parseDouble(latitude.getValueAsString().replaceAll(",", "."));
                        double lon = Double.parseDouble(longitude.getValueAsString().replaceAll(",", "."));

                        double[] coord = {lat, lon};
                        return coord;

                } catch (NumberFormatException ne) {
                        return null;
                }
        }

        private String[] getValeurCoordonnees() {
                double[] coDouble = coordonneesValides();

                if(coDouble != null) {
                        String[] coord = {coDouble[0]+"",coDouble[1]+""};
                        return coord;
                } else {
                        String[] coord = {"","" };
                        return coord;
                }
        }

        public String getlocalite() {

                String valeurlocalite = "";

                if(localite.getText() != null) {
                        valeurlocalite = localite.getText();
                }
                return valeurlocalite;
        }

        public String getlocaliteSansIdLoc() {
                return Util.supprimerChaineIdLocalite(getlocalite());
        }

        private String getValeurChampListeLibre(ComboBox champ) {
                String valeurChamp = champ.getValue();
                String valeurChampBrute = champ.getRawValue();

                // Test idiot qui permet de savoir si l'on utilise la valeur saisie directement ou bien la valeur
                // selectionnee car lors du setValue sur le keypress, gwtext ne prends pas en compte le dernier
                // caractère
                if(valeurChampBrute.trim().length() == 0) {
                        valeurChamp = "";
                } else {
                        if(valeurChamp != null && valeurChamp.length() > 0) {
                                if(valeurChamp.equals(valeurChampBrute.substring(0, valeurChampBrute.length() -1))) {
                                        valeurChamp = champ.getRawValue();
                                }
                        }
                }
                return valeurChamp;
        }

        public String getAbondance() {
                return getValeurChampListeLibre(selecteurAbondance);
        }

        public String getCertitude() {
                return getValeurChampListeLibre(selecteurCertitude);
        }

        public String getPhenologie() {
                return getValeurChampListeLibre(selecteurStadePheno);
        }

        public String getReferentielTaxo() {
                String codeCourt = getValeurChampListeLibre(selecteurReferentielTaxo);
                return Ontologies.getInfosReferentielNomParCode(codeCourt).getCodeVersionComplet();
        }

        public boolean localiteInitialisee() {
                return localiteModifiee;
        }

        public void redimensionnerFormulaire() {
                afficherFormulaireLatLon.setWidth(panneauIntermediaire.getWidth()+"px");
                panneauPremierColonne.doLayout();
                panneauSecondeColonne.doLayout();
                panneauIntermediaire.doLayout();

                doLayout();
        }
        
        private void verifierPresenceTaxonSaisi() {
                affecterCodeLocaliteOuPays();
                if(!enRequeteChrologie && !codeLocalite.isEmpty() && numeroNom != null && !numeroNom.isEmpty()) {
                        enRequeteChrologie = true;
                        // Pour le moment, si on a un code localité, c'est qu'on est en France
                        final String paysStr = pays.isEmpty() ? "FR" : pays;
                        final String cleCache = numeroNom.trim()+paysStr.trim()+codeLocalite.trim();

                        // Pour éviter de vérifier et d'afficher plus d'une fois l'avertissement de présence
                        if(!avertissementPresence.containsKey(cleCache)) {
                                // Pour l'instant c'est toujours France mais il serait bon un jour d'avoir une chorologie multi pays.
                                // donc ça ne coute rien de le gérer déjà ici dans l'interface
                                ImageInformationRepartitionAsynchroneDAO.taxonEstPresentDansZoneGeo(referentielTaxo, numeroNom, paysStr, codeLocalite, new Callback<String, String>() {                 
                                        @Override
                                        public void onSuccess(String result) {
                                                
                                                // En cas d'absence d'infos sur la zone le service retourne "" (chaîne vide)
                                                // En cas de non signalement dans la zone, il retourne 0, 
                                                // En cas de présence, il retourne 1 
                                                if(result.equals("0")) {
                                                        // L'absence explicite est le seul cas qui nous interesse
                                                        String[] stParams = {espece.getText(), codeLocalite, Configuration.getChorologieAvertissementCourriel()};
                                                        String message = Msg.get("indication-premiere-presence", stParams);
                                                        
                                                        Window.alert(message);
                                                }

                                                avertissementPresence.put(cleCache, result);
                                                enRequeteChrologie = false;
                                        }
                                        
                                        @Override
                                        public void onFailure(String reason) {
                                                enRequeteChrologie = false;
                                        }
                                });
                        } else {
                                enRequeteChrologie = false;
                        }
                }
        }
}