Module:Taxobox-outils

 Documentation[créer] [purger]
-- Ce module contient les fonctions traitant les différents blocs qui constituent les taxobox
-- comme par exemple la partie UICN, CITES, taxon, classification...

local tools = {}


-- "data" : module contenant les informations (listes, textes, noms
--      de catégories, nom des classifications...) associées
--      au rendu des taxobox. Contient en pratique les fonction
--      permettant d'accéder à ces informations
local data = require "Module:Taxobox-data"

-- "briques" : contient les "briques de base" Infobox, c'est-à-dire
--             les codes (wiki et/ou HTML) permettant de créer les
--             différents éléments de base d'une info/taxobox
-- Note : je présume qu'à terme il y aura un ou des modules "externes"
--        contenant les briques de base (comme il existe des briques
--        pour les infobox V2 et V3), mais en attendant...
--        Le fait de séparer tout ça dans un module séparé permettra
--        par ailleurs de simplifier les futures migrations.
local briques = require "Module:Taxobox-briques"


-- cette fonction découpe un nom (un titre) et retourne les deux parties de ce titre
-- dans une table : d'abord la partie avant le "(...)" et ensuite la partie avec les "(...)"
-- Exemple : "toto (titi)" -> { "toto", "(titi)" }
-- Note : la fonction élimine les espaces avant/après chaque partie
-- S'il n'y a pas de partie homonymie retourne { "<titre complet>", nil }
function tools.decoupe_homonymie(nom)
    -- localisation de la parenthèse ouvrante
    local pos = string.find (nom, "(", 1, true)

    -- pas de parenthèse -> on retourne tout
    if (nil == pos) then
        return {tools.nettoie(nom), nil}
    end

    -- on retourne les deux parties, en enlevant les blancs avant/après
    local p1 = tools.nettoie(string.sub (nom, 1, pos-1))
    local p2 = tools.nettoie(string.sub (nom, pos, -1))
    return {p1, p2}
end

-- cette fonction nettoie les blancs au début et à la fin du texte. Utile pour nettoyer
-- les paramètres reçus qui peuvent contenir des blancs selon la mise en forme à l'appel 
function tools.nettoie(nom)
    -- histoire de ne pas générer d'erreur
    if (nil == nom or "" == nom) then
        return nil
    end
    return string.gsub (string.gsub (nom, "^[%s]*", ""), "[%s]*$", "")
end


-- cette fonction construit la version mise en forme d'un nom scientifique
-- paramètres :
--  regne : le règne
--  rang  : le rang du taxon
--  nom   : le nom du taxon (sans formatage)
--  html  : si true la mise en forme est au format HTML et non wiki
function tools.formate_ns(regne, rang, nom, html, lien)
    -- sécurité
    if (nom == nil or nom == "") then
        return ""
    end

    -- est-ce qu'il faut mettre en italique ?
    local it = data.italiques_vf(regne, rang)
    -- si pas d'italiques aucune mise en forme nécessaire
    if (it == false) then
        if (lien == true) then
            return "[[" .. nom .. "]]"
        end
        return nom
    end

    -- italiques ouvrantes et fermantes selon le mode
    local ito
    local itf
    if (html == true) then
        ito = "<i>"
        itf = "</i>"
    else
        ito = "''"
        itf = "''"
    end

    -- on regarde s'il y a une partie homonymie
    local vnom
    local tmp = tools.decoupe_homonymie(nom)
    if (tmp[2] == nil) then
        vnom = nom -- on travaille sur l'ensemble
    else
        vnom = tmp[1] -- on travaille uniquement sur la partie effective
    end

    -- on cherche si c'est un hybride
    local pos = string.find (vnom, "×", 1, true)
    local part1  -- partie avant le x. Peut être vide
    local part2  -- partie après le x. Si vide pas de x.

    if (pos == nil) then
        part1 = vnom
        part2 = nil
    else
        -- on découpe les deux parties
        local p1 = tools.nettoie(string.match (vnom, "^(.*)×") or "")
        if (p1 == nil or p1 == "") then
            part1 = nil
        else
            part1 = p1
        end
        local p2 = tools.nettoie(string.match (vnom, "×(.*)$") or "")
        if (p2 == nil or p2 == "") then
            part2 = nil
        else
            part2 = p2
        end
    end

    -- on reconstitue la partie du nom :
    local fnom = ""
    -- première partie
    if (part1 ~= nil) then
        fnom = fnom .. ito .. part1 .. itf
    end
    -- le x si besoin (normalement c'est lié à la présence de part2)
    if (pos ~= nil) then
        if (part1 ~= nil) then
            fnom = fnom .. " ×"
        else
            fnom = fnom .. "×"
        end
    end
    -- deuxième partie
    if (part2 ~= nil) then
        fnom = fnom .. ito .. part2 .. itf
    end

    -- on ajoute la partie homonymie si présente
    if (tmp[2] ~= nil) then
        fnom = fnom .. " " .. tmp[2]
    end

    -- si on demande le lien on fait [[nom|nom-mis-en-forme]]
    -- ce n'est pas propre, mais c'est simple. À traiter plus tard
    if (lien == true) then
        fnom = "[[" .. nom .. "|" .. fnom .. "]]"
    end

    -- on retourne le résultat
    return fnom    
end


-- fonction pour tester l'existence d'un fichier
function tools.t_exists(page, conf)
    local t = mw.title.new(page)
    if (t.fileExists) then
        return true
    else
        return false
    end
end


-- fonction externe pour inclure une image
function tools.t_insert_image(image, legende, conf)

    local buf = ""

    if (image ~= nil and image ~= "") then
        buf = buf .. '[[Fichier:' .. image .. '|frameless|center|upright=1|alt='
        if (nil ~= legende and "" ~= legende) then
            buf = buf .. 'Description de cette image, également commentée ci-après'
        else
            buf = buf .. 'Description de l\'image ' .. image
        end
        buf = buf .. "]]"
    end

    return buf
end


-- insert de début d'une liste de classification. Géré par taxobox début dans les modèles.
-- Paramètres :
--   texte : le nom de la classification
function tools.t_entete_classification(texte)

    -- début de la table associée
    local result = '<table class="taxobox_classification">'
    -- le titre (nom de la classification)
    result = result .. '<caption>' .. data.classification (texte or "ndef") .. '</caption>\n'

    return result
end


-- la vraie "fin"
function tools.t_vraie_fin(conf)

    local result = ""

    -- on ferme les tables qui trainent le cas échéant
    for i = 1, conf.table_nb do
        result = result .. "</table>"
    end
    conf.table_nb = 0

    -- on valide qu'on est ouvert
    if (conf.div_nb > 0) then
        result = result .. briques.t_end()
        conf.div_nb = conf.div_nb - 1
    end

    return result
end


-- génère le début de la taxobox.
-- paramètres :
-- image : l'image à afficher, sans préfix (optionnel, nil si absent)
-- legende : la légende de l'image (optionnel, nil si absent, non affiché si pas d'image)
-- classification : la classification suivie ou nil si non précisé
-- phylo : booléen. true si ce taxon n'existe pas en classification classique.
-- titre_taxobox : le titre de la taxobox, mis en forme.
-- regne : le règne
-- article : booléen. true si on est dans l'espace des articles
-- no_cat : booléen. true si la génération des catégories est désactivée
function tools.t_debut(params, conf)

    local buf = ""

    -- faire un début si on est déjà dedans = erreur
    if (conf.div_nb > 0) then
        conf.f_erreurs("structure", "Ligne ''début'' alors que la taxobox est déjà ouverte.")
        conf.f_err_categories("Taxobox avec erreur/structure")
        return "ZZZ"
    end

    -- on crée l'entête de la taxobox
    buf = buf .. briques.t_debut(data.style(conf.regne), conf.titre_taxobox)
    conf.div_nb = conf.div_nb + 1

    -- on ajoute les catégories d'information
    conf.f_categories("Article avec taxobox-" .. conf.regne)
    if (params.image == nil or params.image == "") then
        conf.f_categories("Article à illustrer/Taxobox " .. conf.regne)
    end

    local existe
    if (params.image ~= nil and params.image ~= "") then
        existe = tools.t_exists("Media:" .. params.image, conf) -- existence de l'image
        if (not existe) then
            -- catégorie "image inexistante"
            conf.f_err_categories("Taxobox avec erreur/image")
        end
    else
        existe = false
    end

    -- si présent on ajoute l'image (si définie et si existe)
    if (params.image ~= nil and params.image ~= "" and existe) then
        -- si la cible n'existe pas, on ajoute une catégorie
        buf = buf .. tools.t_insert_image(params.image, params.legende, conf)
        if (params.legende ~= nil and params.legende ~= "") then
            buf = buf .. '<p class="legend">' .. params.legende .. '</p>\n'
        end
    end
    if (params.image ~= nil and params.image ~= "" and existe == false) then
        buf = buf .. '<p class="center">' .. "''Image inexistante''</p>"
    end

    -- entête de classification sauf si "phylo"
    if (params.phylo == nil) then
        buf = buf .. tools.t_entete_classification(params.classification)
        conf.table_nb = conf.table_nb + 1
    else
        -- message d'information
        buf = buf .. briques.t_bloc("[[File:danger.png|25px|left]]<small>Taxon inexistant en " .. data.classification(params.classification) .. "<br />Voir le texte pour plus d'information.</small>")
    end

    -- est-ce que ce règne insert automatiquement la classification "règne" ?
    sans_regne = data.premier_noregne(conf.regne)
    local l_rang
    local l_nom
    if (sans_regne == nil) then
        -- on récupère les données de ce règne
        local regne_affiche = data.premier_regne(conf.regne)
        local regne_lien = data.est_rang("règne")[2][1] -- il ne devrait jamais y avoir d'erreur
        -- classique : on affiche le règne et son lien
        if (params.phylo == nil and regne_lien ~= nil) then
            -- insertion
            buf = buf .. briques.t_ligne_mixte(regne_lien, tools.formate_ns(conf.regne, "règne", regne_affiche, false, true))
        end
    else
        -- on affiche la ligne retournée à la place
        l_rang = sans_regne[1]
        l_nom = sans_regne[2]
        local x = data.est_rang(l_rang)
        local xx = x[2][1]
        buf = buf .. briques.t_ligne_mixte(xx, tools.formate_ns(conf.regne, xx, l_nom, false, true))
    end

    return buf
end


-- génère le bandeau de début de classification phylogénique
-- image : l'image associée, optionnelle
-- classification : la classification suivie
-- div_nb, table_nb : compteurs de structure
-- regne : le règne
-- article : booléen. true si on est dans l'espace des articles
-- no_cat : booléen. true si la génération des catégories est désactivée
function tools.t_phylo_inexistant(params, conf)

    local buf = ""
    local tmp
    local classif = ""

    -- on crée le bandeau
    -- on valide la classification
    if (params.classification == nil) then
        params.classification = "ndef phylo"
    end

    classif = data.classification(params.classification)
    -- on insert : c'est juste un affichage
    buf = buf .. briques.t_bloc(classif)

    -- bloc d'information
    buf = buf .. "<p>[[File:Achtung.svg|25px|left|alt=Attention !|link=]]<small>Taxon inexistant en "
    buf = buf .. classif .. "<br/>Voir le texte pour plus d'information.</small></p>"

    -- insertion catégorie
    conf.f_categories("Taxon inexistant en " .. classification)

    return buf
end

-- génère le bandeau de début de classification phylogénique
-- image : l'image associée, optionnelle
-- classification : la classification suivie
-- div_nb, table_nb : compteurs de structure
-- regne : le règne
-- article : booléen. true si on est dans l'espace des articles
-- no_cat : booléen. true si la génération des catégories est désactivée
function tools.t_phylo_bandeau(params, conf)

    local buf = ""
    local tmp

    -- on crée le bandeau
    -- on valide la classification
    if (params.classification == nil or params.classification == "") then
        params.classification = "ndef phylo"
    end

    buf = buf .. tools.t_entete_classification(params.classification)
    conf.table_nb = conf.table_nb + 1 -- on entre dans une table

    -- si une image est présente on l'ajoute
    if (params.image ~= nil and params.image ~= "") then
        local img
        -- attention : on n'est pas sur fr: -> File et non Fichier qui n'est pas reconnu
        img = '[[File:' .. params.image .. '|thumb|center|upright=1.3|alt=Image présentant la classification phylogénique également détaillée ci-après]]'
        buf = buf .. briques.t_ligne_unique(img)
    end

    return buf
end



-- génère une entrée UICN.
-- paramètres (les 3 premiers sont les 3 paramètres du modèle) :
-- risque : le code du risque (LC, VU, EX…)
-- critere : le critère UICN associé (optionnel, nil si absent)
-- lien : en fait le champs commentaire (optionnel, nil si absent)
-- regne : le règne
-- article : booléen. true si on est dans l'espace des articles
-- no_cat : booléen. true si la génération des catégories est désactivée
function tools.t_uicn(params, conf)
    local result = ""

    if (params.risque == nil) then
        conf.f_erreurs("syntaxe", "Paramètre de risque manquant")
        conf.f_err_categories("Taxobox avec erreur/syntaxe")
        return nil
    end

    -- question : faut-il faire une entrée dans "taxobox-data" pour le texte ci-dessous ?
    result = result .. briques.t_bloc("[[Statut de conservation]] [[Union internationale pour la conservation de la nature|UICN]]")
    -- début zone
    result = result .. '<p class="center">'

   texte = data.uicn(params.risque)
   -- on ajoute l'image sauf si DD
   if (risque ~= "DD") then
       result = result .. "[[File:Status iucn3.1_" .. params.risque .. "-fr.svg|alt=Image du statut UICN " .. params.risque .. "|link=|244px]]<br />"
   end
   -- on ajoute la phrase
   result = result .. "'''" .. params.risque .. "''' "
   if (params.critere ~= nil) then
       result = result .. params.critere .. " "
   end
   result = result .. ": '''" .. texte .. "'''\n"
   if (params.lien ~= nil) then
       result = result .. "<br/>" .. params.lien
   end

    result = result .. '</p>\n'
    -- on ajoute la catégorie
    conf.f_categories("Statut UICN " .. texte)

    -- on retourne le résultat
    return result
end


-- génère une entrée CITES.
-- paramètres (les 3 premiers sont ceux du modèle) :
-- annexe : annexe CITES (I, II ou III)
-- date : date de la révision CITES (optionnel, nil si absent)
-- precision : commentaire associé (optionnel, nil si absent)
-- regne : le règne
-- article : booléen. true si on est dans l'espace des articles
-- no_cat : booléen. true si la génération des catégories est désactivée
function tools.t_cites(params, conf)

    local result = ""

    -- titre du bloc (faut-il mettre ce texte dans "data" ?)
    result = result .. briques.t_bloc("Statut [[Convention sur le commerce international des espèces de faune et de flore sauvages menacées d'extinction|CITES]]")

    -- début de la zone
    result = result .. '<p class="center">'
    if (params.annexe == nil or params.annexe == "") then
        -- erreur
        conf.f_erreurs("syntaxe", "Paramètre CITES absent.")
        conf.f_err_categories("Taxobox avec erreur/syntaxe")
        return nil
    end

    -- l'image
    result = result .. "<small>[[File:Cites "
    if (params.annexe == "I" or params.annexe == "II" or params.annexe == "III") then
        result = result .. params.annexe
    else
        -- on devrait plutôt retourner une erreur
        conf.f_erreurs("syntaxe", "Paramètre CITES invalide.")
        conf.f_err_categories("Taxobox avec erreur/syntaxe")
        return nil
    end
    result = result .. ".svg|link=|alt=Image de l'annexe " .. params.annexe .. " de la CITES|30px]] "
    -- lien
    result = result .. "[[Annexe " .. params.annexe .. " de la CITES|Annexe " .. params.annexe .. "]], "
    -- la deuxième partie
    if (date ~= "") then
        result = result .. "Rév. du " .. params.date .. "\n"
    else
        result = result .. "Date de rév. inconnue\n"
    end
    if (params.precision ~= nil) then
        result = result .. "<br/>" .. params.precision .. "\n"
    end

    -- ajout de la catégorie (si article)
    result = result .. "</small>"
    conf.f_categories("CITES annexe " .. params.annexe)

    result = result .. '</p>\n'

    return result
end


-- gère la fin de la taxobox
-- regne : le règne
-- article : booléen. true si on est dans l'espace des articles
-- no_cat : booléen. true si la génération des catégories est désactivée
function tools.t_fin(params, conf)

    local tmp = tools.t_vraie_fin(conf)

    -- le retour
    return tmp
end


-- gère une entrée rang (ligne de classification)
-- paramètres :
-- rang : le rang de la ligne
-- nom : le nom du taxon associé à ce rang
-- lien : la cible réelle si différente de nom (optionnel, nil si absent)
function tools.t_rang(params, conf)

    local buf = ""

    if (params.rang == nil or params.nom == nil) then
        conf.f_erreurs("syntaxe", "Paramètre de ''rang'' ou ''nom'' absent.")
        conf.f_err_categories("Taxobox avec erreur/syntaxe")
        return nil
    end

    -- nom du rang
    local cible
    if (params.lien == nil) then
        cible = tools.formate_ns(conf.regne, params.rang, params.nom, false, true)
    else
        cible = tools.formate_ns(conf.regne, params.rang, params.lien, false, false)
        cible = "[[" .. params.nom .. "|" .. cible .. "]]"
    end

    local rg = data.est_rang(params.rang)
    if (rg == nil or rg[1] == 0) then
        -- ce n'est pas un rang valide
        conf.f_erreurs("syntaxe", "Rang attendu, ''" .. params.rang .. "'' trouvé à la place.")
        conf.f_err_categories("Taxobox avec erreur/syntaxe")
        return nil -- on ne retourne rien, on ignore la ligne
    end
    -- si ancien, on raye le tout
    if (params.ancien == true) then
        buf = buf .. briques.t_ligne_mixte("<s>" .. rg[2][1] .. "</s>", "<s>" .. cible .. "</s>")
    else
        buf = buf .. briques.t_ligne_mixte(rg[2][1], cible)
    end

    return buf
end

-- entrée du taxon (taxobox taxon)
function tools.t_taxon(params, conf)

    local buf = ""

    if (params.rang == nil or params.nom == nil) then
        conf.f_erreurs("syntaxe", "Paramètre de ''rang'' ou ''nom'' absent.")
        conf.f_err_categories("Taxobox avec erreur/syntaxe")
        return nil
    end

    -- on insert l'entrée
    local bla = data.est_rang(params.rang)
    -- pas un rang valide ?
    if (bla[1] == 0) then
        conf.f_erreurs("syntaxe", "Rang invalide dans ''taxon'' (" .. params.rang .. ").")
        conf.f_err_categories("Taxobox avec erreur/syntaxe")
        return nil -- on ignore la ligne
    end

    local tt
    if (params.rang == "espèce" and conf.regne == "virus") then
        -- cas spécial. Ceci peut sans doute être amélioré en faisant une table qui dépend du règne, mais comme il n'y a semble-t-il que cette
        -- exception ça m'a paru plus simple de l'introduire dans le code plutôt que dans les données. À discuter.
        tt = '[[Espèce]]'
    else
        tt = bla[2][1]
    end
    buf = buf .. briques.t_bloc(tt)

    -- le taxon lui-même (génération HTML à placer dans une fonction à part)
    buf = buf .. '<p class="center">'
    if (params.obsolete ~= nil) then
        buf = buf .. '<s><b>' .. tools.formate_ns(conf.regne, params.rang, params.nom, false, false) .. '</b><br/>'
    else
        buf = buf .. '<b>' .. tools.formate_ns(conf.regne, params.rang, params.nom, false, false) .. '</b><br/>'
    end
    if (params.sans_auteur ~= true) then -- option "sans auteur" permet de ne rien afficher (même pas auteur manquant)
        buf = buf .. '<small><b>'
        -- ici il faut ajouter  l'appel au modèle auteur inconnu (ou autre) et l'insertion des catégories idoines.
        if (params.auteur == "" or params.auteur == nil) then
            buf = buf .. data.auteur_t_manquant(regne) .. ", " .. data.date_t_manquante(regne)
            -- on ajoute les catégories
            conf.f_categories(data.auteur_z_manquant(regne))
            conf.f_categories(data.date_z_manquante(regne))
        else
            buf = buf .. params.auteur
        end
        buf = buf .. "</b></small>\n"
    end

    if (params.obsolete ~= nil) then
        buf = buf .. "</s> (obsolète)"
        -- on ajoute le nouveau nom
        if (params.obsolete ~= "") then
            buf = buf .. "<br/><b>" .. tools.formate_ns(conf.regne, params.rang, params.obsolete, false, false) .. "</b>"
        end
    end
    buf = buf .. '</p>\n'

    return buf
end



-- génère la position phylogénique
-- Paramètres :
--   arbre : l'arbre phylo (une liste à puce en général)
--   frere : (optionnel) le groupe frère
function tools.t_position(params, conf)

    local buf = ""

    if (params.arbre == nil or params.arbre == "") then
        conf.f_erreurs("syntaxe", "Paramètre manquant.")
        conf.f_err_categories("Taxobox avec erreur/syntaxe")
        return nil
    end

    -- bloc de "sous-titre"
    local buf = briques.t_bloc("[[Classification phylogénétique|Position phylogénétique]]")

    -- si ça ne commence pas par "\n" on l'ajoute (sinon les puces ne "démarrent" pas)
    buf = buf .. '<p>\n' .. params.arbre .. '</p>\n'

    -- groupe frère si présent
    if (params.frere ~= nil and params.frere ~= "") then
        -- peut-on faire la mise en forme du "frère" automatiquement ?
        buf = buf .. '<p>\n[[Groupe frère]] : [[' .. params.frere .. ']]</p>\n'
    end

    return buf
end


-- génère la liste des synonymes. Similaire à "Taxobox synonymes".
-- Paramètres :
--   texte : le texte à afficher (en général une liste à puce).
function tools.t_synonymes(params, conf)

    local buf = ""

    if (params.synonymes == "" or params.synonymes == nil) then
        conf.f_erreurs("syntaxe", "Paramètre manquant.")
        conf.f_err_categories("Taxobox avec erreur/syntaxe")
        return nil
    end

    -- bloc de "sous-titre"
    local buf = briques.t_bloc("[[Synonyme (taxinomie)|Synonymes]]")

    -- si ça ne commence pas par "\n" on l'ajoute (sinon les puces ne "démarrent" pas)
    buf = buf .. '<p>\n' .. params.synonymes .. '</p>\n'

    return buf
end

-- génère la liste des taxons de rang inférieur. Similaire à "Taxobox taxons".
-- Paramètres :
--   texte : le texte à afficher (en général une liste à puce).
function tools.t_taxons(params, conf)

    local buf = ""

    -- bloc de "sous-titre"
    if (params.texte2 == nil or params.texte2 == "") then
        buf = briques.t_bloc("Taxons de rang inférieur")
    else
        buf = briques.t_bloc(params.texte .. " de rang inférieur")
    end

    -- si ça ne commence pas par "\n" on l'ajoute (sinon les puces ne "démarrent" pas)
    if (params.texte2 == nil or params.texte2 == "") then
        if (params.texte == nil or params.texte == "") then
            -- texte par défaut
            buf = buf .. "<p>\n* Voir texte\n</p>\n"
        else
            buf = buf .. '<p>\n' .. params.texte .. '</p>\n'
        end
    else
        buf = buf .. '<p>\n' .. params.texte2 .. '</p>\n'
    end

    return buf
end


-- affiche une image et sa légende, avec un éventuel séparateur avant
-- Paramètres :
--   image : l'image à afficher
--   legende : la légende (optionnelle)
--   separateur : booléen. Si vrai un séparateur est affiché avant l'image
function tools.t_image(params, conf)

    local buf = ""

    if (params.image == nil or params.image == "") then
        conf.f_erreurs("syntaxe", "Pas d'image fournie.")
        conf.f_err_categories("Taxobox avec erreur/syntaxe")
        return nil -- on ignore la ligne
    end

    -- si demandé séparateur
    if (params.separateur == true) then
        buf = buf .. '<div class="hr" style="height: 2px;"></div>\n'
    end

    buf = buf .. '[[File:' .. params.image .. '|thumb|center|upright=1.3|alt='
    if (nil ~= params.legende and "" ~= params.legende) then
        buf = buf .. 'Description de cette image, également commentée ci-après'
    else
        buf = buf .. 'Description de l\'image ' .. params.image
    end
    buf = buf .. "]]"
    if (params.legende ~= nil and params.legende ~= "") then
        buf = buf .. '<p class="legend">' .. params.legende .. '</p>\n'
    end

    return buf
end


-- affiche une image et sa légende, avec un éventuel séparateur avant
-- Paramètres :
--   image : l'image à afficher (répartition)
--   legende : la légende (optionnelle)
--   taille : la taille de l'image (utilisé ?)
--   separateur : booléen. Si vrai un séparateur est affiché avant l'image
function tools.t_repartition(params, conf)

    local buf = ""

    if (params.image == nil or params.image == "") then
        conf.f_erreurs("syntaxe", "Pas d'image fournie.")
        conf.f_err_categories("Taxobox avec erreur/syntaxe")
        return nil -- on ignore la ligne
    end

    -- si demandé séparateur
    if (params.separateur == true) then
        buf = buf .. '<div class="hr" style="height: 2px;"></div>\n'
    end

    -- entête
    buf = buf .. briques.t_bloc("[[Aire de répartition]]")

    buf = buf .. '[[File:' .. params.image .. '|thumb|center|upright='
    if (params.taille ~= nil and params.taille ~= "") then
        buf = buf .. params.taille .. '|alt='
    else
        buf = buf .. '1.3|alt='
    end
    if (nil ~= params.legende and "" ~= params.legende) then
        buf = buf .. 'Description de cette image, également commentée ci-après'
    else
        buf = buf .. 'Description de l\'image ' .. params.image
    end
    buf = buf .. "]]"
    if (params.legende ~= nil and params.legende ~= "") then
        buf = buf .. '<p class="legend">' .. params.legende .. '</p>\n'
    end

    return buf
end


-- affiche seulement une légende.
-- paramètres :
--  legende : la légende à afficher
function tools.t_legende(params, conf)

    local buf = ""

    if (params.legende == nil or params.legende == "") then
        conf.f_erreurs("syntaxe", "Pas de légende fournie.")
        conf.f_err_categories("Taxobox avec erreur/syntaxe")
        return nil -- on ignore la ligne
    end

    buf = buf .. '<p class="legend">' .. params.legende .. '</p>\n'

    return buf
end

-- affiche seulement une légende.
-- paramètres :
--  legende : la légende à afficher
function tools.t_repartition_legende(params, conf)

    local buf = ""

    if (params.legende == nil or params.legende == "" or params.couleur == nil or params.couleur == "") then
        conf.f_erreurs("syntaxe", "Pas de légende fournie.")
        conf.f_err_categories("Taxobox avec erreur/syntaxe")
        return nil -- on ignore la ligne
    end

    buf = buf .. '<p class="legend" style="text-align:left">'
    buf = buf .. '<small>&nbsp;&nbsp;&nbsp;<span style="background: #' .. params.couleur .. '">'
    buf = buf .. "'''&nbsp;&nbsp;<font color=\"#"
    if (params.couleur2 == nil or params.couleur2 == "") then
        buf = buf .. params.couleur .. '">/</font>&nbsp;&nbsp;'
    else
        buf = buf .. params.couleur2 .. '">/</font>&nbsp;&nbsp;'
    end
    buf = buf .. "'''</span>&nbsp;" .. params.legende .. "</small></small><br /></p>"

    return buf
end


-- fonction utilisée par la suivante. Prend 1 ou plusieurs codes de site de références
-- (séparé par des espaces et/ou des "&") et retourne la liste des liens correspondant
-- ou les éléments sans rien s'ils n'existent pas
function tools.mutlisite(noms)
    local tbl = {}
    local res = ""
    local pos

    -- on nettoie les éléments de séparation
    local tmp = string.gsub(tools.nettoie(noms), "[ &]+", " ")

    -- on parcours les mots
    for mot in string.gmatch(tmp, "%S+") do
        -- on insert, soit en lien soit directement
        table.insert(tbl, data.ref_sites(mot) or mot)
    end

    -- si un seul on retourne
    if (tbl[2] == nil) then
        return tbl[1]
    end
    -- sinon on construit la "phrase"
    pos = 1
    while (tbl[pos] ~= nil) do
        if (pos == 1) then
            res = res .. tbl[pos]
        else
            if (tbl[pos+1] == nil) then -- le dernier
                res = res .. " & " .. tbl[pos]
            else
                res = res .. ", " .. tbl[pos]
            end
        end
        pos = pos + 1
    end
    return res
end


-- affiche un rang conflit
-- paramètres :
--  rang : le rang du taxon
--  nom1 : le nom du taxon
--  site1 : le site qui présente ce nom
--  nom2 : le nom du taxon numéro 2 (optionnel)
--  site2 : le site qui présente ce nom
--  nom3 : le nom du taxon numéro 3 (optionnel)
--  site3 : le site qui présente ce nom
function tools.t_conflit(params, conf)

    local buf = ""

    if (params.rang == nil or params.nom1 == nil or params.site1 == nil) then
        conf.f_erreurs("syntaxe", "Paramètre(s) manquant(s).")
        conf.f_err_categories("Taxobox avec erreur/syntaxe")
        return nil
    end

    local rg = data.est_rang(params.rang)
    if (rg == nil or rg[1] == 0) then
        -- ce n'est pas un rang valide
        conf.f_erreurs("syntaxe", "Rang attendu, ''" .. params.rang .. "'' trouvé à la place.")
        conf.f_err_categories("Taxobox avec erreur/syntaxe")
        return nil -- on ne retourne rien, on ignore la ligne
    end

    -- nom du rang
    local cible = ""
    if (params.nom1 ~= nil) then
        cible = cible .. tools.formate_ns(conf.regne, params.rang, params.nom1, false, true)  .. "<small> selon "
        if (params.site1 == nil) then
            cible = cible .. data.ref_sites("?") .. "</small>"
        else
            cible = cible .. tools.mutlisite(params.site1) .. "</small>"
        end
    end
    if (params.nom2 ~= nil) then
        cible = cible .. "<br/>" .. tools.formate_ns(conf.regne, params.rang, params.nom2, false, true) .. "<small> selon "
        if (params.site2 == nil) then
            cible = cible .. data.ref_sites("?") .. "</small>"
        else
            cible = cible .. tools.mutlisite(params.site2) .. "</small>"
        end
    end
    if (params.nom3 ~= nil) then
        cible = cible .. "<br/>" .. tools.formate_ns(conf.regne, params.rang, params.nom3, false, true) .. "<small> selon "
        if (params.site3 == nil) then
            cible = cible .. data.ref_sites("?") .. "</small>"
        else
            cible = cible .. tools.mutlisite(params.site3) .. "</small>"
        end
    end

    buf = buf .. briques.t_ligne_mixte(rg[2][1], cible)

    return buf
end


-- table classée par tag des entrées (pas utilisé actuellement)
-- format du retour : comportement-sur-erreur-de-syntaxe, table de la syntaxe
-- comportement-sur... : que faire si la ligne lue est invalide :
--  0 : ignorer la ligne sans générer d'erreur
--  1 : ignorer la ligne en génerant une erreur
--  2 : rendre le problème fatal
tools.d_syntaxe = {}
tools.d_syntaxe["début"] = { 2, data.df_debut, tools.t_debut }
tools.d_syntaxe["fin"] = { 1, data.df_fin, tools.t_fin }
tools.d_syntaxe["rang"] = { 1, data.df_rang, tools.t_rang }
tools.d_syntaxe["conflit"] = { 1, data.df_conflit, tools.t_conflit }
tools.d_syntaxe["taxon"] = { 1, data.df_taxon, tools.t_taxon }
tools.d_syntaxe["taxons"] = { 1, data.df_taxons, tools.t_taxons }
tools.d_syntaxe["uicn"] = { 1, data.df_uicn, tools.t_uicn }
tools.d_syntaxe["cites"] = { 1, data.df_cites, tools.t_cites }
tools.d_syntaxe["synonymes"] = { 1, data.df_synonymes, tools.t_synonymes }
tools.d_syntaxe["parents"] = { 1, data.df_parents, tools.t_parents }
tools.d_syntaxe["image"] = { 1, data.df_image, tools.t_image }
tools.d_syntaxe["répartition"] = { 1, data.df_repartition, tools.t_repartition }
tools.d_syntaxe["répartition légende"] = { 1, data.df_repartition_legende, tools.t_repartition_legende }
tools.d_syntaxe["légende"] = { 1, data.df_legende, tools.t_legende }
tools.d_syntaxe["phylogénie bandeau"] = { 2, data.df_phylo_bandeau, tools.t_phylo_bandeau }
tools.d_syntaxe["phylogénie inexistant"] = { 1, data.df_phylo_inexistant, tools.t_phylo_inexistant }
tools.d_syntaxe["position"] = { 1, data.df_position, tools.t_position }
-- il manque : "phylogénie arbre", "répartition début", "répartition image", "répartition fin"
-- toutefois : il est probable que répartition début/fin n'aient plus de raison d'exister (les laisser pour compatiblité ?),
--             et que répartition image soit identique à image (à valider).
-- Note : il est probable également que légende soit identique à répartition légende (à valider).
-- Si c'est le cas : prévoir dans la gestion → plusieurs mot-clés pour une même action + info d'obsolescence de certaines entrées
-- retourne le format de la ligne demandée (si ne fait rien : fonction "nil" ?)
function tools.syntaxe_ligne(cle)
    if (cle == nil or cle == "") then
        return nil
    end
    return tools.d_syntaxe[cle]
end

return tools