class Noeud extends ElementCarteTopo {

  public Groupe plusCourtChemin(Noeud arrivee, double maxLongueur) {

    // Noeud.logger.debug("shortest path between " + this.getCoord() + " - " + arrivee.getCoord());

    List<Noeud> noeudsFinaux = new ArrayList<Noeud>(0);
    List<Arc> arcsFinaux = new ArrayList<Arc>(0);
    List<Noeud> noeudsVoisins = new ArrayList<Noeud>(0);
    List<Arc> arcsVoisins = new ArrayList<Arc>(0);
    List<Double> distancesVoisins = new ArrayList<Double>(0);
    List<Noeud> traites = new ArrayList<Noeud>(0);
    List<Noeud> aTraiter = new ArrayList<Noeud>(0);
    int i;
    Arc arcVoisin;
    Noeud noeudVoisin, plusProche, suivant;
    double dist;

    try {

      if (this.getCarteTopo() == null) {
        Noeud.logger.error("ATTENTION : le noeud " + this + " ne fait pas partie d'une carte topo");
        Noeud.logger.error("            Impossible de calculer un plus court chemin");
        return null;
      }

      if (this.getCarteTopo().getPopGroupes() == null) {
        Noeud.logger.error("ATTENTION : le noeud " + this
            + " fait partie d'une carte topo sans population de groupes");
        Noeud.logger.error("            Impossible de calculer un plus court chemin");
        return null;
      }

      Groupe plusCourtChemin = this.getCarteTopo().getPopGroupes().nouvelElement();
      
      // Schema ??? - Quels attributs ???
      plusCourtChemin.setSchema(this.getSchema());
      
      
      if (this == arrivee) {
          Noeud.logger.debug("node is arrival");
          plusCourtChemin.addNoeud(this);
          this.addGroupe(plusCourtChemin);
          return plusCourtChemin;
      }

      this.distance = 0;
      this.chercheArcsNoeudsVoisins(noeudsVoisins, distancesVoisins, arcsVoisins);
      // logger.info("voisins " + noeudsVoisins.size());

      for (i = 0; i < noeudsVoisins.size(); i++) {
        noeudVoisin = noeudsVoisins.get(i);
        arcVoisin = arcsVoisins.get(i);
        dist = distancesVoisins.get(i).doubleValue();
        noeudVoisin.distance = dist;
        noeudVoisin.arcPrecedent = arcVoisin;
        noeudVoisin.noeudPrecedent = this;
      }
      aTraiter.addAll(noeudsVoisins);

      // Phase "avant"
      while (!aTraiter.isEmpty()) {
        // choisi le noeud à marquer comme traité parmi les voisins
        plusProche = aTraiter.get(0);
        for (i = 1; i < aTraiter.size(); i++) {
          if (aTraiter.get(i).distance < plusProche.distance) {
            plusProche = aTraiter.get(i);
          }
        }
        // logger.info("plus proche " + plusProche);
        traites.add(plusProche);
        aTraiter.remove(plusProche);
        // il s'agit du noeud d'arrivée
        if (plusProche == arrivee) {
          // logger.info("arrivé !!!");
          break;
        }
        if (maxLongueur != 0) {
          if (plusProche.distance > maxLongueur) {
            // Noeud.logger.debug("Trop long, on s'arrête");
            return null; // heuristique pour stopper la recherche
          }
        }
        plusProche.chercheArcsNoeudsVoisins(noeudsVoisins, distancesVoisins, arcsVoisins);
        // logger.info("voisins " + noeudsVoisins.size());
        for (i = 0; i < noeudsVoisins.size(); i++) {
          noeudVoisin = noeudsVoisins.get(i);
          arcVoisin = arcsVoisins.get(i);
          dist = distancesVoisins.get(i).doubleValue();
          if (traites.contains(noeudVoisin)) {
            continue; // Noeud déjà traité
          }
          if (aTraiter.contains(noeudVoisin)) {
            // Noeud déjà atteint, on voit si on a trouvé un chemin
            // plus court pour y accèder
            if (noeudVoisin.distance > (plusProche.distance + dist)) {
              noeudVoisin.distance = plusProche.distance + dist;
              noeudVoisin.arcPrecedent = arcVoisin;
              noeudVoisin.noeudPrecedent = plusProche;
            }
            continue;
          }
          // Nouveau noeud atteint, on l'initialise
          noeudVoisin.distance = plusProche.distance + dist;
          noeudVoisin.arcPrecedent = arcVoisin;
          noeudVoisin.noeudPrecedent = plusProche;
          aTraiter.add(noeudVoisin);
        }
      }

      // Phase "arriere"
      if (!traites.contains(arrivee)) {
        Noeud.logger.debug("couldn't reach it");
        return null;
      }
      suivant = arrivee;
      while (true) {
        arcsFinaux.add(0, suivant.arcPrecedent);
        suivant.arcPrecedent.addGroupe(plusCourtChemin);
        suivant = suivant.noeudPrecedent;
        if (suivant == this) {
          break;
        }
        noeudsFinaux.add(0, suivant);
        suivant.addGroupe(plusCourtChemin);
      }
      noeudsFinaux.add(0, this);
      this.addGroupe(plusCourtChemin);
      noeudsFinaux.add(arrivee);
      arrivee.addGroupe(plusCourtChemin);
      plusCourtChemin.setListeArcs(arcsFinaux);
      plusCourtChemin.setListeNoeuds(noeudsFinaux);
      plusCourtChemin.setLength(arrivee.distance);
      return plusCourtChemin;
    } catch (Exception e) {
      Noeud.logger.error("----- ERREUR dans calcul de plus court chemin.");
      e.printStackTrace();
      return null;
    }
  }

  public  Noeud();
  public  Noeud(IPoint point);
  public  Noeud(IDirectPosition p);

}