/*
Copyright 2005-2013 Samuel Gesche

This file is part of ArcEnCiel.

ArcEnCiel is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

ArcEnCiel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with ArcEnCiel.  If not, see <http://www.gnu.org/licenses/>.
*/

package data;

import ihm.Charte;

import java.io.File;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;

import java.util.Set;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
import java.util.Arrays;
import java.util.Vector;
import java.util.Comparator;
/**
 * Cette classe regroupe plusieurs graphes dans l'optique d'une confrontation.
 * Elle encapsule donc également les outils pour travailler sur les différents
 * graphes.<br><br>
 * La confrontation se déroule en deux étapes : d'abord l'application détermine
 * des liens potentiels entre éléments des graphes, puis l'utilisateur travaille
 * sur ces liens. Cela lui laisse donc deux activités : <br><ul>
 * <li><i>Séparer</i> des termes que l'application aurait mis en relation ;</li>
 * <li><i>Relier</i> des termes que l'application n'a pas mis en relation.</li></ul>
 * A cela se rajoutent les concepts de mots vides et de suggestion : des
 * algorithmes de recherche de liens (alignement de graphes) peuvent être
 * déroulés afin de proposer des liens à l'utilisateur. Celui-ci peut les
 * accepter ou les refuser. Il peut également définir les mots à négliger lors
 * de la recherche.<br><br>
 * Dans cette classe, comme il s'agissait de la conception initiale, les termes
 * reliés sont appelés <i>Synonymes</i> et les termes séparés <i>Homonymes</i>
 * ou <i>Termes polysémiques</i>.<br><br>
 * <u>Note</u> : La confrontation est bâtie autour des graphes. Cela veut dire
 * qu'il n'y a aucun mouvement de graphe durant la confrontation : on ne peut
 * ni rajouter, ni supprimer un graphe sans remettre en cause tout le processus.
 * <br>
 *
 * @author Samuel GESCHE
 * @version 3.5.1
 * @since 3.0
 */
public class Confrontation {
    private Graphe[] graphes;
    private Set listeMotsVides;
    private Map listePolysemiques;
    private Map listeTLPolysemiques;
    private Map listePPolysemiques;
    private TableSynonymes tableSynonymesN;
    private TableSynonymes tableSynonymesT;
    private TableSynonymes tableSynonymesP;
    private double seuilN = 0.5;
    private double seuilT = 0.5;
    private double seuilP = 0.5;
    private Map allMotsGraphe = null;
    private Map allTermesNoeuds = null;
    private Map allTermesTypesLiens = null;
    private Map allTermesProprietes = null;
    private Map allTermesCommuns = null;
    private Map allTypesLiensCommuns = null;
    private Map allProprietesCommunes = null;
    private Vector raisonsRapprochement;
    private Vector raisonsEloignement;


    /**
     * Le texte présenté lors d'une justification de reliage pour une raison
     * d'identité.
     */
    public final static String RAISON_IDENTITE = Charte.getMessage("Conf_Identite");
    /**
     * Le texte présenté lors d'une justification de reliage ou de séparation
     * pour une raison à préciser.
     */
    public final static String RAISON_A_PRECISER = Charte.getMessage("Conf_APreciser");

    /**
     * Construit une instance de la classe à partir des Graphes donnés en
     * paramètres.
     * @param graphes Graphe[] les Graphes à confronter.
     * @since 3.0
     */
    public Confrontation(Graphe[] graphes) {
        this.graphes = graphes;
        this.listeMotsVides = new HashSet();
        this.listePolysemiques = new HashMap();
        this.listeTLPolysemiques = new HashMap();
        this.listePPolysemiques = new HashMap();
        this.tableSynonymesN = new TableSynonymes();
        this.tableSynonymesT = new TableSynonymes();
        this.tableSynonymesP = new TableSynonymes();
    }

    /**
     * Enregistre la Confrontation dans le fichier donné en paramètre.
     * @param f File la cible de la sauvegarde
     * @throws IOException en cas d'échec de la sauvegarde
     * @since 3.3.5
     */
    public void save(File f) throws IOException {
        BufferedWriter writer = null;
        try {
            writer = new BufferedWriter(new FileWriter(f, false));
        } catch (IOException ioe) {
            throw new IOException(Charte.getMessage("Error_NotOpenSave"));
        }
        try {
            writer.write("$$ Graphes");
            writer.newLine();
            for (int i = 0; i < graphes.length; i++) {
                writer.write(graphes[i].getNom());
                writer.newLine();
            }
            writer.write("$$ Fin Graphes");
            writer.newLine();
            writer.flush();
        } catch (IOException ioe) {
            throw new IOException(Charte.getMessage("Error_NotWrittenVP"));
        }
        try {
            writer.write("$$ Mots Vides");
            writer.newLine();
            TexteCommun[] t = new TexteCommun[listeMotsVides.size()];
            listeMotsVides.toArray(t);
            for (int i = 0; i < t.length; i++) {
                writer.write(t[i].getTexte());
                writer.newLine();
            }
            writer.write("$$ Fin Mots Vides");
            writer.newLine();
            writer.flush();
        } catch (IOException ioe) {
            throw new IOException(Charte.getMessage("Error_NotWrittenMV"));
        }
        try {
            writer.write("$$ Noeuds Homonymes");
            writer.newLine();
            MotHomonyme[] m = new MotHomonyme[
                              listePolysemiques.values().size()];
            listePolysemiques.values().toArray(m);
            for (int i = 0; i < m.length; i++) {
                writer.write(m[i].getSauvegarde());
                writer.newLine();
            }
            writer.write("$$ Fin Noeuds Homonymes");
            writer.newLine();
            writer.flush();
        } catch (IOException ioe) {
            throw new IOException(Charte.getMessage("Error_NotWrittenTeH"));
        }
        try {
            writer.write("$$ Types de Liens Homonymes");
            writer.newLine();
            MotHomonyme[] m = new MotHomonyme[
                              listeTLPolysemiques.values().size()];
            listeTLPolysemiques.values().toArray(m);
            for (int i = 0; i < m.length; i++) {
                writer.write(m[i].getSauvegarde());
                writer.newLine();
            }
            writer.write("$$ Fin Types de Liens Homonymes");
            writer.newLine();
            writer.flush();
        } catch (IOException ioe) {
            throw new IOException(Charte.getMessage("Error_NotWrittenRTH"));
        }
        try {
            writer.write("$$ Propriétés Homonymes");
            writer.newLine();
            MotHomonyme[] m = new MotHomonyme[
                              listePPolysemiques.values().size()];
            listePPolysemiques.values().toArray(m);
            for (int i = 0; i < m.length; i++) {
                writer.write(m[i].getSauvegarde());
                writer.newLine();
            }
            writer.write("$$ Fin Propriétés Homonymes");
            writer.newLine();
            writer.flush();
        } catch (IOException ioe) {
            throw new IOException(Charte.getMessage("Error_NotWrittenRPH"));
        }
        try {
            writer.write("$$ Noeuds Synonymes");
            writer.newLine();
            ListeSynonymes[] l = tableSynonymesN.getListes();
            for (int i = 0; i < l.length; i++) {
                writer.write(l[i].getSauvegarde());
                writer.newLine();
            }
            writer.write("$$ Fin Noeuds Synonymes");
            writer.newLine();
            writer.flush();
        } catch (IOException ioe) {
            throw new IOException(Charte.getMessage("Error_NotWrittenTeS"));
        }
        try {
            writer.write("$$ Types de Liens Synonymes");
            writer.newLine();
            ListeSynonymes[] l = tableSynonymesT.getListes();
            for (int i = 0; i < l.length; i++) {
                writer.write(l[i].getSauvegarde());
                writer.newLine();
            }
            writer.write("$$ Fin Types de Liens Synonymes");
            writer.newLine();
            writer.flush();
        } catch (IOException ioe) {
            throw new IOException(Charte.getMessage("Error_NotWrittenRTS"));
        }
        try {
            writer.write("$$ Propriétés Synonymes");
            writer.newLine();
            ListeSynonymes[] l = tableSynonymesP.getListes();
            for (int i = 0; i < l.length; i++) {
                writer.write(l[i].getSauvegarde());
                writer.newLine();
            }
            writer.write("$$ Fin Propriétés Synonymes");
            writer.newLine();
            writer.flush();
        } catch (IOException ioe) {
            throw new IOException(Charte.getMessage("Error_NotWrittenRPS"));
        }
    }

    /**
     * Charge une Confrontation qui a été enregistrée dans le fichier donné en
     * paramètre.
     * @param f File la source du chargement
     * @return Confrontation un objet Confrontation rempli avec le contenu du
     * fichier
     * @throws IOException en cas d'échec du chargement
     * @since 3.0.4
     */
    public static Confrontation load(File f) throws IOException {
        Confrontation res;
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader(f));
        } catch (IOException ioe) {
            throw new IOException(Charte.getMessage("Error_NotOpenSave"));
        }
        String s = "";
        Vector gr = new Vector();
        while (!(s.equals("$$ Graphes") || !(reader.ready()))) {
            s = reader.readLine();
        }
        if (!(reader.ready())) {
            throw new IOException(Charte.getMessage("Error_EmptySave"));
        }
        try {
            while (!(s.equals("$$ Fin Graphes"))) {
                s = reader.readLine().trim();
                if (!(s.equals("$$ Fin Graphes"))) {
                    Graphe g = new Graphe("");
                    if (s.endsWith("bch")) {
                        g = Chargeur.chargeBCH(new File("dat/pdv/" + s));
                    } else if (s.endsWith("leu")) {
                        g = Chargeur.chargeLEU(new File("dat/pdv/" + s));
                    } else if (s.endsWith("xml")) {
                        g = Chargeur.chargeLEUEN(new File("dat/pdv/" + s));
                    } else if (s.endsWith("two")) {
                        g = Chargeur.chargeTWO(new File("dat/pdv/" + s));
                    } else if (s.endsWith("xtm")) {
                        g = Chargeur.chargeXTM(new File("dat/pdv/" + s));
                    } else if (s.endsWith("jou")) {
                        g = Chargeur.chargeJOU(new File("dat/pdv/" + s));
                    } else if (s.endsWith("mdn")) {
                        g = Chargeur.chargeMDN(new File("dat/pdv/" + s));
                    } else {
                        throw new IOException(Charte.getMessage("Error_Format"));
                    }
                    gr.addElement(g);
                }
            }
            Graphe[] gra = new Graphe[gr.size()];
            gr.toArray(gra);
            res = new Confrontation(gra);
        } catch (ImportException ie) {
            throw new IOException(Charte.getMessage("Error_NotReadVP"));
        }
        try {
            Set mv = new HashSet();
            while (!(s.equals("$$ Mots Vides"))) {
                s = reader.readLine();
            } while (!(s.equals("$$ Fin Mots Vides"))) {
                s = reader.readLine().trim();
                if (!(s.equals("$$ Fin Mots Vides"))) {
                    TexteCommun t = res.trouveMot(s);
                    mv.add(t);
                }
            }
            res.listeMotsVides = mv;
        } catch (Exception ie) {
            throw new IOException(Charte.getMessage("Error_NotReadMV"));
        }
        try {
            res.getRaisonsEloigner();
            while (!(s.equals("$$ Noeuds Homonymes"))) {
                s = reader.readLine();
            } while (!(s.equals("$$ Fin Noeuds Homonymes"))) {
                s = reader.readLine().trim();
                if (!(s.equals("$$ Fin Noeuds Homonymes"))) {
                    MotHomonyme m = new MotHomonyme(s);
                    res.addMotPolysemique(m.getMots(), m.getLien(),
                                          m.getCommentaire());
                }
            }
        } catch (Exception ie) {
            throw new IOException(Charte.getMessage("Error_NotReadTeH"));
        }
        try {
            while (!(s.equals("$$ Types de Liens Homonymes"))) {
                s = reader.readLine();
            } while (!(s.equals("$$ Fin Types de Liens Homonymes"))) {
                s = reader.readLine().trim();
                if (!(s.equals("$$ Fin Types de Liens Homonymes"))) {
                    MotHomonyme m = new MotHomonyme(s);
                    res.addTypeLienPolysemique(m.getMots(), m.getLien(),
                                               m.getCommentaire());
                }
            }
        } catch (Exception ie) {
            throw new IOException(Charte.getMessage("Error_NotReadRTH"));
        }
        try {
            while (!(s.equals("$$ Propriétés Homonymes"))) {
                s = reader.readLine();
            } while (!(s.equals("$$ Fin Propriétés Homonymes"))) {
                s = reader.readLine().trim();
                if (!(s.equals("$$ Fin Propriétés Homonymes"))) {
                    MotHomonyme m = new MotHomonyme(s);
                    res.addProprietePolysemique(m.getMots(), m.getLien(),
                                                m.getCommentaire());
                }
            }
        } catch (Exception ie) {
            throw new IOException(Charte.getMessage("Error_NotReadRPH"));
        }
        res.getRaisonsRapprocher();
        res.getAllTermesNoeuds();
        try {
            while (!(s.equals("$$ Noeuds Synonymes"))) {
                s = reader.readLine();
            } while (!(s.equals("$$ Fin Noeuds Synonymes"))) {
                s = reader.readLine().trim();
                if (!(s.equals("$$ Fin Noeuds Synonymes"))) {
                    ListeSynonymes ll = new ListeSynonymes(s);
                    String sy = "";
                    for (int i = 0; i < ll.getListe().length; i++) {
                        sy += ll.getListe()[i].getTexte();
                        if (i < ll.getListe().length - 1) {
                            sy += ";";
                        }
                    }
                    res.addSynonymesNoeuds(sy, ll.getLien(),
                                           ll.getCommentaire());
                }
            }
        } catch (Exception ie) {
            throw new IOException(Charte.getMessage("Error_NotReadTeS"));
        }
        res.getAllTermesTypesLiens();
        try {
            while (!(s.equals("$$ Types de Liens Synonymes"))) {
                s = reader.readLine();
            } while (!(s.equals("$$ Fin Types de Liens Synonymes"))) {
                s = reader.readLine().trim();
                if (!(s.equals("$$ Fin Types de Liens Synonymes"))) {
                    ListeSynonymes ll = new ListeSynonymes(s);
                    String sy = "";
                    for (int i = 0; i < ll.getListe().length; i++) {
                        sy += ll.getListe()[i].getTexte();
                        if (i < ll.getListe().length - 1) {
                            sy += ";";
                        }
                    }
                    res.addSynonymesTypesLiens(sy, ll.getLien(),
                                               ll.getCommentaire());
                }
            }
        } catch (Exception ie) {
            throw new IOException(Charte.getMessage("Error_NotReadRTS"));
        }
        res.getAllTermesProprietes();
        try {
            while (!(s.equals("$$ Propriétés Synonymes"))) {
                s = reader.readLine();
            } while (!(s.equals("$$ Fin Propriétés Synonymes"))) {
                s = reader.readLine().trim();
                if (!(s.equals("$$ Fin Propriétés Synonymes"))) {
                    ListeSynonymes ll = new ListeSynonymes(s);
                    String sy = "";
                    for (int i = 0; i < ll.getListe().length; i++) {
                        sy += ll.getListe()[i].getTexte();
                        if (i < ll.getListe().length - 1) {
                            sy += ";";
                        }
                    }
                    res.addSynonymesProprietes(sy, ll.getLien(),
                                               ll.getCommentaire());
                }
            }
        } catch (Exception ie) {
            throw new IOException(Charte.getMessage("Error_NotReadRPS"));
        }
        return res;
    }

    /**
     * Renvoie le nombre de graphes pris en compte dans le cadre de la
     * confrontation.
     * @return int le nombre de graphes
     * @since 3.0.0
     */
    public int getNombreDeGraphes() {
        return graphes.length;
    }

    /**
     * Renvoie le graphe situé à l'index donné dans la liste des graphes.
     * @param i int l'index du graphe à récupérer
     * @return Graphe le graphe à l'index i
     * @since 3.0.0
     */
    public Graphe getGrapheAt(int i) {
        return graphes[i];
    }

    /**
     * Renvoie l'ensemble des noms des graphes (dans l'ordre des graphes dans
     * la confrontation).
     * @return String[] les noms des graphes
     * @since 3.0.1
     */
    public String[] getAllNomsGraphes() {
        String[] res = new String[graphes.length];
        for (int i = 0; i < res.length; i++) {
            res[i] = graphes[i].getNom();
        }
        return res;
    }

    /**
     * Définit le seuil du confronteur. Les liens suggérés par la méthode
     * suggereNoeudsSynonymes() se voient attribuer un pourcentage. Le seuil
     * détermine à partir de quel pourcentage le résultat sera renvoyé.
     * @param seuil double le seuil (entre 0 et 1) au-dessus duquel un résultat
     * est jugé utile à rapporter
     * @since 3.0.2
     */
    public void setSeuilNoeuds(double seuil) {
        if (seuil < 0) {
            seuil = 0;
        }
        if (seuil > 1) {
            seuil = 1;
        }
        this.seuilN = seuil;
    }

    /**
     * Définit le seuil du confronteur. Les liens suggérés par la méthode
     * suggereTypesLiensSynonymes() se voient attribuer un pourcentage. Le seuil
     * détermine à partir de quel pourcentage le résultat sera renvoyé.
     * @param seuil double le seuil (entre 0 et 1) au-dessus duquel un résultat
     * est jugé utile à rapporter
     * @since 3.0.2
     */
    public void setSeuilTypesLiens(double seuil) {
        if (seuil < 0) {
            seuil = 0;
        }

        if (seuil > 1) {
            seuil = 1;
        }
        this.seuilT = seuil;
    }

    /**
     * Définit le seuil du confronteur. Les liens suggérés par la méthode
     * suggereProprietesSynonymes() se voient attribuer un pourcentage. Le seuil
     * détermine à partir de quel pourcentage le résultat sera renvoyé.
     * @param seuil double le seuil (entre 0 et 1) au-dessus duquel un résultat
     * est jugé utile à rapporter
     * @since 3.0.2
     */
    public void setSeuilProprietes(double seuil) {
        if (seuil < 0) {
            seuil = 0;
        }

        if (seuil > 1) {
            seuil = 1;
        }
        this.seuilP = seuil;
    }

    /**
     * Renvoie l'ensemble des mots utilisés dans les termes des graphes (noeuds,
     * types de relations et propriétés).
     * @param cmp Comparator le comparateur choisi pour le tri
     * @return TexteCommun[] l'ensemble des mots utilisés dans les termes des
     * graphes
     * @throw IllegalArgumentException si le comparateur n'est pas une instance
     * de ComparateurMotsVides ou de ComparateurTexteCommun
     * @since 3.0.3
     */
    public TexteCommun[] getAllMotsGraphes(Comparator cmp) {
        if (!(cmp instanceof ComparateurMotsVides ||
              cmp instanceof ComparateurTexteCommun)) {
            throw new IllegalArgumentException(Charte.getMessage("Error_WrongComparator"));
        }
        if (allMotsGraphe == null) {
            allMotsGraphe = new HashMap();
            for (int i = 0; i < graphes.length; i++) {
                Noeud[] noeuds = graphes[i].getAllNoeuds();
                for (int j = 0; j < noeuds.length; j++) {
                    String[] l = formatage(noeuds[j].getLabel()).split(" ");
                    for (int k = 0; k < l.length; k++) {
                        if (l[k].length() > 0) {
                            String mot = l[k].trim();
                            TexteCommun tc = (TexteCommun)
                                             (allMotsGraphe.get(mot));
                            if (tc == null) {
                                TexteCommun add = new TexteCommun(mot,
                                        graphes.length);
                                add.addConcerne(i, true);
                                allMotsGraphe.put(mot, add);
                            } else {
                                tc.addConcerne(i, true);
                            }
                        }
                    }
                }
                TypeLien[] typesLiens = graphes[i].getAllTypesLiens();
                for (int j = 0; j < typesLiens.length; j++) {
                    String[] l = formatage(typesLiens[j].getNom()).split(" ");
                    for (int k = 0; k < l.length; k++) {
                        if (l[k].length() > 0) {
                            String mot = l[k].trim();
                            TexteCommun tc = (TexteCommun)
                                             (allMotsGraphe.get(mot));
                            if (tc == null) {
                                TexteCommun add = new TexteCommun(mot,
                                        graphes.length);
                                add.addConcerne(i, true);
                                allMotsGraphe.put(mot, add);
                            } else {
                                tc.addConcerne(i, true);
                            }
                        }
                    }
                }
                Propriete[] proprietes = graphes[i].getAllProprietes();
                for (int j = 0; j < proprietes.length; j++) {
                    String[] l = formatage(proprietes[j].getNom()).split(" ");
                    for (int k = 0; k < l.length; k++) {
                        if (l[k].length() > 0) {
                            String mot = l[k].trim();
                            TexteCommun tc = (TexteCommun)
                                             (allMotsGraphe.get(mot));
                            if (tc == null) {
                                TexteCommun add = new TexteCommun(mot,
                                        graphes.length);
                                add.addConcerne(i, true);
                                allMotsGraphe.put(mot, add);
                            } else {
                                tc.addConcerne(i, true);
                            }
                        }
                    }
                }
            }
        }
        TexteCommun[] termes = new TexteCommun[allMotsGraphe.values().size()];
        allMotsGraphe.values().toArray(termes);
        Arrays.sort(termes, cmp);
        return termes;
    }

    /**
     * Renvoie le mot donné sous forme d'un TexteCommun.
     * @param mot String le mot à récupérer
     * @return TexteCommun le mot sous forme de TexteCommun
     * @since 3.0.4
     */
    public TexteCommun trouveMot(String mot) {
        getAllMotsGraphes(new ComparateurMotsVides());
        return (TexteCommun) (allMotsGraphe.get(mot));
    }

    /**
     * Ajoute le mot donné en paramètre à la liste des mots vides.
     * @param mot le mot à rajouter
     * @since 3.0.0
     */
    public void addMotVide(String mot) {
        getAllMotsGraphes(new ComparateurMotsVides());
        listeMotsVides.add((TexteCommun) (allMotsGraphe.get(mot)));
    }


    /**
     * Supprime de la liste des mots vides celui donné en paramètre.
     * @param mot le mot à supprimer
     * @since 3.0.0
     */
    public void removeMotVide(String mot) {
        getAllMotsGraphes(new ComparateurMotsVides());
        listeMotsVides.remove((TexteCommun) (allMotsGraphe.get(mot)));
    }

    /**
     * Renvoie la liste des mots considérés comme vides lors de
     * confrontations avec ce confronteur.
     * @param cmp le comparateur pour le tri
     * @return TexteCommun[] la liste des mots
     * @throw IllegalArgumentException si le comparateur n'est pas une instance
     * de ComparateurMotsVides ou de ComparateurTexteCommun
     * @since 3.0.2
     */
    public TexteCommun[] getListeMotsVides(Comparator cmp) {
        if (!(cmp instanceof ComparateurMotsVides || cmp instanceof
              ComparateurTexteCommun)) {
            throw new IllegalArgumentException(Charte.getMessage("Error_WrongComparator"));
        }
        TexteCommun[] res = new TexteCommun[listeMotsVides.size()];
        listeMotsVides.toArray(res);
        Arrays.sort(res, cmp);
        return res;
    }

    /**
     * Renvoie la liste des mots qui ne sont pas considérés comme vides lors de
     * confrontations avec ce confronteur.
     * @param cmp le comparateur pour le tri
     * @return TexteCommun[] la liste des mots
     * @throw IllegalArgumentException si le comparateur n'est pas une instance
     * de ComparateurMotsVides ou de ComparateurTexteCommun
     * @since 3.0.2
     */
    public TexteCommun[] getListeMotsNonVides(Comparator cmp) {
        if (!(cmp instanceof ComparateurMotsVides || cmp instanceof
              ComparateurTexteCommun)) {
            throw new IllegalArgumentException(Charte.getMessage("Error_WrongComparator"));
        }
        Vector v = new Vector();
        TexteCommun[] ss = getAllMotsGraphes(cmp);
        Vector motsVides = new Vector(listeMotsVides);
        for (int i = 0; i < ss.length; i++) {
            boolean present = false;
            for (int j = 0; j < motsVides.size(); j++) {
                if (motsVides.elementAt(j).equals(ss[i])) {
                    present = true;
                    break;
                }
            }
            if (!present) {
                v.addElement(ss[i]);
            }
        }
        TexteCommun[] res = new TexteCommun[v.size()];
        v.toArray(res);
        Arrays.sort(res, cmp);
        return res;
    }

    /**
     * Renvoie l'ensemble des termes partagés par au moins deux graphes.
     * @param cmp le comparateur pour le tri
     * @return TexteCommun[] l'ensemble des termes partagés par au moins deux
     * graphes
     * @throw IllegalArgumentException si le comparateur n'est pas une instance
     * de ComparateurMotsVides ou de ComparateurTexteCommun
     * @since 3.0.2
     */
    public TexteCommun[] getAllTermesCommuns(Comparator cmp) {
        if (!(cmp instanceof ComparateurMotsVides || cmp instanceof
              ComparateurTexteCommun)) {
            throw new IllegalArgumentException(Charte.getMessage("Error_WrongComparator"));
        }
        if (allTermesCommuns == null) {
            Map liste = new HashMap();
            allTermesCommuns = new HashMap();
            for (int i = 0; i < graphes.length; i++) {
                Noeud[] noeuds = graphes[i].getAllNoeuds();
                for (int j = 0; j < noeuds.length; j++) {
                    String terme = noeuds[j].getLabel();
                    TexteCommun tc = (TexteCommun) (liste.get(terme));
                    if (tc == null) {
                        tc = new TexteCommun(terme, graphes.length);
                        tc.addConcerne(i, true);
                        liste.put(terme, tc);
                    } else {
                        if (!(tc.getConcernes()[i])) {
                            tc.addConcerne(i, true);
                            allTermesCommuns.put(terme, tc);
                        }
                    }
                }
            }
        }
        TexteCommun[] termes = new TexteCommun[allTermesCommuns.values().size()];
        allTermesCommuns.values().toArray(termes);
        Arrays.sort(termes, cmp);
        return termes;
    }

    /**
     * Renvoie le terme séparé donné sous forme d'un MotHomonyme.
     * @param mot String le terme séparé à récupérer
     * @return MotHomonyme le terme séparé sous forme de MotHomonyme
     * @since 3.0.4
     */
    public MotHomonyme trouveMotPolysemique(String mot) {
        return (MotHomonyme) (listePolysemiques.get(mot));
    }

    /**
     * Rajoute à la liste des mots polysémiques la distribution de termes
     * donnée en paramètres, pour la raison donnée en paramètre et avec les
     * commentaires donnés en paramètres.
     * @param repartition TexteCommun[] les termes à séparer
     * @param raison String pourquoi il faut les séparer
     * @param commentaires String une explication plus conséquente de la raison
     * @since 3.0.4
     */
    public void addMotPolysemique(TexteCommun[] repartition, String raison,
                                  String commentaires) {
        if (repartition.length > 1) {
            ajouteRaisonEloignement(raison);
            String id = repartition[0].getTexte();
            for (int i = 0; i < repartition.length; i++) {
                for (int j = 0; j < graphes.length; j++) {
                    if (repartition[i].getConcernes()[j] == true) {
                        graphes[j].desambigueHomonyme(repartition[i].getTexte(),
                                i + 1);
                    }
                }
                repartition[i] = new TexteCommun(repartition[i].getTexte() +
                                                 " - " + (i + 1),
                                                 repartition[i].getConcernes());
            }
            allTermesNoeuds = null;
            allTermesCommuns = null;
            listePolysemiques.put(id, new MotHomonyme(repartition, raison,
                    commentaires));
        }
    }

    /**
     * Supprime de la liste des mots polysémiques le MotHomonyme correspondant
     * à la chaîne donnée en paramètre.
     * @param mot le terme à supprimer
     * @since 3.0.1
     */
    public void removeMotPolysemique(String mot) {
        MotHomonyme m = (MotHomonyme) (listePolysemiques.get(mot));
        TexteCommun[] t = m.getMots();
        TexteCommun n = new TexteCommun(t[0].getTexte(), graphes.length);
        for (int i = 0; i < t.length; i++) {
            for (int j = 0; j < graphes.length; j++) {
                if (t[i].getConcernes()[j] == true) {
                    n.addConcerne(j, true);
                    graphes[j].removeDesambiguation(t[i].getTexte());
                }
            }
        }
        for (int i = 0; i < t.length; i++) {
            fusionneSynonymieNoeuds(t[i].getTexte(), n);
        }
        allTermesNoeuds = null;
        allTermesCommuns = null;
        listePolysemiques.remove(mot);
    }

    /**
     * Renvoie la liste des mots considérés comme polysémiques lors de
     * confrontations avec ce confronteur.
     * @param cmp le comparateur pour le tri
     * @return MotHomonyme[] la liste en question
     * @throw IllegalArgumentException si le comparateur n'est pas une instance
     * de ComparateurMotsVides ou de ComparateurTexteCommun
     * @since 3.0.4
     */
    public MotHomonyme[] getListeMotsPolysemiques(Comparator cmp) {
        if (!(cmp instanceof ComparateurMotsVides || cmp instanceof
              ComparateurHomonymes)) {
            throw new IllegalArgumentException(Charte.getMessage("Error_WrongComparator"));
        }
        MotHomonyme[] res = new MotHomonyme[listePolysemiques.values().size()];
        listePolysemiques.values().toArray(res);
        Arrays.sort(res, cmp);
        return res;
    }

    /**
     * Renvoie la liste des mots considérés comme non polysémiques lors de
     * confrontations avec ce confronteur.
     * @param cmp le comparateur pour le tri
     * @return TexteCommun[] la liste en question
     * @throw IllegalArgumentException si le comparateur n'est pas une instance
     * de ComparateurMotsVides ou de ComparateurTexteCommun
     * @since 3.0.2
     */
    public TexteCommun[] getListeMotsNonPolysemiques(Comparator cmp) {
        if (!(cmp instanceof ComparateurMotsVides || cmp instanceof
              ComparateurTexteCommun)) {
            throw new IllegalArgumentException(Charte.getMessage("Error_WrongComparator"));
        }
        Vector v = new Vector();
        TexteCommun[] ss = getAllTermesCommuns(cmp);
        for (int i = 0; i < ss.length; i++) {
            v.addElement(ss[i]);
        }
        TexteCommun[] res = new TexteCommun[v.size()];
        v.toArray(res);
        Arrays.sort(res, cmp);
        return res;
    }

    /**
     * Renvoie l'ensemble des types de liens partagés par au moins deux graphes.
     * @param cmp le comparateur pour le tri
     * @return TexteCommun[] la liste en question
     * @throw IllegalArgumentException si le comparateur n'est pas une instance
     * de ComparateurMotsVides ou de ComparateurTexteCommun
     * @since 3.0.2
     */
    public TexteCommun[] getAllTypesLiensCommuns(Comparator cmp) {
        if (!(cmp instanceof ComparateurMotsVides || cmp instanceof
              ComparateurTexteCommun)) {
            throw new IllegalArgumentException(Charte.getMessage("Error_WrongComparator"));
        }
        if (allTypesLiensCommuns == null) {
            Map liste = new HashMap();
            allTypesLiensCommuns = new HashMap();
            for (int i = 0; i < graphes.length; i++) {
                TypeLien[] types = graphes[i].getAllTypesLiens();
                for (int j = 0; j < types.length; j++) {
                    String terme = types[j].getNom();
                    TexteCommun tc = (TexteCommun) (liste.get(terme));
                    if (tc == null) {
                        tc = new TexteCommun(terme, graphes.length);
                        tc.addConcerne(i, true);
                        liste.put(terme, tc);
                    } else {
                        if (!(tc.getConcernes()[i])) {
                            tc.addConcerne(i, true);
                            allTypesLiensCommuns.put(terme, tc);
                        }
                    }
                }
            }
        }
        TexteCommun[] termes = new TexteCommun[
                               allTypesLiensCommuns.values().size()];
        allTypesLiensCommuns.values().toArray(termes);
        Arrays.sort(termes, cmp);
        return termes;
    }

    /**
     * Renvoie le type de lien séparé donné sous forme d'un MotHomonyme.
     * @param mot String le type de lien séparé à récupérer
     * @return MotHomonyme le type de lien séparé sous forme de MotHomonyme
     * @since 3.0.4
     */
    public MotHomonyme trouveTypeLienPolysemique(String mot) {
        return (MotHomonyme) (listeTLPolysemiques.get(mot));
    }

    /**
     * Rajoute à la liste des mots polysémiques la distribution de types de
     * liens donnée en paramètres, pour la raison donnée en paramètre et avec
     * les commentaires donnés en paramètres.
     * @param repartition TexteCommun[] les types de liens à séparer
     * @param raison String pourquoi il faut les séparer
     * @param commentaires String une explication plus conséquente de la raison
     * @since 3.0.4
     */
    public void addTypeLienPolysemique(TexteCommun[] repartition, String raison,
                                       String commentaires) {
        if (repartition.length > 1) {
            String id = repartition[0].getTexte();
            ajouteRaisonEloignement(raison);
            for (int i = 0; i < repartition.length; i++) {
                for (int j = 0; j < graphes.length; j++) {
                    if (repartition[i].getConcernes()[j] == true) {
                        graphes[j].desambigueHomonymeTL(
                                repartition[i].getTexte(), i + 1);
                    }
                }
                repartition[i] = new TexteCommun(repartition[i].getTexte() +
                                                 " - " + (i + 1),
                                                 repartition[i].getConcernes());
            }
            allTermesTypesLiens = null;
            allTypesLiensCommuns = null;
            listeTLPolysemiques.put(id, new MotHomonyme(repartition, raison,
                    commentaires));
        }
    }

    /**
     * Supprime de la liste des types de liens polysémiques le MotHomonyme
     * correspondant à la chaîne donnée en paramètre.
     * @param mot le terme à supprimer
     * @since 3.0.1
     */
    public void removeTypeLienPolysemique(String mot) {
        MotHomonyme m = (MotHomonyme) (listeTLPolysemiques.get(mot));
        TexteCommun[] t = m.getMots();
        TexteCommun n = new TexteCommun(t[0].getTexte(), graphes.length);
        for (int i = 0; i < t.length; i++) {
            for (int j = 0; j < graphes.length; j++) {
                if (t[i].getConcernes()[j] == true) {
                    n.addConcerne(j, true);
                    graphes[j].removeDesambiguationTL(t[i].getTexte());
                }
            }
        }
        for (int i = 0; i < t.length; i++) {
            fusionneSynonymieTypesLiens(t[i].getTexte(), n);
        }
        allTermesTypesLiens = null;
        allTypesLiensCommuns = null;
        listeTLPolysemiques.remove(mot);
    }

    /**
     * Renvoie la liste des types de liens considérés comme polysémiques lors de
     * confrontations avec ce confronteur.
     * @param cmp le comparateur pour le tri
     * @return MotHomonyme[] la liste en question
     * @throw IllegalArgumentException si le comparateur n'est pas une instance
     * de ComparateurMotsVides ou de ComparateurTexteCommun
     * @since 3.0.4
     */
    public MotHomonyme[] getListeTypesLiensPolysemiques(Comparator cmp) {
        if (!(cmp instanceof ComparateurMotsVides || cmp instanceof
              ComparateurHomonymes)) {
            throw new IllegalArgumentException(Charte.getMessage("Error_WrongComparator"));
        }
        MotHomonyme[] res = new MotHomonyme[listeTLPolysemiques.values().size()];
        listeTLPolysemiques.values().toArray(res);
        Arrays.sort(res, cmp);
        return res;
    }

    /**
     * Renvoie la liste des types de liens considérés comme non polysémiques
     * lors de confrontations avec ce confronteur.
     * @param cmp le comparateur pour le tri
     * @return TexteCommun[] la liste en question
     * @throw IllegalArgumentException si le comparateur n'est pas une instance
     * de ComparateurMotsVides ou de ComparateurTexteCommun
     * @since 3.0.2
     */
    public TexteCommun[] getListeTypesLiensNonPolysemiques(Comparator cmp) {
        if (!(cmp instanceof ComparateurMotsVides || cmp instanceof
              ComparateurTexteCommun)) {
            throw new IllegalArgumentException(Charte.getMessage("Error_WrongComparator"));
        }
        Vector v = new Vector();
        TexteCommun[] ss = getAllTypesLiensCommuns(cmp);
        for (int i = 0; i < ss.length; i++) {
            v.addElement(ss[i]);
        }
        TexteCommun[] res = new TexteCommun[v.size()];
        v.toArray(res);
        Arrays.sort(res, cmp);
        return res;
    }

    /**
     * Renvoie l'ensemble des propriétés de lien partagées par au moins deux
     * graphes
     * @param cmp le comparateur pour le tri
     * @return TexteCommun[] la liste en question
     * @throw IllegalArgumentException si le comparateur n'est pas une instance
     * de ComparateurMotsVides ou de ComparateurTexteCommun
     * @since 3.0.2
     */
    public TexteCommun[] getAllProprietesCommunes(Comparator cmp) {
        if (!(cmp instanceof ComparateurMotsVides || cmp instanceof
              ComparateurTexteCommun)) {
            throw new IllegalArgumentException(Charte.getMessage("Error_WrongComparator"));
        }
        if (allProprietesCommunes == null) {
            Map liste = new HashMap();
            allProprietesCommunes = new HashMap();
            for (int i = 0; i < graphes.length; i++) {
                Propriete[] types = graphes[i].getAllProprietes();
                for (int j = 0; j < types.length; j++) {
                    String terme = types[j].getNom();
                    TexteCommun tc = (TexteCommun) (liste.get(terme));
                    if (tc == null) {
                        tc = new TexteCommun(terme, graphes.length);
                        tc.addConcerne(i, true);
                        liste.put(terme, tc);
                    } else {
                        if (!(tc.getConcernes()[i])) {
                            tc.addConcerne(i, true);
                            allProprietesCommunes.put(terme, tc);
                        }
                    }
                }
            }
        }
        TexteCommun[] termes = new TexteCommun[
                               allProprietesCommunes.values().size()];
        allProprietesCommunes.values().toArray(termes);
        Arrays.sort(termes, cmp);
        return termes;
    }

    /**
     * Renvoie la propriété séparée donnée sous forme d'un MotHomonyme.
     * @param mot String la propriété séparée à récupérer
     * @return MotHomonyme la propriété séparée sous forme de MotHomonyme
     * @since 3.0.4
     */
    public MotHomonyme trouveProprietePolysemique(String mot) {
        return (MotHomonyme) (listePPolysemiques.get(mot));
    }


    /**
     * Rajoute à la liste des propriétés polysémiques la distribution de
     * propriétés donnée en paramètres, pour la raison donnée en paramètre et
     * avec les commentaires donnés en paramètres.
     * @param repartition TexteCommun[] les propriétés à séparer
     * @param raison String pourquoi il faut les séparer
     * @param commentaires String une explication plus conséquente de la raison
     * @since 3.0.4
     */
    public void addProprietePolysemique(TexteCommun[] repartition,
                                        String raison, String commentaires) {
        if (repartition.length > 1) {
            String id = repartition[0].getTexte();
            ajouteRaisonEloignement(raison);
            for (int i = 0; i < repartition.length; i++) {
                for (int j = 0; j < graphes.length; j++) {
                    if (repartition[i].getConcernes()[j] == true) {
                        graphes[j].desambigueHomonymeP(
                                repartition[i].getTexte(), i + 1);
                    }
                }
                repartition[i] = new TexteCommun(repartition[i].getTexte() +
                                                 " - " + (i + 1),
                                                 repartition[i].getConcernes());
            }
            allTermesProprietes = null;
            allProprietesCommunes = null;
            listePPolysemiques.put(id, new MotHomonyme(repartition, raison,
                    commentaires));
        }
    }

    /**
     * Supprime de la liste des propriétés polysémiques le MotHomonyme
     * correspondant à la chaîne donnée en paramètre.
     * @param mot le terme à supprimer
     * @since 3.0.1
     */
    public void removeProprietePolysemique(String mot) {
        MotHomonyme m = (MotHomonyme) (listePPolysemiques.get(mot));
        TexteCommun[] t = m.getMots();
        TexteCommun n = new TexteCommun(t[0].getTexte(), graphes.length);
        for (int i = 0; i < t.length; i++) {
            for (int j = 0; j < graphes.length; j++) {
                if (t[i].getConcernes()[j] == true) {
                    n.addConcerne(j, true);
                    graphes[j].removeDesambiguationP(t[i].getTexte());
                }
            }
        }
        for (int i = 0; i < t.length; i++) {
            fusionneSynonymieProprietes(t[i].getTexte(), n);
        }
        allTermesProprietes = null;
        allProprietesCommunes = null;
        listePPolysemiques.remove(mot);
    }

    /**
     * Renvoie la liste des propriétés de liens considérés comme polysémiques
     * lors de confrontations avec ce confronteur.
     * @param cmp le comparateur pour le tri
     * @return MotHomonyme[] la liste en question
     * @throw IllegalArgumentException si le comparateur n'est pas une instance
     * de ComparateurMotsVides ou de ComparateurTexteCommun
     * @since 3.0.4
     */
    public MotHomonyme[] getListeProprietesPolysemiques(Comparator cmp) {
        if (!(cmp instanceof ComparateurMotsVides ||
              cmp instanceof ComparateurHomonymes)) {
            throw new IllegalArgumentException(Charte.getMessage("Error_WrongComparator"));
        }
        MotHomonyme[] res = new MotHomonyme[listePPolysemiques.values().size()];
        listePPolysemiques.values().toArray(res);
        Arrays.sort(res, cmp);
        return res;
    }

    /**
     * Renvoie la liste des propriétés de liens considérés comme non
     * polysémiques lors de confrontations avec ce confronteur.
     * @param cmp le comparateur pour le tri
     * @return TexteCommun[] la liste en question
     * @throw IllegalArgumentException si le comparateur n'est pas une instance
     * de ComparateurMotsVides ou de ComparateurTexteCommun
     * @since 3.0.2
     */
    public TexteCommun[] getListeProprietesNonPolysemiques(Comparator cmp) {
        if (!(cmp instanceof ComparateurMotsVides ||
              cmp instanceof ComparateurTexteCommun)) {
            throw new IllegalArgumentException(Charte.getMessage("Error_WrongComparator"));
        }
        Vector v = new Vector();
        TexteCommun[] ss = getAllProprietesCommunes(cmp);
        for (int i = 0; i < ss.length; i++) {
            v.addElement(ss[i]);
        }
        TexteCommun[] res = new TexteCommun[v.size()];
        v.toArray(res);
        Arrays.sort(res, cmp);
        return res;
    }

    /**
     * Renvoie l'ensemble des termes utilisés dans les noeuds des graphes.
     * @return TexteCommun[] la liste en question
     * @since 3.0.2
     */
    public TexteCommun[] getAllTermesNoeuds() {
        if (allTermesNoeuds == null) {
            allTermesNoeuds = new HashMap();
            for (int i = 0; i < graphes.length; i++) {
                Noeud[] noeuds = graphes[i].getAllNoeuds();
                for (int j = 0; j < noeuds.length; j++) {
                    String terme = noeuds[j].getLabel();
                    TexteCommun tc = (TexteCommun) (allTermesNoeuds.get(terme));
                    if (tc == null) {
                        TexteCommun add = new TexteCommun(terme,
                                graphes.length);
                        add.addConcerne(i, true);
                        allTermesNoeuds.put(terme, add);
                    } else {
                        tc.addConcerne(i, true);
                    }
                }
            }
        }
        TexteCommun[] termes = new TexteCommun[allTermesNoeuds.values().size()];
        allTermesNoeuds.values().toArray(termes);
        Arrays.sort(termes, new ComparateurTexteCommun());
        return termes;
    }

    /**
     * Renvoie le terme donné sous forme d'un TexteCommun.
     * @param mot String le terme à récupérer
     * @return TexteCommun le terme sous forme de TexteCommun
     * @since 3.0.4
     */
    public TexteCommun trouveTermeNoeud(String mot) {
        return (TexteCommun) (allTermesNoeuds.get(mot));
    }

    /**
     * Rajoute à la liste des noeuds liés ceux qui sont donnés dans le
     * premier paramètre.
     * @param synos String une liste de termes séparés par des points virgules
     * @param raison String le lien entre eux
     * @param commentaires String plus de détails sur ce lien
     * @since 3.0.3
     */
    public void addSynonymesNoeuds(String synos, String raison,
                                   String commentaires) {
        ajouteRaisonRapprochement(raison);
        ListeSynonymes liste = new ListeSynonymes(raison, commentaires);
        String[] s = synos.split(";");
        for (int i = 0; i < s.length; i++) {
            TexteCommun tc = (TexteCommun) (allTermesNoeuds.get(s[i]));
            liste.add(tc);
        }
        tableSynonymesN.add(liste);
    }

    /**
     * Supprime de la liste des noeuds liés ceux qui sont donnés en
     * paramètre.
     * @param synos String une liste de termes séparés par des points virgules
     * @since 3.0.2
     */
    public void removeSynonymesNoeuds(String synos) {
        ListeSynonymes liste = new ListeSynonymes("", "");
        String[] s = synos.split(";");
        for (int i = 0; i < s.length; i++) {
            TexteCommun tc = (TexteCommun) (allTermesNoeuds.get(s[i]));
            liste.add(tc);
        }
        tableSynonymesN.remove(liste);
    }

    /* Fusion de termes déséparés au sein des liens tissés (utilisé lors de
    l'annulation d'une séparation). */
    private void fusionneSynonymieNoeuds(String nom, TexteCommun fusion) {
        ListeSynonymes[] listes = tableSynonymesN.getListes();
        for (int i = 0; i < listes.length; i++) {
            if (listes[i].contains(new TexteCommun(nom, graphes.length))) {
                listes[i].termeFusionne(new TexteCommun(nom, graphes.length),
                                        fusion);
                if (listes[i].getListe().length < 2) {
                    tableSynonymesN.remove(listes[i]);
                }
            }
        }
    }

    /**
     * Renvoie la liste des liens utilisés lors de confrontations
     * avec ce confronteur.
     * @return ListeSynonymes[] la liste en question
     * @since 3.0.2
     */
    public ListeSynonymes[] getListesSynonymesNoeuds() {
        return tableSynonymesN.getListes();
    }

    /**
     * Renvoie la liste des liens utilisés lors de confrontations
     * avec ce confronteur qui contiennent le TexteCommun donné en paramètre.
     * @param texte le TexteCommun en question
     * @return ListeSynonymes[] la liste en question
     * @since 3.0.4
     */
    public ListeSynonymes[] getListesSynonymesNoeuds(TexteCommun texte) {
        Vector v = new Vector();
        if (texte != null) {
            ListeSynonymes[] listes = tableSynonymesN.getListes();
            for (int i = 0; i < listes.length; i++) {
                if (listes[i].contains(texte)) {
                    v.addElement(listes[i]);
                }
            }
        }
        ListeSynonymes[] res = new ListeSynonymes[v.size()];
        v.toArray(res);
        return res;
    }

    /**
     * Renvoie la liste des liens utilisés lors de confrontations
     * avec ce confronteur qui contiennent l'un des termes séparés du
     * MotHomonyme donné en paramètre.
     * @param mot le MotHomonyme contenant les termes séparés
     * @return ListeSynonymes[] la liste en question
     * @since 3.0.4
     */
    public ListeSynonymes[] getListesSynonymesNoeuds(MotHomonyme mot) {
        TexteCommun[] t = mot.getMots();
        Set res = new HashSet();
        for (int i = 0; i < t.length; i++) {
            ListeSynonymes[] l = getListesSynonymesNoeuds(t[i]);
            for (int j = 0; j < l.length; j++) {
                res.add(l[j]);
            }
        }
        ListeSynonymes[] res2 = new ListeSynonymes[res.size()];
        res.toArray(res2);
        return res2;
    }

    /**
     * Renvoie la liste complète des noeuds liés.
     * @return ListeSynonymes[] la liste complète des noeuds liés.
     * @since 3.0.3
     */
    public ListeSynonymes[] getListeCompleteNoeudsLies() {
        Vector v = new Vector();
        ListeSynonymes[] synos = getListesSynonymesNoeuds();
        for (int i = 0; i < synos.length; i++) {
            v.add(synos[i]);
        }
        TexteCommun[] nonHomos = getListeMotsNonPolysemiques(
                getComparateurAlphabetique());
        for (int i = 0; i < nonHomos.length; i++) {
            boolean contient = false;
            for (int j = 0; j < synos.length; j++) {
                if (synos[j].contains(nonHomos[i])) {
                    contient = true;
                }
            }
            if (!contient) {
                ListeSynonymes liste = new ListeSynonymes(RAISON_IDENTITE, "");
                liste.add(nonHomos[i]);
                v.add(liste);
            }
        }
        ListeSynonymes[] l = new ListeSynonymes[v.size()];
        v.toArray(l);
        return l;
    }

    /**
     * Renvoie l'ensemble des termes utilisés dans les types de relation des
     * graphes.
     * @return TexteCommun[] la liste en question
     * @since 3.0.2
     */
    public TexteCommun[] getAllTermesTypesLiens() {
        if (allTermesTypesLiens == null) {
            allTermesTypesLiens = new HashMap();
            for (int i = 0; i < graphes.length; i++) {
                TypeLien[] noeuds = graphes[i].getAllTypesLiens();
                for (int j = 0; j < noeuds.length; j++) {
                    String terme = noeuds[j].getNom();
                    TexteCommun tc = (TexteCommun)
                                     (allTermesTypesLiens.get(terme));
                    if (tc == null) {
                        TexteCommun add = new TexteCommun(terme,
                                graphes.length);
                        add.addConcerne(i, true);
                        allTermesTypesLiens.put(terme, add);
                    } else {
                        tc.addConcerne(i, true);
                    }
                }
            }
        }
        TexteCommun[] termes = new TexteCommun[
                               allTermesTypesLiens.values().size()];
        allTermesTypesLiens.values().toArray(termes);
        Arrays.sort(termes, new ComparateurTexteCommun());
        return termes;
    }

    /**
     * Renvoie le terme donné sous forme d'un TexteCommun.
     * @param mot String le terme à récupérer
     * @return TexteCommun le terme sous forme de TexteCommun
     * @since 3.0.4
     */
    public TexteCommun trouveTermeTypeLien(String mot) {
        return (TexteCommun) (allTermesTypesLiens.get(mot));
    }

    /**
     * Rajoute à la liste des types de relation liées ceux qui sont donnés
     * dans le premier paramètre.
     * @param synos String une liste de termes séparés par des points virgules
     * @param raison String le lien entre eux
     * @param commentaires String plus de détails sur ce lien
     * @since 3.0.3
     */
    public void addSynonymesTypesLiens(String synos, String raison,
                                       String commentaires) {
        ajouteRaisonRapprochement(raison);
        ListeSynonymes liste = new ListeSynonymes(raison, commentaires);
        String[] s = synos.split(";");
        for (int i = 0; i < s.length; i++) {
            TexteCommun tc = (TexteCommun) (allTermesTypesLiens.get(s[i]));
            liste.add(tc);
        }
        tableSynonymesT.add(liste);
    }

    /**
     * Supprime de la liste des types de relation liés ceux qui sont donnés
     * en paramètre.
     * @param synos String une liste de termes séparés par des points virgules
     * @since 3.0.2
     */
    public void removeSynonymesTypesLiens(String synos) {
        ListeSynonymes liste = new ListeSynonymes("", "");
        String[] s = synos.split(";");
        for (int i = 0; i < s.length; i++) {
            TexteCommun tc = (TexteCommun) (allTermesTypesLiens.get(s[i]));
            liste.add(tc);
        }
        tableSynonymesT.remove(liste);
    }

    /**
     * Renvoie la liste des liens utilisés lors de confrontations
     * avec ce confronteur.
     * @return ListeSynonymes[] la liste en question
     * @since 3.0.2
     */
    public ListeSynonymes[] getListesSynonymesTypesLiens() {
        return tableSynonymesT.getListes();
    }

    /**
     * Renvoie la liste des liens utilisés lors de confrontations
     * avec ce confronteur qui contiennent le TexteCommun donné en paramètre.
     * @param texte le TexteCommun en question
     * @return ListeSynonymes[] la liste en question
     * @since 3.0.4
     */
    public ListeSynonymes[] getListesSynonymesTypesLiens(TexteCommun texte) {
        Vector v = new Vector();
        if (texte != null) {
            ListeSynonymes[] listes = tableSynonymesT.getListes();
            for (int i = 0; i < listes.length; i++) {
                if (listes[i].contains(texte)) {
                    v.addElement(listes[i]);
                }
            }
        }
        ListeSynonymes[] res = new ListeSynonymes[v.size()];
        v.toArray(res);
        return res;
    }

    /**
     * Renvoie la liste des liens utilisés lors de confrontations
     * avec ce confronteur qui contient l'un des termes séparés donnés en
     * paramètre.
     * @param mot le MotHomonyme contenant les termes séparés
     * @return ListeSynonymes[] la liste en question
     * @since 3.0.4
     */
    public ListeSynonymes[] getListesSynonymesTypesLiens(MotHomonyme mot) {
        TexteCommun[] t = mot.getMots();
        Set res = new HashSet();
        for (int i = 0; i < t.length; i++) {
            ListeSynonymes[] l = getListesSynonymesTypesLiens(t[i]);
            for (int j = 0; j < l.length; j++) {
                res.add(l[j]);
            }
        }
        ListeSynonymes[] res2 = new ListeSynonymes[res.size()];
        res.toArray(res2);
        return res2;
    }

    /* Fusion de termes déséparés au sein des liens tissés (utilisé lors de
    l'annulation d'une séparation). */
    private void fusionneSynonymieTypesLiens(String nom, TexteCommun fusion) {
        ListeSynonymes[] listes = tableSynonymesT.getListes();
        for (int i = 0; i < listes.length; i++) {
            if (listes[i].contains(new TexteCommun(nom, graphes.length))) {
                listes[i].termeFusionne(new TexteCommun(nom, graphes.length),
                                        fusion);
                if (listes[i].getListe().length < 2) {
                    tableSynonymesT.remove(listes[i]);
                }
            }
        }
    }

    /**
     * Renvoie l'ensemble des termes utilisés dans les propriétés de relation
     * des graphes.
     * @return TexteCommun[] la liste en question
     * @since 3.0.2
     */
    public TexteCommun[] getAllTermesProprietes() {
        if (allTermesProprietes == null) {
            allTermesProprietes = new HashMap();
            for (int i = 0; i < graphes.length; i++) {
                Propriete[] noeuds = graphes[i].getAllProprietes();
                for (int j = 0; j < noeuds.length; j++) {
                    String terme = noeuds[j].getNom();
                    TexteCommun tc = (TexteCommun)
                                     (allTermesProprietes.get(terme));
                    if (tc == null) {
                        TexteCommun add = new TexteCommun(terme,
                                graphes.length);
                        add.addConcerne(i, true);
                        allTermesProprietes.put(terme, add);
                    } else {
                        tc.addConcerne(i, true);
                    }
                }
            }
        }
        TexteCommun[] termes = new TexteCommun[
                               allTermesProprietes.values().size()];
        allTermesProprietes.values().toArray(termes);
        Arrays.sort(termes, new ComparateurTexteCommun());
        return termes;
    }

    /**
     * Renvoie le terme donné sous forme d'un TexteCommun.
     * @param mot String le terme à récupérer
     * @return TexteCommun le terme sous forme de TexteCommun
     * @since 3.0.4
     */
    public TexteCommun trouveTermePropriete(String mot) {
        return (TexteCommun) (allTermesProprietes.get(mot));
    }

    /**
     * Rajoute à la liste des propriétés liées celles qui sont donnés
     * dans le premier paramètre.
     * @param synos String une liste de termes séparés par des points virgules
     * @param raison String le lien entre eux
     * @param commentaires String plus de détails sur ce lien
     * @since 3.0.3
     */
    public void addSynonymesProprietes(String synos, String raison,
                                       String commentaires) {
        ajouteRaisonRapprochement(raison);
        ListeSynonymes liste = new ListeSynonymes(raison, commentaires);
        String[] s = synos.split(";");
        for (int i = 0; i < s.length; i++) {
            TexteCommun tc = (TexteCommun) (allTermesProprietes.get(s[i]));
            liste.add(tc);
        }
        tableSynonymesP.add(liste);
    }

    /**
     * Supprime de la liste des propriétés liées ceux qui sont donnés
     * en paramètre.
     * @param synos String une liste de termes séparés par des points virgules
     * @since 3.0.2
     */
    public void removeSynonymesProprietes(String synos) {
        ListeSynonymes liste = new ListeSynonymes("", "");
        String[] s = synos.split(";");
        for (int i = 0; i < s.length; i++) {
            TexteCommun tc = (TexteCommun) (allTermesProprietes.get(s[i]));
            liste.add(tc);
        }
        tableSynonymesP.remove(liste);
    }

    /**
     * Renvoie la liste des liens utilisés lors de confrontations
     * avec ce confronteur.
     * @return ListeSynonymes[] la liste en question
     * @since 3.0.2
     */
    public ListeSynonymes[] getListesSynonymesProprietes() {
        return tableSynonymesP.getListes();
    }

    /**
     * Renvoie la liste des liens utilisés lors de confrontations
     * avec ce confronteur qui contiennent le TexteCommun donné en paramètre.
     * @param texte le TexteCommun en question
     * @return ListeSynonymes[] la liste en question
     * @since 3.0.4
     */
    public ListeSynonymes[] getListesSynonymesProprietes(TexteCommun texte) {
        Vector v = new Vector();
        if (texte != null) {
            ListeSynonymes[] listes = tableSynonymesP.getListes();
            for (int i = 0; i < listes.length; i++) {
                if (listes[i].contains(texte)) {
                    v.addElement(listes[i]);
                }
            }
        }
        ListeSynonymes[] res = new ListeSynonymes[v.size()];
        v.toArray(res);
        return res;
    }

    /**
     * Renvoie la liste des liens utilisés lors de confrontations
     * avec ce confronteur qui contiennent l'un des termes séparés donnés en
     * paramètre.
     * @param mot le MotHomonyme contenant les termes séparés
     * @return ListeSynonymes[] la liste en question
     * @since 3.0.4
     */
    public ListeSynonymes[] getListesSynonymesProprietes(MotHomonyme mot) {
        TexteCommun[] t = mot.getMots();
        Set res = new HashSet();
        for (int i = 0; i < t.length; i++) {
            ListeSynonymes[] l = getListesSynonymesProprietes(t[i]);
            for (int j = 0; j < l.length; j++) {
                res.add(l[j]);
            }
        }
        ListeSynonymes[] res2 = new ListeSynonymes[res.size()];
        res.toArray(res2);
        return res2;
    }

    /* Fusion de termes déséparés au sein des liens tissés (utilisé lors de
    l'annulation d'une séparation). */
    private void fusionneSynonymieProprietes(String nom, TexteCommun fusion) {
        ListeSynonymes[] listes = tableSynonymesP.getListes();
        for (int i = 0; i < listes.length; i++) {
            if (listes[i].contains(new TexteCommun(nom, graphes.length))) {
                listes[i].termeFusionne(new TexteCommun(nom, graphes.length),
                                        fusion);
                if (listes[i].getListe().length < 2) {
                    tableSynonymesP.remove(listes[i]);
                }
            }
        }
    }

    /**
     * Lance l'algorithme de suggestion de liens parmi les noeuds.
     * @return ListeSynonymes[] la réponse
     * @since 3.0.2
     */
    public ListeSynonymes[] suggereNoeudsSynonymes() {
        Vector res = new Vector();
        TexteCommun[] termes = getAllTermesNoeuds();
        for (int i = 0; i < termes.length; i++) {
            for (int j = i + 1; j < termes.length; j++) {
                if (!(termes[i].hasPVCommun(termes[j]))) {
                    double fiabilite = testeConcordance(
                            termes[i], termes[j]) * testeConcordance(
                            termes[j], termes[i]);
                    if (fiabilite > seuilN) {
                        ListeSynonymes l = new ListeSynonymes(
                                Charte.getMessage("Conf_SurA") + " " +
                                (int) (fiabilite * 100) + "%", "");
                        l.add(termes[i]);
                        l.add(termes[j]);
                        res.add(l);
                    }
                }
            }
        }
        ListeSynonymes[] res3 = new ListeSynonymes[res.size()];
        res.toArray(res3);
        Arrays.sort(res3, new ComparateurSynonymes());
        return res3;
    }

    /**
     * Lance l'algorithme de suggestion de liens parmi les noeuds, qui ne
     * tournera que le nombre de millisecondes imparti.<br>
     * Les alignements seront évalués au hasard, permettant ainsi une couverture
     * complète bien que non exhaustive.
     * @param ms int le temps alloué à la recherche
     * @return ListeSynonymes[] la réponse
     * @since 3.5.1
     */
    public ListeSynonymes[] suggereNoeudsSynonymes(int ms){
        Map res = new HashMap();
        long time = System.currentTimeMillis();
        TexteCommun[] termes = getAllTermesNoeuds();
        while (System.currentTimeMillis() <= time + ms) {
            int i = (int) (Math.random() * termes.length);
            int j = (int) (Math.random() * termes.length);
            if (i != j && !(termes[i].hasPVCommun(termes[j]))) {
                double fiabilite = testeConcordance(
                        termes[i], termes[j]) * testeConcordance(
                                termes[j], termes[i]);
                if (fiabilite > seuilN) {
                    ListeSynonymes l = new ListeSynonymes(
                            Charte.getMessage("Conf_SurA") + " " +
                            (int) (fiabilite * 100) + "%", "");
                    l.add(termes[i]);
                    l.add(termes[j]);
                    res.put(l.getSauvegarde(), l); // le Set ne marche pas ici
                }
            }
        }
        ListeSynonymes[] res3 = new ListeSynonymes[res.values().size()];
        res.values().toArray(res3);
        Arrays.sort(res3, new ComparateurSynonymes());
        return res3;
    }

    /**
     * Lance l'algorithme de suggestion de liens parmi les types de relation.
     * @return ListeSynonymes[] la réponse
     * @since 3.0.2
     */
    public ListeSynonymes[] suggereTypesLiensSynonymes() {
        Vector res = new Vector();
        TexteCommun[] termes = getAllTermesTypesLiens();
        for (int i = 0; i < termes.length; i++) {
            for (int j = i + 1; j < termes.length; j++) {
                if (!(termes[i].hasPVCommun(termes[j]))) {
                    double fiabilite = testeConcordance(
                            termes[i], termes[j]) * testeConcordance(
                            termes[j], termes[i]);
                    if (fiabilite > seuilT) {
                        ListeSynonymes l = new ListeSynonymes(
                                Charte.getMessage("Conf_SurA") + " " +
                                (int) (fiabilite * 100) + "%", "");
                        l.add(termes[i]);
                        l.add(termes[j]);
                        res.add(l);
                    }
                }
            }
        }
        ListeSynonymes[] res3 = new ListeSynonymes[res.size()];
        res.toArray(res3);
        Arrays.sort(res3, new ComparateurSynonymes());
        return res3;
    }

    /**
     * Lance l'algorithme de suggestion de liens parmi les types de relation,
     * qui ne tournera que le nombre de millisecondes imparti.<br>
     * Les alignements seront évalués au hasard, permettant ainsi une couverture
     * complète bien que non exhaustive.
     * @param ms int le temps alloué à la recherche
     * @return ListeSynonymes[] la réponse
     * @since 3.5.1
     */
    public ListeSynonymes[] suggereTypesLiensSynonymes(int ms){
        Map res = new HashMap();
        long time = System.currentTimeMillis();
        TexteCommun[] termes = getAllTermesTypesLiens();
        while (System.currentTimeMillis() < time + ms) {
            int i = (int) (Math.random() * termes.length);
            int j = (int) (Math.random() * termes.length);
            if (i != j && !(termes[i].hasPVCommun(termes[j]))) {
                double fiabilite = testeConcordance(
                        termes[i], termes[j]) * testeConcordance(
                                termes[j], termes[i]);
                if (fiabilite > seuilT) {
                    ListeSynonymes l = new ListeSynonymes(
                            Charte.getMessage("Conf_SurA") + " " +
                            (int) (fiabilite * 100) + "%", "");
                    l.add(termes[i]);
                    l.add(termes[j]);
                    res.put(l.getSauvegarde(), l); // le Set ne marche pas ici
                }
            }
        }
        ListeSynonymes[] res3 = new ListeSynonymes[res.values().size()];
        res.values().toArray(res3);
        Arrays.sort(res3, new ComparateurSynonymes());
        return res3;
    }

    /**
     * Lance l'algorithme de suggestion de liens parmi les propriétés.
     * @return ListeSynonymes[] la réponse
     * @since 3.0.2
     */
    public ListeSynonymes[] suggereProprietesSynonymes() {
        Vector res = new Vector();
        TexteCommun[] termes = getAllTermesProprietes();
        for (int i = 0; i < termes.length; i++) {
            for (int j = i + 1; j < termes.length; j++) {
                if (!(termes[i].hasPVCommun(termes[j]))) {
                    double fiabilite = testeConcordance(
                            termes[i], termes[j]) * testeConcordance(
                            termes[j], termes[i]);
                    if (fiabilite > seuilP) {
                        ListeSynonymes l = new ListeSynonymes(
                                Charte.getMessage("Conf_SurA") + " " +
                                (int) (fiabilite * 100) + "%", "");
                        l.add(termes[i]);
                        l.add(termes[j]);
                        res.add(l);
                    }
                }
            }
        }
        ListeSynonymes[] res3 = new ListeSynonymes[res.size()];
        res.toArray(res3);
        Arrays.sort(res3, new ComparateurSynonymes());
        return res3;
    }

    /**
     * Lance l'algorithme de suggestion de liens parmi les propriétés, qui ne
     * tournera que le nombre de millisecondes imparti.<br>
     * Les alignements seront évalués au hasard, permettant ainsi une couverture
     * complète bien que non exhaustive.
     * @param ms int le temps alloué à la recherche
     * @return ListeSynonymes[] la réponse
     * @since 3.5.1
     */
    public ListeSynonymes[] suggereProprietesSynonymes(int ms){
        Map res = new HashMap();
        long time = System.currentTimeMillis();
        TexteCommun[] termes = getAllTermesProprietes();
        while (System.currentTimeMillis() < time + ms) {
            int i = (int) (Math.random() * termes.length);
            int j = (int) (Math.random() * termes.length);
            if (i != j && !(termes[i].hasPVCommun(termes[j]))) {
                double fiabilite = testeConcordance(
                        termes[i], termes[j]) * testeConcordance(
                                termes[j], termes[i]);
                if (fiabilite > seuilP) {
                    ListeSynonymes l = new ListeSynonymes(
                            Charte.getMessage("Conf_SurA") + " " +
                            (int) (fiabilite * 100) + "%", "");
                    l.add(termes[i]);
                    l.add(termes[j]);
                    res.put(l.getSauvegarde(), l); // le Set ne marche pas ici
                }
            }
        }
        ListeSynonymes[] res3 = new ListeSynonymes[res.values().size()];
        res.values().toArray(res3);
        Arrays.sort(res3, new ComparateurSynonymes());
        return res3;
    }

    /**
     * Renvoie la liste des raisons invoquées lors du tissage d'un lien.
     * @return String[] la liste
     * @since 3.0.2
     */
    public String[] getRaisonsRapprocher() {
        if (raisonsRapprochement == null) {
            raisonsRapprochement = new Vector();
            //raisonsRapprochement.addElement(RAISON_IDENTITE);
            raisonsRapprochement.addElement(Charte.getMessage("Conf_Syno"));
            raisonsRapprochement.addElement(Charte.getMessage("Conf_Proches"));
            raisonsRapprochement.addElement(Charte.getMessage("Conf_Lies"));
            raisonsRapprochement.addElement(RAISON_A_PRECISER);
        }
        String[] res = new String[raisonsRapprochement.size()];
        raisonsRapprochement.toArray(res);
        return res;
    }

    /**
     * Rajoute une raison invoquée pour le tissage d'un lien.
     * @param raison String la raison
     * @since 3.0.2
     */
    public void ajouteRaisonRapprochement(String raison) {
        boolean nouveau = true;
        for (int i = 0; i < raisonsRapprochement.size(); i++) {
            if (((String) (raisonsRapprochement.elementAt(i))).equals(raison)) {
                nouveau = false;
                break;
            }
        }
        if (nouveau) {
            raisonsRapprochement.insertElementAt(
                    raison, raisonsRapprochement.size() - 1);
        }
    }

    /**
     * Renvoie la liste des raisons invoquées lors de la séparation d'un terme.
     * @return String[] la liste
     * @since 3.0.2
     */
    public String[] getRaisonsEloigner() {
        if (raisonsEloignement == null) {
            raisonsEloignement = new Vector();
            raisonsEloignement.addElement(Charte.getMessage("Conf_Homo"));
            raisonsEloignement.addElement(Charte.getMessage("Conf_Poly"));
            raisonsEloignement.addElement(Charte.getMessage("Conf_PasPar"));
            raisonsEloignement.addElement(RAISON_A_PRECISER);
        }
        String[] res = new String[raisonsEloignement.size()];
        raisonsEloignement.toArray(res);
        return res;
    }

    /**
     * Rajoute une raison invoquée pour la séparation d'un terme.
     * @param raison String la raison
     * @since 3.0.2
     */
    public void ajouteRaisonEloignement(String raison) {
        boolean nouveau = true;
        for (int i = 0; i < raisonsEloignement.size(); i++) {
            if (((String) (raisonsEloignement.elementAt(i))).equals(raison)) {
                nouveau = false;
                break;
            }
        }
        if (nouveau) {
            raisonsEloignement.insertElementAt(
                    raison, raisonsEloignement.size() - 1);
        }
    }

    /* Routine de test de la concordance entre deux termes. */
    private double testeConcordance(TexteCommun terme1, TexteCommun terme2) {
        boolean ok = false;
        String t1 = enleveMotsVides(formatage(terme1.getTexte()));
        String t2 = enleveMotsVides(formatage(terme2.getTexte()));
        int lettresCommunes = 0;
        int indexTerme1 = 0;
        int indexTerme2 = 0;
        int max = 0;
        for (int i = 0; i < t1.length(); i++) {
            indexTerme1 = i;
            lettresCommunes = 0;
            while (indexTerme1 < t1.length() &&
                   indexTerme2 < t2.length()) {
                if (t1.charAt(indexTerme1) ==
                    t2.charAt(indexTerme2)) {
                    indexTerme1++;
                    indexTerme2++;
                    lettresCommunes++;
                } else {
                    indexTerme1++;
                }
            }
            if (lettresCommunes > max) {
                max = lettresCommunes;
            }
        }
        return 1.0 * max / t2.length();
    }

    /* Routine d'expurgeage des mots vides dans un terme. */
    private String enleveMotsVides(String s) {
        String[] mots = formatage(s).trim().split(" ");
        Vector motsV = new Vector();
        for (int i = 0; i < mots.length; i++) {
            motsV.addElement(mots[i]);
        }
        Vector mv = new Vector(listeMotsVides);
        for (int h = 0; h < motsV.size(); h++) {
            for (int i = 0; i < mv.size(); i++) {
                if (((String) (motsV.elementAt(h))).
                    equalsIgnoreCase(((TexteCommun) (mv.elementAt(i))).getTexte())) {
                    motsV.remove(h);
                    h--;
                    break;
                }
            }
        }
        String res = "";
        for (int i = 0; i < motsV.size(); i++) {
            res += (String) (motsV.elementAt(i)) + " ";
        }
        return res.trim();
    }

    /* Routine d'élimination des caractères accentués, spéciaux et d'espacement
     (ces derniers sont changés en espaces). */
    private String formatage(String s) {
        s = s.toLowerCase();
        s = s.replaceAll("á|à|â|ä|å", "a");
        s = s.replaceAll("ß", "ss");
        s = s.replaceAll("ç", "c");
        s = s.replaceAll("é|è|ê|ë", "e");
        s = s.replaceAll("í|ì|î|ï", "i");
        s = s.replaceAll("ñ", "n");
        s = s.replaceAll("ó|ò|ô|ö", "o");
        s = s.replaceAll("ú|ù|û|ü", "u");
        s = s.replaceAll("ÿ", "y");
        s = s.replaceAll("\\W", "");
        return s;
    }

    /**
     * Renvoie les listes de termes liés contenant l'un des termes de la liste
     * donnée en paramètre.
     * @param l ListeSynonymes la liste contenant les termes liés à retrouver
     * @return LienEntreListes[] la liste des liens trouvés contenant ces termes
     * @since 3.0.3
     */
    public LienEntreListes[] getListesLiees(ListeSynonymes l) {
        if (allTermesNoeuds == null) {
            allTermesNoeuds = new HashMap();
            for (int i = 0; i < graphes.length; i++) {
                Noeud[] noeuds = graphes[i].getAllNoeuds();
                for (int j = 0; j < noeuds.length; j++) {
                    String terme = noeuds[j].getLabel();
                    TexteCommun tc = (TexteCommun) (allTermesNoeuds.get(terme));
                    if (tc == null) {
                        TexteCommun add = new TexteCommun(terme,
                                graphes.length);
                        add.addConcerne(i, true);
                        allTermesNoeuds.put(terme, add);
                    } else {
                        tc.addConcerne(i, true);
                    }
                }
            }
        }

        Set res = new HashSet();
        TexteCommun[] mots = l.getListe();
        for (int i = 0; i < mots.length; i++) {
            for (int j = 0; j < graphes.length; j++) {
                if (mots[i].getConcernes()[j] == true) {
                    Association[] liens = graphes[j].getAssociationsContenant(
                            graphes[j].trouveNoeud(mots[i].getTexte()));
                    for (int k = 0; k < liens.length; k++) {
                        String orig = liens[k].getOrigine().getLabel();
                        String dest = liens[k].getDestination().getLabel();
                        String autre = "";
                        if (orig.equals(mots[i].getTexte())) {
                            autre = dest;
                        } else {
                            autre = orig;
                        }
                        TexteCommun motLie = (TexteCommun) (allTermesNoeuds.get(
                                autre));
                        ListeSynonymes[] synos = this.getListesSynonymesNoeuds();
                        boolean trouve = false;
                        for (int m = 0; m < synos.length; m++) {
                            if (synos[m].contains(motLie)) {
                                trouve = true;
                                res.add(new LienEntreListes(l, synos[m]));
                            }
                        }
                        if (!trouve) {
                            ListeSynonymes lDest = new ListeSynonymes("", "");
                            lDest.add(motLie);
                            res.add(new LienEntreListes(l, lDest));
                        }
                    }
                }
            }
        }

        LienEntreListes[] res2 = new LienEntreListes[res.size()];
        res.toArray(res2);
        return res2;
    }

    /**
     * Renvoie une description textuelle de l'objet.
     * @return String une description textuelle de l'objet
     * @since 4.0.1
     */
    public String toString(){
        return "Confronteur de "+graphes.length+" points de vue.";
    }


    /**
     * Renvoie un comparateur de MotHomonymes.
     * @return Comparator le comparateur en question
     * @since 3.0.4
     */
    public Comparator getComparateurHomonymes() {
        return new ComparateurHomonymes();
    }

    /**
     * Renvoie un comparateur alphabétique de TexteCommuns.
     * @return Comparator le comparateur en question
     * @since 3.0.2
     */
    public Comparator getComparateurAlphabetique() {
        return new ComparateurTexteCommun();
    }

    /**
     * Renvoie un comparateur de termes par nombre de lettres.
     * @return Comparator le comparateur en question
     * @since 3.0.2
     */
    public Comparator getComparateurParNbLettres() {
        return new ComparateurMotsVides();
    }


    private class TableSynonymes {
        private Vector liste;

        public TableSynonymes() {
            liste = new Vector();
        }

        public void add(ListeSynonymes synos) {
            liste.add(synos);
            controleIntersections();
        }

        public void remove(ListeSynonymes synos) {
            liste.remove(synos);
        }

        private void controleIntersections() {
            for (int i = 0; i < liste.size(); i++) {
                for (int j = i + 1; j < liste.size(); j++) {
                    ListeSynonymes l1 = (ListeSynonymes) (liste.elementAt(i));
                    ListeSynonymes l2 = (ListeSynonymes) (liste.elementAt(j));
                    if (l1.intersects(l2) && !(l1.equals(l2))) {
                        l1.mergeWith(l2);
                        liste.remove(l2);
                        j--;
                        i--;
                        break;
                    }
                }
            }
        }

        public ListeSynonymes[] getListes() {
            ListeSynonymes[] res = new ListeSynonymes[liste.size()];
            liste.toArray(res);
            return res;
        }
    }

    private class ComparateurMotsVides implements Comparator {
        public int compare(Object o1, Object o2) {
            int a = ((TexteCommun) (o1)).getTexte().length() -
                    ((TexteCommun) (o2)).getTexte().length();
            if (a == 0) {
                a = formatage(((TexteCommun) (o1)).getTexte()).
                    compareToIgnoreCase(
                            formatage(((TexteCommun) (o2)).getTexte()));
            }
            return a;
        }
    }

    private class ComparateurTexteCommun implements Comparator {
        public int compare(Object o1, Object o2) {
            int a = formatage(((TexteCommun) (o1)).getTexte()).
                    compareToIgnoreCase(
                            formatage(((TexteCommun) (o2)).getTexte()));
            return a;
        }
    }

    private class ComparateurString implements Comparator {
        public int compare(Object o1, Object o2) {
            int a = formatage((String) (o1)).compareToIgnoreCase(
                    formatage((String) (o2)));
            return a;
        }
    }

    private class ComparateurSynonymes implements Comparator {
        public int compare(Object o1, Object o2) {
            ListeSynonymes l1 = (ListeSynonymes) o1;
            ListeSynonymes l2 = (ListeSynonymes) o2;
            String[] parse1 = l1.getLien().split(" ");
            String[] parse2 = l2.getLien().split(" ");
            String nb1 = parse1[parse1.length-1];
            String nb2 = parse2[parse2.length-1];
            int i1 = Integer.parseInt(nb1.substring(0,
                    nb1.length() - 1));
            int i2 = Integer.parseInt(nb2.substring(0,
                    nb2.length() - 1));
            return i2 - i1;
        }
    }

    private class ComparateurHomonymes implements Comparator {
        public int compare(Object o1, Object o2) {
            MotHomonyme l1 = (MotHomonyme) o1;
            MotHomonyme l2 = (MotHomonyme) o2;
            return l1.getMots()[0].getTexte().compareToIgnoreCase(l2.getMots()[
                    0].getTexte());
        }
    }
}
