/*
Copyright 2012-2014 Samuel Gesche

This file is part of the Greek Reuse Toolkit.

The Greek Reuse Toolkit 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.

The Greek Reuse Toolkit 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 the Greek Reuse Toolkit.  If not, see <http://www.gnu.org/licenses/>.
*/

package fr.cnrs.liris.drim.grt.proc.parsers;

import fr.cnrs.liris.drim.grt.modele.Coordonnee;
import fr.cnrs.liris.drim.grt.modele.OrdreStrict;
import fr.cnrs.liris.drim.grt.modele.Reference;
import fr.cnrs.liris.drim.grt.modele.convertisseurs.ConvertisseurNomLivresBible;
import java.util.ArrayList;

/**
 *
 * @author sgesche
 */
public class References {
    
    /**
     * Essaie de trouver une référence à partir du texte fourni.
     * @param formeTextuelle un texte à parcourir, contenant la référence et uniquement elle
     * @param typePassage le type du passage : biblique, patristique ou Philon (@see PassageType)
     * @return un objet Reference correspondant
     * @throws IllegalArgumentException si le texte ne correspond pas à une référence
     */
    public static Reference parseReference(String formeTextuelle, int typePassage) throws IllegalArgumentException{
        Reference resultat = null;
        switch(typePassage) {
            case PassageType.PASSAGE_BIBLIQUE:
                resultat = parseReferenceBiblique(formeTextuelle);
                break;
            case PassageType.PASSAGE_PATRISTIQUE:
                resultat = parseReferencePatristique(formeTextuelle);
                break;
            case PassageType.PASSAGE_PHILON:
                resultat = parseReferencePhilon(formeTextuelle);
                break;
            default:
                
        }
        return resultat;
    }
    
    /**
     * Essaie de trouver une référence biblique à partir du texte fourni.
     * 
     * Le texte doit être composé comme suit : 
     * (a) des plages séparées par des virgules (x, y, z)
     * (b) les plages comportent un nom de livre, un espace, puis une plage de chapitre (Mat 15.2)
     * (c) dans les plages de chapitre, des intervalles sont représentés par des tirets (15-18), 
     * et le passage au verset par un point (2.3). Le premier nombre doit être un 
     * numéro de chapitre (même dans le cas des livres qui n'en ont qu'un). Il 
     * peut y avoir des intervalles sur plusieurs chapitres (2.8-3.2).
     * 
     * Il n'y a aucune garantie que la référence à trouver existe dans un quelconque document. 
     * Pour vérifier ce point, @see Passage.rassembleReference().
     * 
     * Il est supposé que la granularité des textes bibliques va jusqu'au verset, 
     * et non jusqu'au mot.
     * 
     * @param formeTextuelle un texte à parcourir, contenant la référence et uniquement elle
     * @return un objet Reference correspondant
     * @throws IllegalArgumentException si le texte ne correspond pas à une référence
     */
    private static Reference parseReferenceBiblique(String formeTextuelle) throws IllegalArgumentException {
        //System.err.println("A parser : " + formeTextuelle);       
        
        String[] plages = formeTextuelle.split(", ");
        for(int i=0; i<plages.length; i++) {
            plages[i] = plages[i].trim();
        }
        
        ArrayList<Reference> references = new ArrayList<>();
        for(String plage: plages) {
            //System.err.println("Analyse : " + plage);
            Reference courante = new Reference();
            String[] livreEtReste = plage.split(" ");
            for(int i=0; i<livreEtReste.length; i++) {
                livreEtReste[i] = livreEtReste[i].trim();
            }
            
            if(livreEtReste.length > 2) {
                throw new IllegalArgumentException("Cette référence ("+plage+") "
                        + "n'est pas réductible à un livre et une plage de chapitres/lignes. "
                        + "S'il y a plusieurs livres, séparez-les par des virgules.");
            }
            
            String livre = livreEtReste[0];
            if(OrdreStrict.getInstance(OrdreStrict.LIVRES_BIB).contient(livre)) {
                courante.setBorne(Reference.COTE_DEBUT, 
                    new Coordonnee(OrdreStrict.getInstance(OrdreStrict.LIVRES_BIB), livre));
            } else {
                throw new IllegalArgumentException("Le livre '"+livre+"' "
                        + "n'est pas dans les versions bibliques disponibles.");
            }
            
            
            if(livreEtReste.length == 2) {
            /* ça devient technique :
             *  - S'il n'y a pas de tiret : 
             *    - s'il y a un point, c'est chapitre.verset (c.v)
             *    - sinon, c'est chapitre
             *  - s'il y a un tiret : 
             *    - s'il y a un point avant : 
             *      - s'il y a un point après, c'est une plage de chapitres partiels (c.v - c.v)
             *      - sinon, c'est une plage de versets (c.v-v)
             *    - sinon : 
             *      - s'il y a un point après, c'est une plage de chapitres partiels (c - c.v)
             *      - sinon, c'est une plage de chapitres entiers (c-c)
             */
            String[] test1 = livreEtReste[1].split("\\-");
            for(int i=0; i<test1.length; i++) {
                test1[i] = test1[i].trim();
            }
            
            if(test1.length > 2) {
                throw new IllegalArgumentException("Cette plage ("+livreEtReste[1]+") "
                        + "n'est pas correcte (trop de tirets).");
            }
            
            if(test1.length == 1) {
                String[] test2 = test1[0].split("\\.");
                for(int i=0; i<test2.length; i++) {
                    test2[i] = test2[i].trim();
                }
                
                if(test2.length > 2) {
                    throw new IllegalArgumentException("Cette plage ("+test1[0]+") "
                            + "n'est pas correcte (trop de points pour chapitre.verset).");
                }
                
                if(test2.length == 1) {
                    try {
                        int chapitre = Integer.parseInt(test2[0]);
                        Reference c = new Reference();
                        c.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre));
                        courante.addSousReference(Reference.RELATION_PRECISION, c);
                    } catch(NumberFormatException nfe) {
                        throw new IllegalArgumentException("Numéro incorrect ("+test2[0]+").");
                    }
                } else {
                    try {
                        int chapitre = Integer.parseInt(test2[0]);
                        Reference c = new Reference();
                        c.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre));
                        courante.addSousReference(Reference.RELATION_PRECISION, c);
                        int verset = Integer.parseInt(test2[1]);
                        Reference v = new Reference();
                        v.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), verset));
                        c.addSousReference(Reference.RELATION_PRECISION, v);
                    } catch(NumberFormatException nfe) {
                        throw new IllegalArgumentException("Numéro incorrect ("+test2[0]
                                + " ou " + test2[1]+").");
                    }
                }
            } else {
                //System.err.println("   -> deux parties : " + Arrays.toString(test1));
                String[] test2 = test1[1].split("\\.");
                String[] test3 = test1[0].split("\\.");
                for(int i=0; i<test2.length; i++) {
                    test2[i] = test2[i].trim();
                }
                for(int i=0; i<test3.length; i++) {
                    test3[i] = test3[i].trim();
                }
                
                if(test2.length > 2) {
                    throw new IllegalArgumentException("Cette plage ("+test1[1]+") "
                            + "n'est pas correcte (trop de points pour chapitre.verset).");
                }
                if(test3.length > 2) {
                    throw new IllegalArgumentException("Cette plage ("+test1[0]+") "
                            + "n'est pas correcte (trop de points pour chapitre.verset).");
                }
                if(test3.length == 1) {
                    if(test2.length == 1) {
                        // plage de chapitres complets
                        try {
                            int chapitre0 = Integer.parseInt(test3[0]);
                            int chapitre1 = Integer.parseInt(test2[0]);
                            Reference c = new Reference();
                            //System.err.println("01 essai de mettre chapitre début et fin : " + chapitre0 + ", " + chapitre1);
                            c.setBorne(Reference.COTE_DEBUT, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre0));
                            c.setBorne(Reference.COTE_FIN, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre1));
                            courante.addSousReference(Reference.RELATION_PRECISION, c);
                        } catch(NumberFormatException nfe) {
                            throw new IllegalArgumentException("Numéro incorrect ("+test3[0]
                                    + " ou " + test2[0]+").");
                        }
                    } else {
                        // plage de chapitres partiels
                        try {
                            int chapitre0 = Integer.parseInt(test3[0]);
                            int chapitre1 = Integer.parseInt(test2[0]);
                            int verset1 = Integer.parseInt(test2[1]);
                            
                            Reference c0 = new Reference();
                            Coordonnee coo0 = new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre0);
                            c0.setBorne(Reference.COTE_DEBUT, coo0);
                            
                            Reference c1 = new Reference();
                            Coordonnee coo1 = new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre1);
                            c1.setBorne(Reference.COTE_DEBUT, coo1);
                            Reference v1 = new Reference();
                            //System.err.println("02 essai de mettre verset début et fin : " + 1 + ", " + verset1);
                            v1.setBorne(Reference.COTE_DEBUT, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), 1));
                            v1.setBorne(Reference.COTE_FIN, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), verset1));
                            c1.addSousReference(Reference.RELATION_PRECISION, v1);
                            
                            Coordonnee coo = new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), coo0);
                            do {
                                Reference c = new Reference();
                                c.setBorne(Reference.COTE_DEBUT, coo);
                                c0.addSousReference(Reference.RELATION_INCLUSION, c);
                                coo = new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), coo);
                            } while(!coo.equals(coo1));
                            c0.addSousReference(Reference.RELATION_INCLUSION, c1);
                            
                            courante.addSousReference(Reference.RELATION_PRECISION, c0);
                        } catch(NumberFormatException nfe) {
                            throw new IllegalArgumentException("Numéro incorrect ("+test3[0]
                                    + ", " + test2[0] + " ou " + test2[1]+").");
                        }
                    }
                } else {
                    if(test2.length == 1) {
                        // plage de versets
                        try {
                            int chapitre = Integer.parseInt(test3[0]);
                            int verset0 = Integer.parseInt(test3[1]);
                            int verset1 = Integer.parseInt(test2[0]);
                            
                            
                            Reference c = new Reference();
                            Coordonnee coo0 = new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre);
                            c.setBorne(Reference.COTE_DEBUT, coo0);
                            Reference v0 = new Reference();
                            //System.err.println("03 essai de mettre verset début et fin : " + verset0 + ", " + verset1);
                            v0.setBorne(Reference.COTE_DEBUT, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), verset0));
                            v0.setBorne(Reference.COTE_FIN, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), verset1));
                            c.addSousReference(Reference.RELATION_PRECISION, v0);
                            courante.addSousReference(Reference.RELATION_PRECISION, c);
                            
                        } catch(NumberFormatException nfe) {
                            throw new IllegalArgumentException("Numéro incorrect ("+test3[0]
                                    + ", " + test3[1] + " ou " + test2[0]+").");
                        }
                    } else {
                        // plage de chapitres partiels
                        if(test2[0].equals(Coordonnee.FIN) && test2[1].equals(Coordonnee.FIN)) {
                            int chapitre0 = Integer.parseInt(test3[0]);
                            int verset0 = Integer.parseInt(test3[1]);
                            
                            Reference c0 = new Reference();
                            Coordonnee coo0 = new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre0);
                            c0.setBorne(Reference.COTE_DEBUT, coo0);
                            Coordonnee coo1 = new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), Coordonnee.FIN);
                            c0.setBorne(Reference.COTE_FIN, coo1);
                            Reference v0 = new Reference();
                            //System.err.println("04 essai de mettre verset début et fin : " + verset0 + ", " + Coordonnee.FIN);
                            v0.setBorne(Reference.COTE_DEBUT, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), verset0));
                            v0.setBorne(Reference.COTE_FIN, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), Coordonnee.FIN));
                            c0.addSousReference(Reference.RELATION_PRECISION, v0);
                            
                            courante.addSousReference(Reference.RELATION_PRECISION, c0);
                        } else {
                            try {
                                int chapitre0 = Integer.parseInt(test3[0]);
                                int verset0 = Integer.parseInt(test3[1]);
                                int chapitre1 = Integer.parseInt(test2[0]);
                                int verset1 = Integer.parseInt(test2[1]);

                                Reference c0 = new Reference();
                                Coordonnee coo0 = new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre0);
                                c0.setBorne(Reference.COTE_DEBUT, coo0);
                                Reference v0 = new Reference();
                                //System.err.println("05 essai de mettre verset début et fin : " + verset0 + ", " + Coordonnee.FIN);
                                v0.setBorne(Reference.COTE_DEBUT, 
                                    new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), verset0));
                                v0.setBorne(Reference.COTE_FIN, 
                                    new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), Coordonnee.FIN));
                                c0.addSousReference(Reference.RELATION_PRECISION, v0);

                                Reference c1 = new Reference();
                                Coordonnee coo1 = new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre1);
                                c1.setBorne(Reference.COTE_DEBUT, coo1);
                                Reference v1 = new Reference();
                                //System.err.println("06 essai de mettre verset début et fin : " + 1 + ", " + verset1);
                                v1.setBorne(Reference.COTE_DEBUT, 
                                    new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), 1));
                                if(verset1 > 1) {
                                    v1.setBorne(Reference.COTE_FIN, 
                                        new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), verset1));
                                }
                                c1.addSousReference(Reference.RELATION_PRECISION, v1);

                                Coordonnee coo = coo0.getSuivante();
                                while(!coo.equals(coo1)) {
                                    Reference c = new Reference();
                                    c.setBorne(Reference.COTE_DEBUT, coo);
                                    c0.addSousReference(Reference.RELATION_INCLUSION, c);
                                    coo = coo.getSuivante();
                                }
                                c0.addSousReference(Reference.RELATION_INCLUSION, c1);

                                courante.addSousReference(Reference.RELATION_PRECISION, c0);
                            } catch(NumberFormatException nfe) {
                                throw new IllegalArgumentException("Numéro incorrect ("+test3[0]
                                        + ", " + test3[1] + ", " + test2[0] + " ou " + test2[1]+").");
                            }
                        }
                    }
                }
            }
            }
            references.add(courante);
        }
            
        Reference resultat = references.get(0);
        if(plages.length > 1) {
            for(int i=1; i<references.size(); i++) {
                resultat.addSousReference(Reference.RELATION_INCLUSION, references.get(i));
            }
        }
        //System.err.println(" Résultat : " + resultat.toString());
        return resultat;
    }
    
    /**
     * Essaie de trouver une référence à un corpus à partir du texte fourni.
     * 
     * Le texte doit être composé comme suit : 
     * (a) des plages séparées par des virgules (x, y, z)
     * (b) les plages comportent un nom de livre, un espace, puis une plage de chapitre (Abr 15.2)
     * (c) dans les plages de chapitre, des intervalles sont représentés par des tirets (15-18), 
     * et le passage au verset par un point (2.3). Le premier nombre doit être un 
     * numéro de chapitre (même dans le cas des livres qui n'en ont qu'un). Il 
     * peut y avoir des intervalles sur plusieurs chapitres (2.8-3.2).
     * 
     * Il n'y a aucune garantie que la référence à trouver existe dans un quelconque document. 
     * Pour vérifier ce point, @see Passage.rassembleReference().
     * 
     * Il est supposé que la granularité des textes va jusqu'à la ligne, 
     * et non jusqu'au mot.
     * 
     * @param formeTextuelle un texte à parcourir, contenant la référence et uniquement elle
     * @return un objet Reference correspondant
     * @throws IllegalArgumentException si le texte ne correspond pas à une référence
     */
    private static Reference parseReferencePhilon(String formeTextuelle) throws IllegalArgumentException {
        //System.err.println("A parser : " + formeTextuelle);       
        
        String[] plages = formeTextuelle.split(", ");
        for(int i=0; i<plages.length; i++) {
            plages[i] = plages[i].trim();
        }
        
        ArrayList<Reference> references = new ArrayList<>();
        for(String plage: plages) {
            //System.err.println("Analyse : " + plage);
            Reference courante = new Reference();
            String[] livreEtReste = plage.split(" ");
            for(int i=0; i<livreEtReste.length; i++) {
                livreEtReste[i] = livreEtReste[i].trim();
            }
            
            if(livreEtReste.length > 2) {
                throw new IllegalArgumentException("Cette référence ("+plage+") "
                        + "n'est pas réductible à un livre et une plage de chapitres/versets. "
                        + "S'il y a plusieurs livres, séparez-les par des virgules.");
            }
            
            String livre = livreEtReste[0];
            if(OrdreStrict.getInstance(OrdreStrict.LIVRES_PHI).contient(livre)) {
                courante.setBorne(Reference.COTE_DEBUT, 
                    new Coordonnee(OrdreStrict.getInstance(OrdreStrict.LIVRES_PHI), livre));
            } else {
                throw new IllegalArgumentException("Le livre '"+livre+"' "
                        + "n'est pas dans les versions bibliques disponibles.");
            }
            
            
            if(livreEtReste.length == 2) {
            /* ça devient technique :
             *  - S'il n'y a pas de tiret : 
             *    - s'il y a un point, c'est chapitre.verset (c.v)
             *    - sinon, c'est chapitre
             *  - s'il y a un tiret : 
             *    - s'il y a un point avant : 
             *      - s'il y a un point après, c'est une plage de chapitres partiels (c.v - c.v)
             *      - sinon, c'est une plage de versets (c.v-v)
             *    - sinon : 
             *      - s'il y a un point après, c'est une plage de chapitres partiels (c - c.v)
             *      - sinon, c'est une plage de chapitres entiers (c-c)
             */
            String[] test1 = livreEtReste[1].split("\\-");
            for(int i=0; i<test1.length; i++) {
                test1[i] = test1[i].trim();
            }
            
            if(test1.length > 2) {
                throw new IllegalArgumentException("Cette plage ("+livreEtReste[1]+") "
                        + "n'est pas correcte (trop de tirets).");
            }
            
            if(test1.length == 1) {
                String[] test2 = test1[0].split("\\.");
                for(int i=0; i<test2.length; i++) {
                    test2[i] = test2[i].trim();
                }
                
                if(test2.length > 2) {
                    throw new IllegalArgumentException("Cette plage ("+test1[0]+") "
                            + "n'est pas correcte (trop de points pour chapitre.verset).");
                }
                
                if(test2.length == 1) {
                    try {
                        int chapitre = Integer.parseInt(test2[0]);
                        Reference c = new Reference();
                        c.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre));
                        courante.addSousReference(Reference.RELATION_PRECISION, c);
                    } catch(NumberFormatException nfe) {
                        throw new IllegalArgumentException("Numéro incorrect ("+test2[0]+").");
                    }
                } else {
                    try {
                        int chapitre = Integer.parseInt(test2[0]);
                        Reference c = new Reference();
                        c.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre));
                        courante.addSousReference(Reference.RELATION_PRECISION, c);
                        int verset = Integer.parseInt(test2[1]);
                        Reference v = new Reference();
                        v.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), verset));
                        c.addSousReference(Reference.RELATION_PRECISION, v);
                    } catch(NumberFormatException nfe) {
                        throw new IllegalArgumentException("Numéro incorrect ("+test2[0]
                                + " ou " + test2[1]+").");
                    }
                }
            } else {
                //System.err.println("   -> deux parties : " + Arrays.toString(test1));
                String[] test2 = test1[1].split("\\.");
                String[] test3 = test1[0].split("\\.");
                for(int i=0; i<test2.length; i++) {
                    test2[i] = test2[i].trim();
                }
                for(int i=0; i<test3.length; i++) {
                    test3[i] = test3[i].trim();
                }
                
                if(test2.length > 2) {
                    throw new IllegalArgumentException("Cette plage ("+test1[1]+") "
                            + "n'est pas correcte (trop de points pour chapitre.verset).");
                }
                if(test3.length > 2) {
                    throw new IllegalArgumentException("Cette plage ("+test1[0]+") "
                            + "n'est pas correcte (trop de points pour chapitre.verset).");
                }
                if(test3.length == 1) {
                    if(test2.length == 1) {
                        // plage de chapitres complets
                        try {
                            int chapitre0 = Integer.parseInt(test3[0]);
                            int chapitre1 = Integer.parseInt(test2[0]);
                            Reference c = new Reference();
                            //System.err.println("01 essai de mettre chapitre début et fin : " + chapitre0 + ", " + chapitre1);
                            c.setBorne(Reference.COTE_DEBUT, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre0));
                            c.setBorne(Reference.COTE_FIN, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre1));
                            courante.addSousReference(Reference.RELATION_PRECISION, c);
                        } catch(NumberFormatException nfe) {
                            throw new IllegalArgumentException("Numéro incorrect ("+test3[0]
                                    + " ou " + test2[0]+").");
                        }
                    } else {
                        // plage de chapitres partiels
                        try {
                            int chapitre0 = Integer.parseInt(test3[0]);
                            int chapitre1 = Integer.parseInt(test2[0]);
                            int verset1 = Integer.parseInt(test2[1]);
                            
                            Reference c0 = new Reference();
                            Coordonnee coo0 = new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre0);
                            c0.setBorne(Reference.COTE_DEBUT, coo0);
                            
                            Reference c1 = new Reference();
                            Coordonnee coo1 = new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre1);
                            c1.setBorne(Reference.COTE_DEBUT, coo1);
                            Reference v1 = new Reference();
                            //System.err.println("02 essai de mettre verset début et fin : " + 1 + ", " + verset1);
                            v1.setBorne(Reference.COTE_DEBUT, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), 1));
                            v1.setBorne(Reference.COTE_FIN, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), verset1));
                            c1.addSousReference(Reference.RELATION_PRECISION, v1);
                            
                            Coordonnee coo = new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), coo0);
                            do {
                                Reference c = new Reference();
                                c.setBorne(Reference.COTE_DEBUT, coo);
                                c0.addSousReference(Reference.RELATION_INCLUSION, c);
                                coo = new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), coo);
                            } while(!coo.equals(coo1));
                            c0.addSousReference(Reference.RELATION_INCLUSION, c1);
                            
                            courante.addSousReference(Reference.RELATION_PRECISION, c0);
                        } catch(NumberFormatException nfe) {
                            throw new IllegalArgumentException("Numéro incorrect ("+test3[0]
                                    + ", " + test2[0] + " ou " + test2[1]+").");
                        }
                    }
                } else {
                    if(test2.length == 1) {
                        // plage de versets
                        try {
                            int chapitre = Integer.parseInt(test3[0]);
                            int verset0 = Integer.parseInt(test3[1]);
                            int verset1 = Integer.parseInt(test2[0]);
                            
                            
                            Reference c = new Reference();
                            Coordonnee coo0 = new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre);
                            c.setBorne(Reference.COTE_DEBUT, coo0);
                            Reference v0 = new Reference();
                            //System.err.println("03 essai de mettre verset début et fin : " + verset0 + ", " + verset1);
                            v0.setBorne(Reference.COTE_DEBUT, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), verset0));
                            v0.setBorne(Reference.COTE_FIN, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), verset1));
                            c.addSousReference(Reference.RELATION_PRECISION, v0);
                            courante.addSousReference(Reference.RELATION_PRECISION, c);
                            
                        } catch(NumberFormatException nfe) {
                            throw new IllegalArgumentException("Numéro incorrect ("+test3[0]
                                    + ", " + test3[1] + " ou " + test2[0]+").");
                        }
                    } else {
                        // plage de chapitres partiels
                        if(test2[0].equals(Coordonnee.FIN) && test2[1].equals(Coordonnee.FIN)) {
                            int chapitre0 = Integer.parseInt(test3[0]);
                            int verset0 = Integer.parseInt(test3[1]);
                            
                            Reference c0 = new Reference();
                            Coordonnee coo0 = new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre0);
                            c0.setBorne(Reference.COTE_DEBUT, coo0);
                            Coordonnee coo1 = new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), Coordonnee.FIN);
                            c0.setBorne(Reference.COTE_FIN, coo1);
                            Reference v0 = new Reference();
                            //System.err.println("04 essai de mettre verset début et fin : " + verset0 + ", " + Coordonnee.FIN);
                            v0.setBorne(Reference.COTE_DEBUT, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), verset0));
                            v0.setBorne(Reference.COTE_FIN, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), Coordonnee.FIN));
                            c0.addSousReference(Reference.RELATION_PRECISION, v0);
                            
                            courante.addSousReference(Reference.RELATION_PRECISION, c0);
                        } else {
                            try {
                                int chapitre0 = Integer.parseInt(test3[0]);
                                int verset0 = Integer.parseInt(test3[1]);
                                int chapitre1 = Integer.parseInt(test2[0]);
                                int verset1 = Integer.parseInt(test2[1]);

                                Reference c0 = new Reference();
                                Coordonnee coo0 = new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre0);
                                c0.setBorne(Reference.COTE_DEBUT, coo0);
                                Reference v0 = new Reference();
                                //System.err.println("05 essai de mettre verset début et fin : " + verset0 + ", " + Coordonnee.FIN);
                                v0.setBorne(Reference.COTE_DEBUT, 
                                    new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), verset0));
                                v0.setBorne(Reference.COTE_FIN, 
                                    new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), Coordonnee.FIN));
                                c0.addSousReference(Reference.RELATION_PRECISION, v0);

                                Reference c1 = new Reference();
                                Coordonnee coo1 = new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre1);
                                c1.setBorne(Reference.COTE_DEBUT, coo1);
                                Reference v1 = new Reference();
                                //System.err.println("06 essai de mettre verset début et fin : " + 1 + ", " + verset1);
                                v1.setBorne(Reference.COTE_DEBUT, 
                                    new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), 1));
                                if(verset1 > 1) {
                                    v1.setBorne(Reference.COTE_FIN, 
                                        new Coordonnee(OrdreStrict.getInstance(OrdreStrict.VERSETS), verset1));
                                }
                                c1.addSousReference(Reference.RELATION_PRECISION, v1);

                                Coordonnee coo = coo0.getSuivante();
                                while(!coo.equals(coo1)) {
                                    Reference c = new Reference();
                                    c.setBorne(Reference.COTE_DEBUT, coo);
                                    c0.addSousReference(Reference.RELATION_INCLUSION, c);
                                    coo = coo.getSuivante();
                                }
                                c0.addSousReference(Reference.RELATION_INCLUSION, c1);

                                courante.addSousReference(Reference.RELATION_PRECISION, c0);
                            } catch(NumberFormatException nfe) {
                                throw new IllegalArgumentException("Numéro incorrect ("+test3[0]
                                        + ", " + test3[1] + ", " + test2[0] + " ou " + test2[1]+").");
                            }
                        }
                    }
                }
            }
            }
            references.add(courante);
        }
            
        Reference resultat = references.get(0);
        if(plages.length > 1) {
            for(int i=1; i<references.size(); i++) {
                resultat.addSousReference(Reference.RELATION_INCLUSION, references.get(i));
            }
        }
        //System.err.println(" Résultat : " + resultat.toString());
        return resultat;
    }
    
    /**
     * Essaie de trouver une référence patristique à partir du texte fourni.
     * 
     * Le texte doit être composé comme suit : 
     * (a) des plages séparées par des virgules (x, y, z)
     * (b) les plages comportant un numéro de chapitre, de paragraphe, de ligne, puis de mot ; 
     * les trois premiers sont séparés par des points, le dernier est séparé du reste par un espace
     * (c.p.l m)
     * (c) les intervalles sont représentés par des tirets ; pour simplifier, les tirets ne séparent 
     * que des parties complètes (c.p.l m - c.p.l m et non par exemple c.p.l m-m)
     * 
     * Il n'y a aucune garantie que la référence à trouver existe dans un quelconque document. 
     * Pour vérifier ce point, @see Passage.rassembleReference().
     *
     * @param formeTextuelle un texte à parcourir, contenant la référence et uniquement elle
     * @return un objet Reference correspondant
     * @throws IllegalArgumentException si le texte ne correspond pas à une référence
     */
    private static Reference parseReferencePatristique(String formeTextuelle) throws IllegalArgumentException {
        //System.err.println("A parser : " + formeTextuelle);
        
        String[] plages = formeTextuelle.split(", ");
        for(int i=0; i<plages.length; i++) {
            plages[i] = plages[i].trim();
        }
        
        ArrayList<Reference> references = new ArrayList<>();
        for(String plage: plages) {
            //System.err.println("Analyse : " + plage);
            Reference courante = new Reference();
            
            String[] intervalle = plage.split("\\-");
            for(int i=0; i<intervalle.length; i++) {
                intervalle[i] = intervalle[i].trim();
            }
            
            if(intervalle.length > 2) {
                throw new IllegalArgumentException("Cette plage ("+plage+") "
                        + "n'est pas correcte (trop de tirets).");
            }
            
            if(intervalle.length == 1) {
                // partie unique
                String[] motEtReste = intervalle[0].split(" ");
                for(int i=0; i<motEtReste.length; i++) {
                    motEtReste[i] = motEtReste[i].trim();
                }
                int chapitre = -1;
                int paragraphe = -1;
                int ligne = -1;
                int mot = -1;
                
                if(motEtReste.length == 2) {
                    // mot
                    try {
                        mot = Integer.parseInt(motEtReste[1]);
                    } catch(NumberFormatException nfe) {
                        throw new IllegalArgumentException("Numéro incorrect ("+motEtReste[1]+").");
                    }
                }
                // ligne, paragraphe ou chapitre
                String[] reste = motEtReste[0].split("\\.");
                for(int i=0; i<reste.length; i++) {
                    reste[i] = reste[i].trim();
                }

                if(reste.length > 3) {
                    throw new IllegalArgumentException("Cette référence ("+motEtReste[0]+") "
                        + "n'a pas la structure chapitre.paragraphe.ligne.");
                }
                    
                switch(reste.length) {
                    case 3:
                        // chapitre.paragraphe.ligne
                        try {
                            ligne = Integer.parseInt(reste[2]);
                        } catch(NumberFormatException nfe) {
                            throw new IllegalArgumentException("Numéro incorrect ("+reste[2]+").");
                        }
                    case 2:
                        // chapitre.paragraphe
                        try {
                            paragraphe = Integer.parseInt(reste[1]);
                        } catch(NumberFormatException nfe) {
                            throw new IllegalArgumentException("Numéro incorrect ("+reste[1]+").");
                        }
                    case 1:
                        // chapitre
                        try {
                            chapitre = Integer.parseInt(reste[0]);
                        } catch(NumberFormatException nfe) {
                            throw new IllegalArgumentException("Numéro incorrect ("+reste[0]+").");
                        }
                }
                
                if(chapitre > 0) {
                    courante.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre));
                    if(paragraphe > 0) {
                        Reference p = new Reference();
                        p.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.PARAGRAPHES), paragraphe));
                        courante.addSousReference(Reference.RELATION_PRECISION, p);
                        if(ligne > 0) {
                            Reference l = new Reference();
                            l.setBorne(Reference.COTE_DEBUT, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.LIGNES), ligne));
                            p.addSousReference(Reference.RELATION_PRECISION, l);
                            if(mot > 0) {
                                Reference m = new Reference();
                                m.setBorne(Reference.COTE_DEBUT, 
                                    new Coordonnee(OrdreStrict.getInstance(OrdreStrict.MOTS), mot));
                                l.addSousReference(Reference.RELATION_PRECISION, m);
                            }
                        }
                    }
                } else {
                    throw new IllegalArgumentException("Référence sans chapitre ("+intervalle[0]+").");
                }
                
            } else {
                // plage : deux parties séparées par un tiret
                
                String[] motEtReste0 = intervalle[0].split(" ");
                for(int i=0; i<motEtReste0.length; i++) {
                    motEtReste0[i] = motEtReste0[i].trim();
                }
                int chapitre0 = -1;
                int paragraphe0 = -1;
                int ligne0 = -1;
                int mot0 = -1;
                
                if(motEtReste0.length == 2) {
                    // mot
                    try {
                        mot0 = Integer.parseInt(motEtReste0[1]);
                    } catch(NumberFormatException nfe) {
                        throw new IllegalArgumentException("Numéro incorrect ("+motEtReste0[1]+").");
                    }
                }
                // ligne, paragraphe ou chapitre
                String[] reste0 = motEtReste0[0].split("\\.");
                for(int i=0; i<reste0.length; i++) {
                    reste0[i] = reste0[i].trim();
                }

                if(reste0.length > 3) {
                    throw new IllegalArgumentException("Cette référence ("+motEtReste0[0]+") "
                        + "n'a pas la structure chapitre.paragraphe.ligne.");
                }
                    
                switch(reste0.length) {
                    case 3:
                        // chapitre.paragraphe.ligne
                        try {
                            ligne0 = Integer.parseInt(reste0[2]);
                        } catch(NumberFormatException nfe) {
                            throw new IllegalArgumentException("Numéro incorrect ("+reste0[2]+").");
                        }
                    case 2:
                        // chapitre.paragraphe
                        try {
                            paragraphe0 = Integer.parseInt(reste0[1]);
                        } catch(NumberFormatException nfe) {
                            throw new IllegalArgumentException("Numéro incorrect ("+reste0[1]+").");
                        }
                    case 1:
                        // chapitre
                        try {
                            chapitre0 = Integer.parseInt(reste0[0]);
                        } catch(NumberFormatException nfe) {
                            throw new IllegalArgumentException("Numéro incorrect ("+reste0[0]+").");
                        }
                }
                
                String[] motEtReste1 = intervalle[1].split(" ");
                for(int i=0; i<motEtReste1.length; i++) {
                    motEtReste1[i] = motEtReste1[i].trim();
                }
                int chapitre1 = -1;
                int paragraphe1 = -1;
                int ligne1 = -1;
                int mot1 = -1;
                
                if(motEtReste1.length == 2) {
                    // mot
                    try {
                        mot1 = Integer.parseInt(motEtReste1[1]);
                    } catch(NumberFormatException nfe) {
                        throw new IllegalArgumentException("Numéro incorrect ("+motEtReste1[1]+").");
                    }
                }
                // ligne, paragraphe ou chapitre
                String[] reste1 = motEtReste1[0].split("\\.");
                for(int i=0; i<reste1.length; i++) {
                    reste1[i] = reste1[i].trim();
                }

                if(reste1.length > 3) {
                    throw new IllegalArgumentException("Cette référence ("+motEtReste1[0]+") "
                        + "n'a pas la structure chapitre.paragraphe.ligne.");
                }
                    
                switch(reste1.length) {
                    case 3:
                        // chapitre.paragraphe.ligne
                        try {
                            ligne1 = Integer.parseInt(reste1[2]);
                        } catch(NumberFormatException nfe) {
                            throw new IllegalArgumentException("Numéro incorrect ("+reste1[2]+").");
                        }
                    case 2:
                        // chapitre.paragraphe
                        try {
                            paragraphe1 = Integer.parseInt(reste1[1]);
                        } catch(NumberFormatException nfe) {
                            throw new IllegalArgumentException("Numéro incorrect ("+reste1[1]+").");
                        }
                    case 1:
                        // chapitre
                        try {
                            chapitre1 = Integer.parseInt(reste1[0]);
                        } catch(NumberFormatException nfe) {
                            throw new IllegalArgumentException("Numéro incorrect ("+reste1[0]+").");
                        }
                }
                
                if(chapitre0 <= 0) {
                    throw new IllegalArgumentException("Référence sans chapitre ("+intervalle[0]+").");
                }
                
                if(chapitre0 != chapitre1) {
                    // chapitres différents, et tout ce qui suit différent aussi
                    
                    // premier chapitre : de la borne de début à la fin de chapitre
                    courante.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre0));
                    if(paragraphe0 > 0) {
                        Reference p = new Reference();
                        //System.err.println("07 essai de mettre paragraphe début et fin : " + paragraphe0 + ", " + Coordonnee.FIN);
                        p.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.PARAGRAPHES), paragraphe0));
                        p.setBorne(Reference.COTE_FIN, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.PARAGRAPHES), Coordonnee.FIN));
                        courante.addSousReference(Reference.RELATION_PRECISION, p);
                        if(ligne0 > 0) {
                            Reference l = new Reference();
                            l.setBorne(Reference.COTE_DEBUT, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.LIGNES), ligne0));
                            p.addSousReference(Reference.RELATION_PRECISION, l);
                            if(mot0 > 0) {
                                Reference m = new Reference();
                                m.setBorne(Reference.COTE_DEBUT, 
                                    new Coordonnee(OrdreStrict.getInstance(OrdreStrict.MOTS), mot0));
                                l.addSousReference(Reference.RELATION_PRECISION, m);
                            }
                        }
                    }
                    
                    // chapitres au milieu
                    for(int i=chapitre0+1; i<chapitre1; i++) {
                        Reference milieu = new Reference();
                        milieu.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), i));
                        courante.addSousReference(Reference.RELATION_INCLUSION, milieu);
                    }
                    
                    // dernier chapitre : du début de chapitre à la borne de fin
                    // à chaque étape, on fait un paquet 1 - n-1, et un paquet n précisé
                    Reference fin = new Reference();
                    fin.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre1));
                    courante.addSousReference(Reference.RELATION_INCLUSION, fin);
                    if(paragraphe1 > 0) {
                        Reference pFin = new Reference();
                        if(paragraphe1 > 1) {
                            Reference p = new Reference();
                            p.setBorne(Reference.COTE_DEBUT, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.PARAGRAPHES), 1));
                            if(paragraphe1 > 2) {
                                //System.err.println("08 essai de mettre paragraphe début et fin : " + 1 + ", " + (paragraphe1 - 1));
                                p.setBorne(Reference.COTE_FIN, 
                                    new Coordonnee(OrdreStrict.getInstance(OrdreStrict.PARAGRAPHES), paragraphe1 - 1));
                            }
                            p.addSousReference(Reference.RELATION_INCLUSION, pFin);
                            fin.addSousReference(Reference.RELATION_PRECISION, p);
                        } else {
                            fin.addSousReference(Reference.RELATION_PRECISION, pFin);
                        }
                        pFin.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.PARAGRAPHES), paragraphe1));
                        
                        if(ligne1 > 0) {
                            Reference lFin = new Reference();
                            if(ligne1 > 1) {
                                Reference l = new Reference();
                                l.setBorne(Reference.COTE_DEBUT, 
                                    new Coordonnee(OrdreStrict.getInstance(OrdreStrict.LIGNES), 1));
                                if(ligne1 > 2) {
                                    //System.err.println("09 essai de mettre ligne début et fin : " + 1 + ", " + (ligne1 - 1));
                                    l.setBorne(Reference.COTE_FIN, 
                                        new Coordonnee(OrdreStrict.getInstance(OrdreStrict.LIGNES), ligne1 - 1));
                                }
                                l.addSousReference(Reference.RELATION_INCLUSION, lFin);
                                pFin.addSousReference(Reference.RELATION_PRECISION, l);
                            } else {
                                pFin.addSousReference(Reference.RELATION_PRECISION, lFin);
                            }
                            lFin.setBorne(Reference.COTE_DEBUT, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.LIGNES), ligne1));
                            
                            if(mot1 > 0) {
                                Reference mFin = new Reference();
                                mFin.setBorne(Reference.COTE_DEBUT, 
                                    new Coordonnee(OrdreStrict.getInstance(OrdreStrict.MOTS), 1));
                                if(mot1 > 1) {
                                    //System.err.println("10 essai de mettre mot début et fin : " + 1 + ", " + mot1);
                                    mFin.setBorne(Reference.COTE_FIN, 
                                        new Coordonnee(OrdreStrict.getInstance(OrdreStrict.MOTS), mot1));
                                }
                                lFin.addSousReference(Reference.RELATION_PRECISION, mFin);
                            }
                        }
                    }
                    
                } else if(paragraphe0 != paragraphe1) {
                    // chapitre commun
                    courante.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre0));
                    
                    // premier paragraphe : de la borne de début à la fin de paragraphe
                    Reference pCourant = new Reference();
                    pCourant.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.PARAGRAPHES), paragraphe0));
                    if(ligne0 > 0) {
                        Reference l = new Reference();
                        //System.err.println("11 essai de mettre ligne début et fin : " + ligne0 + ", " + Coordonnee.FIN);
                        l.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.LIGNES), ligne0));
                        l.setBorne(Reference.COTE_FIN, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.LIGNES), Coordonnee.FIN));
                        pCourant.addSousReference(Reference.RELATION_PRECISION, l);
                        if(mot0 > 0) {
                            Reference m = new Reference();
                            m.setBorne(Reference.COTE_DEBUT, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.MOTS), mot0));
                            l.addSousReference(Reference.RELATION_PRECISION, m);
                        }
                    }
                    courante.addSousReference(Reference.RELATION_PRECISION, pCourant);
                    
                    // paragraphes au milieu
                    for(int i=paragraphe0+1; i<paragraphe1; i++) {
                        Reference milieu = new Reference();
                        milieu.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.PARAGRAPHES), i));
                        pCourant.addSousReference(Reference.RELATION_INCLUSION, milieu);
                    }
                    
                    // dernier paragraphe : du début de paragraphe à la borne de fin
                    // à chaque étape, on fait un paquet 1 - n-1, et un paquet n précisé
                    Reference fin = new Reference();
                    fin.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.PARAGRAPHES), paragraphe1));
                    pCourant.addSousReference(Reference.RELATION_INCLUSION, fin);
                    if(ligne1 > 0) {
                        Reference lFin = new Reference();
                        if(ligne1 > 1) {
                            Reference l = new Reference();
                            l.setBorne(Reference.COTE_DEBUT, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.LIGNES), 1));
                            if(ligne1 > 2) {
                                //System.err.println("12 essai de mettre ligne début et fin : " + 1 + ", " + (ligne1 - 1));
                                l.setBorne(Reference.COTE_FIN, 
                                    new Coordonnee(OrdreStrict.getInstance(OrdreStrict.LIGNES), ligne1 - 1));
                            }
                            l.addSousReference(Reference.RELATION_INCLUSION, lFin);
                            fin.addSousReference(Reference.RELATION_PRECISION, l);
                        } else {
                            fin.addSousReference(Reference.RELATION_PRECISION, lFin);
                        }
                        lFin.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.LIGNES), ligne1));

                        if(mot1 > 0) {
                            Reference mFin = new Reference();
                            mFin.setBorne(Reference.COTE_DEBUT, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.MOTS), 1));
                            if(mot1 > 1) {
                                //System.err.println("13 essai de mettre mot début et fin : " + 1 + ", " + (mot1));
                                mFin.setBorne(Reference.COTE_FIN, 
                                    new Coordonnee(OrdreStrict.getInstance(OrdreStrict.MOTS), mot1));
                            }
                            lFin.addSousReference(Reference.RELATION_PRECISION, mFin);
                        }
                    }
                    
                } else if(ligne0 != ligne1) {
                    // chapitre et paragraphe communs
                    courante.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre0));
                    Reference pCourant = new Reference();
                    pCourant.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.PARAGRAPHES), paragraphe0));
                    courante.addSousReference(Reference.RELATION_PRECISION, pCourant);
                    
                    // première ligne : de la borne de début à la fin de ligne
                    Reference lCourante = new Reference();
                    lCourante.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.LIGNES), ligne0));
                    if(mot0 > 0) {
                        Reference m = new Reference();
                        //System.err.println("14 essai de mettre mot début et fin : " + mot0 + ", " + (Coordonnee.FIN));
                        m.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.MOTS), mot0));
                        m.setBorne(Reference.COTE_FIN, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.MOTS), Coordonnee.FIN));
                        lCourante.addSousReference(Reference.RELATION_PRECISION, m);
                    }
                    pCourant.addSousReference(Reference.RELATION_PRECISION, lCourante);
                    
                    // lignes au milieu
                    for(int i=ligne0+1; i<ligne1; i++) {
                        Reference milieu = new Reference();
                        milieu.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.LIGNES), i));
                        lCourante.addSousReference(Reference.RELATION_INCLUSION, milieu);
                    }
                    
                    // dernière ligne : du début de ligne à la borne de fin
                    Reference lFin = new Reference();
                    lFin.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.LIGNES), ligne1));
                    if(mot0 > 0) {
                        Reference m = new Reference();
                        //System.err.println("15 essai de mettre mot début et fin : " + 1 + ", " + (mot1));
                        m.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.MOTS), 1));
                        m.setBorne(Reference.COTE_FIN, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.MOTS), mot1));
                        lFin.addSousReference(Reference.RELATION_PRECISION, m);
                    }
                    lCourante.addSousReference(Reference.RELATION_INCLUSION, lFin);
                    
                } else if(mot0 != mot1) {
                    // chapitre, paragraphe et ligne communs
                    courante.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre0));
                    Reference pCourant = new Reference();
                    pCourant.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.PARAGRAPHES), paragraphe0));
                    courante.addSousReference(Reference.RELATION_PRECISION, pCourant);
                    Reference lCourante = new Reference();
                    lCourante.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.LIGNES), ligne0));
                    pCourant.addSousReference(Reference.RELATION_PRECISION, lCourante);
                    
                    // mots différents
                    Reference mCourant = new Reference();
                    //System.err.println("16 essai de mettre mot début et fin : " + mot0 + ", " + (mot1));
                    mCourant.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.MOTS), mot0));
                    mCourant.setBorne(Reference.COTE_FIN, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.MOTS), mot1));
                    lCourante.addSousReference(Reference.RELATION_PRECISION, mCourant);
                    
                } else {
                    // tout en commun : on ne stocke que le premier
                    courante.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.CHAPITRES), chapitre0));
                    if(paragraphe0 > 0) {
                        Reference p = new Reference();
                        p.setBorne(Reference.COTE_DEBUT, 
                            new Coordonnee(OrdreStrict.getInstance(OrdreStrict.PARAGRAPHES), paragraphe0));
                        courante.addSousReference(Reference.RELATION_PRECISION, p);
                        if(ligne0 > 0) {
                            Reference l = new Reference();
                            l.setBorne(Reference.COTE_DEBUT, 
                                new Coordonnee(OrdreStrict.getInstance(OrdreStrict.LIGNES), ligne0));
                            p.addSousReference(Reference.RELATION_PRECISION, l);
                            if(mot0 > 0) {
                                Reference m = new Reference();
                                m.setBorne(Reference.COTE_DEBUT, 
                                    new Coordonnee(OrdreStrict.getInstance(OrdreStrict.MOTS), mot0));
                                l.addSousReference(Reference.RELATION_PRECISION, m);
                            }
                        }
                    }
                }
            }
            
            references.add(courante);
        }
            
        Reference resultat = references.get(0);
        if(plages.length > 1) {
            for(int i=1; i<references.size(); i++) {
                resultat.addSousReference(Reference.RELATION_INCLUSION, references.get(i));
            }
        }
        //System.err.println(" Résultat : " + resultat.toString());
        return resultat;
    }
    
    public static String toReference(Reference debut, Reference fin, int typePassage) {
        String resultat = "";
        switch(typePassage) {
            case PassageType.PASSAGE_BIBLIQUE:
                resultat = toReferenceBiblique(debut, fin);
                break;
            case PassageType.PASSAGE_PATRISTIQUE:
                resultat = toReferencePatristique(debut, fin);
                break;
            case PassageType.PASSAGE_PHILON:
                resultat = toReferencePhilon(debut, fin);
                break;
            default:
                
        }
        return resultat;
    }
    
    private static String toReferenceBiblique(Reference debut, Reference fin) {
        String resultat = "";
        String refD = addRefBib(debut);
        String refF = addRefBib(fin);
        String ref = combineRefsBib(refD, refF);
        resultat += ref;
        return resultat;
    }
    
    private static String addRefBib(Reference aAjouter) {
        String ajout = "";
        boolean suite = false;
        OrdreStrict systeme = aAjouter.getBorne(Reference.COTE_DEBUT).getSysteme();
        if(systeme.equals(OrdreStrict.getInstance(OrdreStrict.LIVRES_BIB))) {
            ajout += aAjouter.getBorne(Reference.COTE_DEBUT).getExpression();
            suite = true;
        } else if(systeme.equals(OrdreStrict.getInstance(OrdreStrict.CHAPITRES))) {
            ajout += " " + aAjouter.getBorne(Reference.COTE_DEBUT).getExpression();
            suite = true;
        } else if(systeme.equals(OrdreStrict.getInstance(OrdreStrict.VERSETS))) {
            ajout += "." + aAjouter.getBorne(Reference.COTE_DEBUT).getExpression();
            suite = false;
        } /*else if(systeme.equals(OrdreStrict.getInstance(OrdreStrict.MOTS))) {
            ajout += " " + aAjouter.getBorne(Reference.COTE_DEBUT).getExpression();
            suite = false;
        }*/ // Les mots ne sont pas référencés dans la base d'expérience
        if(suite) {
            ajout += addRefBib(aAjouter.getSousReferences(Reference.RELATION_PRECISION)[0]);
        }
        return ajout;
    }
    
    private static String combineRefsBib(String refD, String refF) {
        String[] lD = refD.split("[ \\.]");
        String[] lF = refF.split("[ \\.]");
        String res;
        if(lD[0].equals(lF[0])) { // mêmes livres
            // on supprime la seconde occurrence du livre
            lF[0] = "";
            if(lF.length>1 && lD.length>1 && lF[1].equals(lD[1])) { // mêmes chapitres aussi
                // on supprime la seconde occurrence du chapitre
                lF[1] = "";
                if(lF.length>2 && lD.length>2 && lF[2].equals(lD[2])) { // mêmes versets aussi
                    // on supprime la seconde occurrence du verset
                    lF[2] = "";
                }
            }
        }
        if(lD.length<2) { // pas de verset pour le premier cas
            if(lD.length<1) { // pas de chapitre non plus
                lD = new String[]{lD[0], "1", "1"}; // rajout de ch1 v1
            } else {
                lD = new String[]{lD[0], lD[1], "1"}; // rajout de v1
            }
        }
        if(lF[2].isEmpty()) { // verset unique
            res = lD[0] + " " + lD[1] + "." + lD[2];
        } else if(lF[1].isEmpty()) { // seul le verset diffère
            res = lD[0] + " " + lD[1] + "." + lD[2] + "-" + lF[2];
        } else if(lF[0].isEmpty()) { // chapitre et versets diffèrent
            res = lD[0] + " " + lD[1] + "." + lD[2] + "-" + lF[1] + "." + lF[2];
        } else { // même les livres diffèrent ; impossible dans notre contexte
            res = lD[0] + " " + lD[1] + "." + lD[2] + "-" + Coordonnee.FIN + "." + Coordonnee.FIN;
            //System.err.println("   Remplacement : "+refD+"-"+refF+" -> "+res);
        }
        //System.err.println(refD+"-"+refF+" -> "+Arrays.toString(lD)+"-"+Arrays.toString(lF)+" -> "+res);
        return res;
    }
    
    private static String toReferencePatristique(Reference debut, Reference fin) {
        String resultat = "";
        String refD = addRefPat(debut);
        String refF = addRefPat(fin);
        resultat += refD;
        if(!refD.equals(refF)) {
            resultat += "-" + refF;
        }
        return resultat;
    }
    
    private static String addRefPat(Reference aAjouter) {
        String ajout = "";
        boolean suite = false;
        OrdreStrict systeme = aAjouter.getBorne(Reference.COTE_DEBUT).getSysteme();
        if(systeme.equals(OrdreStrict.getInstance(OrdreStrict.CHAPITRES))) {
            ajout += aAjouter.getBorne(Reference.COTE_DEBUT).getExpression();
            suite = true;
        } else if(systeme.equals(OrdreStrict.getInstance(OrdreStrict.PARAGRAPHES))) {
            ajout += "." + aAjouter.getBorne(Reference.COTE_DEBUT).getExpression();
            suite = true;
        } else if(systeme.equals(OrdreStrict.getInstance(OrdreStrict.LIGNES))) {
            ajout += "." + aAjouter.getBorne(Reference.COTE_DEBUT).getExpression();
            suite = true;
        } else if(systeme.equals(OrdreStrict.getInstance(OrdreStrict.MOTS))) {
            ajout += " " + aAjouter.getBorne(Reference.COTE_DEBUT).getExpression();
            suite = false;
        }
        if(suite) {
            ajout += addRefPat(aAjouter.getSousReferences(Reference.RELATION_PRECISION)[0]);
        }
        return ajout;
    }
    
    private static String toReferencePhilon(Reference debut, Reference fin) {
        String resultat = "";
        String refD = addRefPhi(debut);
        String refF = addRefPhi(fin);
        String ref = combineRefsPhi(refD, refF);
        resultat += ref;
        return resultat;
    }
    
    private static String addRefPhi(Reference aAjouter) {
        String ajout = "";
        boolean suite = false;
        OrdreStrict systeme = aAjouter.getBorne(Reference.COTE_DEBUT).getSysteme();
        if(systeme.equals(OrdreStrict.getInstance(OrdreStrict.LIVRES_PHI))) {
            ajout += aAjouter.getBorne(Reference.COTE_DEBUT).getExpression();
            suite = true;
        } else if(systeme.equals(OrdreStrict.getInstance(OrdreStrict.CHAPITRES))) {
            ajout += " " + aAjouter.getBorne(Reference.COTE_DEBUT).getExpression();
            suite = true;
        } else if(systeme.equals(OrdreStrict.getInstance(OrdreStrict.VERSETS))) {
            ajout += "." + aAjouter.getBorne(Reference.COTE_DEBUT).getExpression();
            suite = false;
        } /*else if(systeme.equals(OrdreStrict.getInstance(OrdreStrict.MOTS))) {
            ajout += " " + aAjouter.getBorne(Reference.COTE_DEBUT).getExpression();
            suite = false;
        }*/ // Les mots ne sont pas référencés dans la base d'expérience
        if(suite) {
            ajout += addRefBib(aAjouter.getSousReferences(Reference.RELATION_PRECISION)[0]);
        }
        return ajout;
    }
    
    private static String combineRefsPhi(String refD, String refF) {
        //System.err.println("A combiner : " + refD + " - " + refF);
        String[] lD = refD.split("[ \\.]");
        String[] lF = refF.split("[ \\.]");
        String res;
        if(lD[0].equals(lF[0])) { // mêmes livres
            // on supprime la seconde occurrence du livre
            lF[0] = "";
            if(lF.length>1 && lD.length>1 && lF[1].equals(lD[1])) { // mêmes chapitres aussi
                // on supprime la seconde occurrence du chapitre
                lF[1] = "";
                if(lF.length>2 && lD.length>2 && lF[2].equals(lD[2])) { // mêmes versets aussi
                    // on supprime la seconde occurrence du verset
                    lF[2] = "";
                }
            }
        }
        if(lD.length<2) { // pas de verset pour le premier cas
            if(lD.length<1) { // pas de chapitre non plus
                lD = new String[]{lD[0], "1", "1"}; // rajout de ch1 v1
            } else {
                lD = new String[]{lD[0], lD[1], "1"}; // rajout de v1
            }
        }
        if(lF[2].isEmpty()) { // verset unique
            res = lD[0] + " " + lD[1] + "." + lD[2];
        } else if(lF[1].isEmpty()) { // seul le verset diffère
            res = lD[0] + " " + lD[1] + "." + lD[2] + "-" + lF[2];
        } else if(lF[0].isEmpty()) { // chapitre et versets diffèrent
            res = lD[0] + " " + lD[1] + "." + lD[2] + "-" + lF[1] + "." + lF[2];
        } else { // même les livres diffèrent ; impossible dans notre contexte
            res = lD[0] + " " + lD[1] + "." + lD[2] + "-" + Coordonnee.FIN + "." + Coordonnee.FIN;
            //System.err.println("   Remplacement : "+refD+"-"+refF+" -> "+res);
        }
        //System.err.println(refD+"-"+refF+" -> "+Arrays.toString(lD)+"-"+Arrays.toString(lF)+" -> "+res);
        return res;
    }
    
    public static String minimiseRefs(String references, int typePassage) {
        String resultat = "";
        switch(typePassage) {
            case PassageType.PASSAGE_BIBLIQUE:
                resultat = minimiseStyleBib(references);
                break;
            case PassageType.PASSAGE_PATRISTIQUE:
                resultat = minimiseStylePatr(references);
                break;
            case PassageType.PASSAGE_PHILON:
                resultat = minimiseStylePhi(references);
                break;
            default:
                
        }
        return resultat;
    }
    
    public static String minimiseRefsFR(String references, int typePassage) {
        String resultat = "";
        switch(typePassage) {
            case PassageType.PASSAGE_BIBLIQUE:
                resultat = minimiseStyleBibFR(references);
                break;
            case PassageType.PASSAGE_PATRISTIQUE:
                resultat = minimiseStylePatr(references);
                break;
            case PassageType.PASSAGE_PHILON:
                resultat = minimiseStylePhi(references);
                break;
            default:
                
        }
        return resultat;
    }
    
    private static String minimiseStyleBib(String references) {
        if(references.isEmpty()) {
            return "référence vide";
        }
        // On considère que l'on a une référence du type 
        // livre x chapitre n verset n mot n - livre x chapitre n verset n mot n 
        // à changer en x n.n - n.n
        String[] atomes = references.split(" ");
        return atomes[1] + " " + atomes[3] + "." + atomes[5]  + 
                ((atomes[3].equalsIgnoreCase(atomes[13]) && atomes[5].equalsIgnoreCase(atomes[15])) ? "" :
                (atomes[3].equalsIgnoreCase(atomes[13])) ? ("-" + atomes[15]) : 
                (" - " + atomes[13] + "." + atomes[15])) ;
    }
    
    private static String minimiseStyleBibFR(String references) {
        if(references.isEmpty()) {
            return "référence vide";
        }
        // On considère que l'on a une référence du type 
        // livre x chapitre n verset n mot n - livre x chapitre n verset n mot n 
        // à changer en x n.n - n.n
        String[] atomes = references.split(" ");
        return ConvertisseurNomLivresBible.convertisENversFR(atomes[1]) + " " + atomes[3] + "." + atomes[5]  + 
                ((atomes[3].equalsIgnoreCase(atomes[13]) && atomes[5].equalsIgnoreCase(atomes[15])) ? "" :
                (atomes[3].equalsIgnoreCase(atomes[13])) ? ("-" + atomes[15]) : 
                (" - " + atomes[13] + "." + atomes[15])) ;
    }
    
    private static String minimiseStylePatr(String references) {
        if(references.isEmpty()) {
            return "référence vide";
        }
        // On considère que l'on a une référence du type 
        // chapitre n paragraphe n ligne n mot n - chapitre n paragraphe n ligne n mot n
        // à changer en n.n.n n - n.n.n n
        String[] atomes = references.split(" ");
        return atomes[1] + "." + atomes[3] + "." + atomes[5] + " " + atomes[7] + 
                " - " + atomes[11] + "." + atomes[13] + "." + atomes[15] + " " + atomes[17];
    }
    
    private static String minimiseStylePhi(String references) {
        if(references.isEmpty()) {
            return "référence vide";
        }
        // On considère que l'on a une référence du type 
        // livre x chapitre n verset n mot n - livre x chapitre n verset n mot n 
        // à changer en x n.n - n.n
        String[] atomes = references.split(" ");
        return atomes[1] + " ch" + atomes[3] + "." + atomes[5]  + 
                " - " + atomes[13] + "." + atomes[15] ;
    }
}

/*try {
    References.parseReferenceBiblique("Lev");
    References.parseReferenceBiblique("Gen 10");
    References.parseReferenceBiblique("Mar 10.18");
    References.parseReferenceBiblique("Luk 14.11, Luk 18.14, Mat 7.27");
    References.parseReferenceBiblique("Mar 10.17-31");
    References.parseReferenceBiblique("Mar 10.17-14.4");
    References.parseReferenceBiblique("Ezr 10-11");
    References.parseReferenceBiblique("Mar 10-12.18");
    References.parseReferenceBiblique("Mat 19.16-30, Luk 18.18-30");
    References.parseReferenceBiblique("Rom 8.14-17, Mat 12.50");
    References.parseReferenceBiblique("Luk 5.29-31, Luk 19.5-7, Mar 2.14-17, Mat 9.9-12");
} catch(Exception e) {
    System.out.println(e.getMessage());
}
try {
    References.parseReferenceBiblique("Mar 10.18-Luk 7.6");
} catch(Exception e) {
    System.out.println(e.getMessage());
}
try {
    References.parseReferenceBiblique("Mar 10.18-19-20");
} catch(Exception e) {
    System.out.println(e.getMessage());
}
try {
    References.parseReferenceBiblique("Mar 10.18.15");
} catch(Exception e) {
    System.out.println(e.getMessage());
}
try {
    References.parseReferenceBiblique("Mak 10.18");
} catch(Exception e) {
    System.out.println(e.getMessage());
}
try {
    References.parseReferenceBiblique("Mar 10.18b");
} catch(Exception e) {
    System.out.println(e.getMessage());
}*/

/*try {
    String s = "1";
    System.out.println(s+"\n"+References.parseReferencePatristique(s));
} catch(Exception e) {
    e.printStackTrace(System.out);
}
try {
    String s = "1.1";
    System.out.println(s+"\n"+References.parseReferencePatristique(s));
} catch(Exception e) {
    e.printStackTrace(System.out);
}
try {
    String s = "1.1.1";
    System.out.println(s+"\n"+References.parseReferencePatristique(s));
} catch(Exception e) {
    e.printStackTrace(System.out);
}
try {
    String s = "1.1.1 1";
    System.out.println(s+"\n"+References.parseReferencePatristique(s));
} catch(Exception e) {
    e.printStackTrace(System.out);
}
try {
    String s = "1.1.1 1 - 1.1.1 5";
    System.out.println(s+"\n"+References.parseReferencePatristique(s));
} catch(Exception e) {
    e.printStackTrace(System.out);
}
try {
    String s = "1.1.1 1 - 1.1.2 2";
    System.out.println(s+"\n"+References.parseReferencePatristique(s));
} catch(Exception e) {
    e.printStackTrace(System.out);
}
try {
    String s = "1.1.1 1 - 1.1.2 2, 5.2.2 5 - 6.1.3 2";
    System.out.println(s+"\n"+References.parseReferencePatristique(s));
} catch(Exception e) {
    e.printStackTrace(System.out);
}
try {
    String s = "1.1.1 1 - 1.1.2 2, 5.2.2 5 - 5.1.3 2";
    System.out.println(s+"\n"+References.parseReferencePatristique(s));
} catch(Exception e) {
    e.printStackTrace(System.out);
}*/