/* BdfServer_DirectoryStorage - Copyright (c) 2014-2025 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package fr.exemole.bdfserver.storage.directory.oldversions;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import net.fichotheque.Fichotheque;
import net.fichotheque.SubsetKey;
import net.fichotheque.corpus.fiche.AttConsumer;
import net.fichotheque.corpus.fiche.Cdatadiv;
import net.fichotheque.corpus.fiche.Code;
import net.fichotheque.corpus.fiche.EmailItem;
import net.fichotheque.corpus.fiche.DateItem;
import net.fichotheque.corpus.fiche.Div;
import net.fichotheque.corpus.fiche.Fiche;
import net.fichotheque.corpus.fiche.FicheBlock;
import net.fichotheque.corpus.fiche.FicheBlocks;
import net.fichotheque.corpus.fiche.FicheItem;
import net.fichotheque.corpus.fiche.FicheItems;
import net.fichotheque.corpus.fiche.GeopointItem;
import net.fichotheque.corpus.fiche.H;
import net.fichotheque.corpus.fiche.ImageItem;
import net.fichotheque.corpus.fiche.Insert;
import net.fichotheque.corpus.fiche.Item;
import net.fichotheque.corpus.fiche.LanguageItem;
import net.fichotheque.corpus.fiche.Li;
import net.fichotheque.corpus.fiche.LinkItem;
import net.fichotheque.corpus.fiche.Ln;
import net.fichotheque.corpus.fiche.AmountItem;
import net.fichotheque.corpus.fiche.NumberItem;
import net.fichotheque.corpus.fiche.P;
import net.fichotheque.corpus.fiche.ParaItem;
import net.fichotheque.corpus.fiche.ParagraphBlock;
import net.fichotheque.corpus.fiche.CountryItem;
import net.fichotheque.corpus.fiche.PersonItem;
import net.fichotheque.corpus.fiche.S;
import net.fichotheque.corpus.fiche.Table;
import net.fichotheque.corpus.fiche.Td;
import net.fichotheque.corpus.fiche.TextContentBuilder;
import net.fichotheque.corpus.fiche.Tr;
import net.fichotheque.corpus.fiche.Ul;
import net.fichotheque.corpus.fiche.ZoneBlock;
import net.fichotheque.corpus.metadata.FieldKey;
import net.fichotheque.sphere.Redacteur;
import net.fichotheque.sphere.Sphere;
import net.fichotheque.utils.FicheUtils;
import net.mapeadores.util.html.HtmlCleaner;
import net.mapeadores.util.localisation.Country;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.models.EmailCore;
import net.mapeadores.util.models.EmailCoreUtils;
import net.mapeadores.util.models.PersonCore;
import net.mapeadores.util.models.PersonCoreUtils;
import net.mapeadores.util.money.ExtendedCurrency;
import net.mapeadores.util.primitives.Decimal;
import net.mapeadores.util.primitives.DegreDecimal;
import net.mapeadores.util.date.FuzzyDate;
import net.mapeadores.util.text.StringUtils;
import net.mapeadores.util.xml.DOMUtils;
import net.mapeadores.util.xml.XMLUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;


/**
 *
 * @author Vincent Calame
 */
public class OldFicheDOMReader {

    private final Fichotheque fichotheque;
    private final HtmlCleaner htmlCleaner;
    private Fiche currentFiche;
    private boolean allowFlat = false;
    private final RootConsumer rootConsumer = new RootConsumer();
    private final EnteteConsumer enteteConsumer = new EnteteConsumer();
    private boolean append = true;
    private final CorpsdeficheConsumer corpsdeficheConsumer = new CorpsdeficheConsumer();

    public OldFicheDOMReader(Fichotheque fichotheque, HtmlCleaner htmlCleaner) {
        this.fichotheque = fichotheque;
        this.htmlCleaner = htmlCleaner;
    }

    public void setAllowFlat(boolean allowFlat) {
        this.allowFlat = allowFlat;
    }

    public void setAppend(boolean append) {
        this.append = append;
    }

    public Fiche readFiche(Element element) {
        Fiche fiche = new Fiche();
        try {
            Lang lang = Lang.parse(element.getAttribute("xml:lang"));
            fiche.setLang(lang);
        } catch (ParseException pe) {
        }
        readFiche(fiche, element);
        return fiche;
    }

    public void readFiche(Fiche fiche, Element element) {
        this.currentFiche = fiche;
        DOMUtils.readChildren(element, rootConsumer);
    }


    private class RootConsumer implements Consumer<Element> {

        private RootConsumer() {

        }

        @Override
        public void accept(Element element) {
            String tagName = element.getTagName();
            if (tagName.equals("entete")) {
                DOMUtils.readChildren(element, enteteConsumer);
            } else if (tagName.equals("corpsdefiche")) {
                DOMUtils.readChildren(element, corpsdeficheConsumer);
            } else if (tagName.equals("source")) {
                DOMUtils.readChildren(element, enteteConsumer);
            } else {
                if (allowFlat) {
                    boolean isEnteteElement = enteteConsumer.readEnteteElement(element);
                    if (!isEnteteElement) {
                        corpsdeficheConsumer.readCorpsdeficheElement(element);
                    }
                }
            }
        }

    }


    private class EnteteConsumer implements Consumer<Element> {

        private EnteteConsumer() {

        }

        @Override
        public void accept(Element element) {
            readEnteteElement(element);
        }

        private boolean readEnteteElement(Element el) {
            switch (el.getTagName()) {
                case "title":
                case "titre":
                    currentFiche.setTitle(XMLUtils.getData(el));
                    return true;
                case "subtitle":
                case "soustitre":
                    currentFiche.setSubtitle(readPara(el));
                    return true;
                case "prop":
                case "propriete":
                    readProp(currentFiche, el);
                    return true;
                case "info":
                case "information":
                    readInfo(currentFiche, el);
                    return true;
                case "owners":
                case "redacteurs":
                    readOwners(currentFiche, el);
                    return true;
            }
            return false;
        }

    }


    private class CorpsdeficheConsumer implements Consumer<Element> {

        private CorpsdeficheConsumer() {

        }

        @Override
        public void accept(Element element) {
            readCorpsdeficheElement(element);
        }

        private boolean readCorpsdeficheElement(Element el) {
            String tagname = el.getTagName();
            if (tagname.equals("texte")) {
                FieldKey fieldKey = FieldKey.build(FieldKey.SECTION_CATEGORY, "texte");
                List<FicheBlock> list = readFicheBlockList(el);
                FicheBlocks ficheBlocks = FicheUtils.toFicheBlocks(list);
                if (append) {
                    currentFiche.appendSection(fieldKey, ficheBlocks);
                } else {
                    currentFiche.setSection(fieldKey, ficheBlocks);
                }
                return true;
            } else if ((tagname.equals("section")) || (tagname.equals("annexe"))) {
                readSection(currentFiche, el);
                return true;
            }
            return false;
        }

    }

    public void readProp(Fiche fiche, Element element) {
        String type = element.getAttribute("type");
        if (type.length() == 0) {
            return;
        }
        FieldKey fieldKey;
        try {
            fieldKey = FieldKey.parse(FieldKey.PROP_CATEGORY, type);
        } catch (ParseException pe) {
            return;
        }
        FicheItem ficheItem = null;
        NodeList liste = element.getChildNodes();
        for (int j = 0; j < liste.getLength(); j++) {
            if (liste.item(j).getNodeType() == Node.ELEMENT_NODE) {
                Element el = (Element) liste.item(j);
                ficheItem = readFicheItem(el);
                break;
            }
        }
        fiche.setProp(fieldKey, ficheItem);
    }

    public void readInfo(Fiche fiche, Element element) {
        String type = element.getAttribute("type");
        if (type.length() == 0) {
            return;
        }
        FieldKey fieldKey;
        try {
            fieldKey = FieldKey.parse(FieldKey.INFO_CATEGORY, type);
        } catch (ParseException pe) {
            return;
        }
        FicheItems ficheItems = readFicheItems(element);
        if (append) {
            fiche.appendInfo(fieldKey, ficheItems);
        } else {
            fiche.setInfo(fieldKey, ficheItems);
        }
    }

    public void readOwners(Fiche fiche, Element element) {
        FicheItems ficheItems = readFicheItems(element);
        if (append) {
            fiche.appendOwners(ficheItems);
        } else {
            fiche.setOwners(ficheItems);
        }
    }

    public FicheItem readFicheItem(Element element) {
        FicheItem ficheItem = null;
        String tagname = element.getTagName();
        if (tagname.equals("item")) {
            String value = XMLUtils.getData(element);
            if (value.length() == 0) {
                return null;
            } else {
                return new Item(value);
            }
        }
        if (tagname.equals("personne")) {
            ficheItem = readPerson(element);
        } else if (tagname.equals("langue")) {
            ficheItem = readLanguage(element);
        } else if (tagname.equals("pays")) {
            ficheItem = readCountry(element);
        } else if (tagname.equals("datation")) {
            ficheItem = readDate(element);
        } else if (tagname.equals("link")) {
            ficheItem = readLink(element);
        } else if (tagname.equals("courriel")) {
            ficheItem = readEmail(element);
        } else if (tagname.equals("entite")) {
            ficheItem = readEntite(element);
        } else if (tagname.equals("biblio")) {
            ficheItem = readBiblio(element);
        } else if (tagname.equals("montant")) {
            ficheItem = readAmount(element);
        } else if (tagname.equals("nombre")) {
            ficheItem = readNumber(element);
        } else if (tagname.equals("geopoint")) {
            ficheItem = readGeopoint(element);
        } else if (tagname.equals("para")) {
            ficheItem = readPara(element);
        } else if (tagname.equals("image")) {
            ficheItem = readImage(element);
        }
        return ficheItem;
    }

    private FicheItem readRedacteur(String sphereString, String login) {
        try {
            SubsetKey subsetKey = SubsetKey.parse(SubsetKey.CATEGORY_SPHERE, sphereString);
            Sphere sphere = (Sphere) fichotheque.getSubset(subsetKey);
            if (sphere != null) {
                try {
                    Redacteur redacteur = sphere.getRedacteurByLogin(login);
                    if (redacteur != null) {
                        return new PersonItem(redacteur.getGlobalId());
                    }
                } catch (NumberFormatException nfe) {
                }
            }
        } catch (ParseException pe) {
        }
        return new Item(login + "[" + sphereString + "]");
    }

    public FicheItem readPerson(Element element_xml) {
        String login = element_xml.getAttribute("idsphere");
        String sphereString = element_xml.getAttribute("sphere");
        if ((sphereString.length() != 0) && (login.length() != 0)) {
            return readRedacteur(sphereString, login);
        }
        String nom = "";
        String prenom = "";
        String organisme = "";
        String original = "";
        NodeList liste = element_xml.getChildNodes();
        boolean nomAvant = false;
        for (int i = 0; i < liste.getLength(); i++) {
            if (liste.item(i).getNodeType() == Node.ELEMENT_NODE) {
                Element el = (Element) liste.item(i);
                String tagname = el.getTagName();
                if (tagname.equals("nom")) {
                    nom = XMLUtils.getData(el);
                    String avantString = el.getAttribute("avant");
                    if (avantString.equals("true")) {
                        nomAvant = true;
                    }
                    //deprecié
                    String strg_style = el.getAttribute("style");
                    if (strg_style.equals("zh") || strg_style.equals("zh-latin")) {
                        nomAvant = true;
                    }
                } else if (tagname.equals("prenom")) {
                    prenom = XMLUtils.getData(el);
                } else if (tagname.equals("original")) {
                    original = XMLUtils.getData(el);
                } else if (tagname.equals("organisme")) {
                    organisme = XMLUtils.getData(el);
                }
            }
        }
        PersonCore personCore = PersonCoreUtils.toPersonCore(nom, prenom, original, nomAvant);
        return new PersonItem(personCore, organisme);
    }

    public LanguageItem readLanguage(Element element_xml) {
        String strg_intlang = element_xml.getAttribute("lang");
        try {
            Lang lang = Lang.parse(strg_intlang);
            return new LanguageItem(lang);
        } catch (ParseException mcle) {
            return null;
        }
    }

    public CountryItem readCountry(Element element_xml) {
        try {
            Country country = Country.parse(element_xml.getAttribute("country"));
            return new CountryItem(country);
        } catch (ParseException pe) {
            return null;
        }
    }

    public NumberItem readNumber(Element element_xml) {
        String valString = element_xml.getAttribute("val");
        try {
            Decimal decimal = StringUtils.parseStrictDecimal(valString);
            return new NumberItem(decimal);
        } catch (NumberFormatException nfe) {
            return null;
        }
    }

    public GeopointItem readGeopoint(Element element_xml) {
        String latitudeString = element_xml.getAttribute("lat");
        String longitudeString = element_xml.getAttribute("lon");
        if (longitudeString.length() == 0) {
            longitudeString = element_xml.getAttribute("long"); //Ancienne version avant 0.9.8.7-beta07
        }
        try {
            Decimal latitude = StringUtils.parseStrictDecimal(latitudeString);
            Decimal longitude = StringUtils.parseStrictDecimal(longitudeString);
            return new GeopointItem(DegreDecimal.newInstance(latitude), DegreDecimal.newInstance(longitude));
        } catch (NumberFormatException nfe) {
            return null;
        }
    }

    public ParaItem readPara(Element element_xml) {
        ParaItem.Builder builder = new ParaItem.Builder();
        readContentList(builder, element_xml);
        return builder.toParaItem();
    }

    public AmountItem readAmount(Element element_xml) {
        String valString = element_xml.getAttribute("val");
        String curString = element_xml.getAttribute("cur");
        try {
            Decimal decimal = StringUtils.parseStrictDecimal(valString);
            ExtendedCurrency currency = ExtendedCurrency.parse(curString);
            return new AmountItem(decimal, currency);
        } catch (NumberFormatException | ParseException e) {
            return null;
        }
    }

    public DateItem readDate(Element element_xml) {
        String type = element_xml.getAttribute("type");
        String a = element_xml.getAttribute("a");
        String s = element_xml.getAttribute("s");
        String t = element_xml.getAttribute("t");
        String m = element_xml.getAttribute("m");
        String j = element_xml.getAttribute("j");
        FuzzyDate date;
        try {
            int annee = Integer.parseInt(a);
            if (type.equals("s")) {
                int semestre = Integer.parseInt(s);
                date = FuzzyDate.fromHalfYear(annee, semestre);
            } else if (type.equals("t")) {
                int trimestre = Integer.parseInt(t);
                date = FuzzyDate.fromQuarter(annee, trimestre);
            } else if (type.equals("m")) {
                int mois = Integer.parseInt(m);
                date = FuzzyDate.fromMonth(annee, mois);
            } else if (type.equals("j")) {
                int mois = Integer.parseInt(m);
                int jour = Integer.parseInt(j);
                date = FuzzyDate.fromDay(annee, mois, jour);
            } else {
                date = FuzzyDate.fromYear(annee);
            }
        } catch (IllegalArgumentException e) {
            return null;
        }
        return new DateItem(date);
    }

    public LinkItem readLink(Element element_xml) {
        String href = element_xml.getAttribute("href");
        String title = "";
        String comment = "";
        NodeList liste = element_xml.getChildNodes();
        for (int i = 0; i < liste.getLength(); i++) {
            if (liste.item(i).getNodeType() == Node.ELEMENT_NODE) {
                Element element = (Element) liste.item(i);
                String tagname = element.getTagName();
                if (tagname.equals("title")) {
                    title = XMLUtils.getData(element);
                } else if (tagname.equals("comment")) {
                    comment = XMLUtils.getData(element);
                }
            }
        }
        return new LinkItem(href, title, comment);
    }

    public ImageItem readImage(Element element_xml) {
        String src = element_xml.getAttribute("src");
        String alt = "";
        String title = "";
        NodeList liste = element_xml.getChildNodes();
        for (int i = 0; i < liste.getLength(); i++) {
            if (liste.item(i).getNodeType() == Node.ELEMENT_NODE) {
                Element element = (Element) liste.item(i);
                String tagname = element.getTagName();
                if (tagname.equals("alt")) {
                    alt = XMLUtils.getData(element);
                } else if (tagname.equals("title")) {
                    title = XMLUtils.getData(element);
                }
            }
        }
        return new ImageItem(src, alt, title);
    }

    public EmailItem readEmail(Element element_xml) {
        String addrSpec = element_xml.getAttribute("addr-spec");
        String realName = element_xml.getAttribute("real-name");
        if (realName.length() == 0) {
            String strg = XMLUtils.getData(element_xml);
            if (strg.length() > 0) {
                try {
                    EmailCore c2 = EmailCoreUtils.parse(strg);
                    realName = c2.getRealName();
                } catch (ParseException pe) {
                }
            }
        }
        try {
            EmailCore emailCore = EmailCoreUtils.parse(addrSpec, realName);
            return new EmailItem(emailCore);
        } catch (ParseException pe) {
            return null;
        }
    }

    public Item readEntite(Element element_xml) {
        String nom = "";
        String localisation = "";
        NodeList liste = element_xml.getChildNodes();
        for (int i = 0; i < liste.getLength(); i++) {
            if (liste.item(i).getNodeType() == Node.ELEMENT_NODE) {
                Element el = (Element) liste.item(i);
                String tagname = el.getTagName();
                if (tagname.equals("nom")) {
                    nom = XMLUtils.getData(el);
                } else if (tagname.equals("localisation")) {
                    localisation = XMLUtils.getData(el);
                }
            }
        }
        return new Item(nom);
    }

    public Item readBiblio(Element element_xml) {
        String titre = "";
        String auteurs = "";
        String collection = "";
        String editeur = "";
        String ville = "";
        String pays = "";
        String annee = "";
        String nbrepages = "";
        NodeList liste = element_xml.getChildNodes();
        for (int i = 0; i < liste.getLength(); i++) {
            if (liste.item(i).getNodeType() == Node.ELEMENT_NODE) {
                Element el = (Element) liste.item(i);
                String tagname = el.getTagName();
                if (tagname.equals("titre")) {
                    titre = XMLUtils.getData(el);
                } else if (tagname.equals("auteurs")) {
                    auteurs = XMLUtils.getData(el);
                } else if (tagname.equals("collection")) {
                    collection = XMLUtils.getData(el);
                } else if (tagname.equals("editeur")) {
                    editeur = XMLUtils.getData(el);
                } else if (tagname.equals("ville")) {
                    ville = XMLUtils.getData(el);
                } else if (tagname.equals("pays")) {
                    pays = XMLUtils.getData(el);
                } else if (tagname.equals("annee")) {
                    annee = XMLUtils.getData(el);
                } else if (tagname.equals("nbrepages")) {
                    nbrepages = XMLUtils.getData(el);
                }
            }
        }
        StringBuilder buf = new StringBuilder();
        buf.append(titre);
        appendString(buf, auteurs);
        appendString(buf, collection);
        appendString(buf, editeur);
        appendString(buf, ville);
        appendString(buf, pays);
        appendString(buf, annee);
        appendString(buf, nbrepages);
        return new Item(buf.toString());
    }

    private void appendString(StringBuilder buf, String s) {
        if (s.length() > 0) {
            buf.append(", ");
            buf.append(s);
        }
    }

    public void readSection(Fiche fiche, Element element) {
        String type = element.getAttribute("type");
        if (type.length() == 0) {
            return;
        }
        FieldKey fieldKey;
        try {
            fieldKey = FieldKey.parse(FieldKey.SECTION_CATEGORY, type);
        } catch (ParseException pe) {
            return;
        }
        List<FicheBlock> list = readFicheBlockList(element);
        FicheBlocks ficheBlocks = FicheUtils.toFicheBlocks(list);
        if (append) {
            fiche.appendSection(fieldKey, ficheBlocks);
        } else {
            fiche.setSection(fieldKey, ficheBlocks);
        }
    }

    public FicheBlock readFicheBlock(Element element) {
        String tagname = element.getTagName();
        if (tagname.equals("p")) {
            return readP(element);
        } else if (tagname.equals("ul")) {
            return readUl(element);
        } else if (tagname.equals("h")) {
            return readH(element);
        } else if (tagname.equals("code")) {
            return readCode(element);
        } else if (tagname.equals("table")) {
            return readTable(element);
        } else if (tagname.equals("insert")) {
            return readInsert(element);
        } else if (tagname.equals("div")) {
            return readDiv(element);
        } else if (tagname.equals("cdatadiv")) {
            return readCdatadiv(element);
        } else {
            return null;
        }
    }

    public P readP(Element element_xml) {
        short type = P.typeToShort(element_xml.getAttribute("type"));
        P p = new P(type);
        p.setSource(element_xml.getAttribute("source"));
        readParagraphBlock(p, element_xml);
        return p;
    }

    public H readH(Element element_xml) {
        int level = 1;
        try {
            level = Integer.parseInt(element_xml.getAttribute("level"));
        } catch (NumberFormatException nfe) {
        }
        H h = new H(level);
        readParagraphBlock(h, element_xml);
        return h;
    }

    public Ul readUl(Element element_xml) {
        Ul ul = null;
        NodeList liste = element_xml.getChildNodes();
        for (int j = 0; j < liste.getLength(); j++) {
            if (liste.item(j).getNodeType() == Node.ELEMENT_NODE) {
                Element el = (Element) liste.item(j);
                String tagname = el.getTagName();
                if (tagname.equals("li")) {
                    Li li = readLi(el);
                    if (li != null) {
                        if (ul == null) {
                            ul = new Ul(li);
                        } else {
                            ul.add(li);
                        }
                    }
                }
            }
        }
        if (ul != null) {
            readOldAtt(ul, element_xml);
        }
        return ul;
    }

    public Li readLi(Element element_xml) {
        List<FicheBlock> list = readFicheBlockList(element_xml);
        int size = list.size();
        if (size == 0) {
            return null;
        }
        Li li;
        FicheBlock firstFicheBlock = list.get(0);
        if (firstFicheBlock instanceof P) {
            li = new Li((P) firstFicheBlock);
        } else {
            li = new Li(new P());
            if (li.isValidFicheBlock(firstFicheBlock)) {
                li.add(firstFicheBlock);
            }
        }
        readOldAtt(li, element_xml);
        for (int i = 1; i < size; i++) {
            li.add(list.get(i));
        }
        return li;
    }

    public Code readCode(Element element_xml) {
        short type = Code.typeToShort(element_xml.getAttribute("type"));
        Code code = new Code(type);
        NodeList liste = element_xml.getChildNodes();
        for (int j = 0; j < liste.getLength(); j++) {
            if (liste.item(j).getNodeType() == Node.ELEMENT_NODE) {
                Element el = (Element) liste.item(j);
                String tagname = el.getTagName();
                if (tagname.equals("ln")) {
                    code.add(readLn(el));
                }
            }
        }
        readZoneBlock(code, element_xml);
        return code;
    }

    public Table readTable(Element element_xml) {
        Table table = new Table();
        NodeList liste = element_xml.getChildNodes();
        for (int j = 0; j < liste.getLength(); j++) {
            if (liste.item(j).getNodeType() == Node.ELEMENT_NODE) {
                Element el = (Element) liste.item(j);
                String tagname = el.getTagName();
                if (tagname.equals("tr")) {
                    table.add(readTr(el));
                } else if (tagname.equals("caption")) {
                    String caption = XMLUtils.getData(el);
                    table.getLegendeBuilder().addText(caption);
                }
            }
        }
        readZoneBlock(table, element_xml);
        return table;
    }

    public Tr readTr(Element element_xml) {
        Tr tr = new Tr();
        readOldAtt(tr, element_xml);
        NodeList liste = element_xml.getChildNodes();
        for (int j = 0; j < liste.getLength(); j++) {
            if (liste.item(j).getNodeType() == Node.ELEMENT_NODE) {
                Element el = (Element) liste.item(j);
                String tagname = el.getTagName();
                if (tagname.equals("td")) {
                    tr.add(readTd(el));
                }
            }
        }
        return tr;
    }

    public Ln readLn(Element element_xml) {
        int indentation = 0;
        try {
            indentation = Integer.parseInt(element_xml.getAttribute("indent"));
            if (indentation < 0) {
                indentation = 0;
            }
        } catch (NumberFormatException nfe) {
        }
        Ln ln = new Ln(XMLUtils.getData(element_xml, false), indentation);
        readOldAtt(ln, element_xml);
        return ln;
    }

    public Td readTd(Element element_xml) {
        String typeString = element_xml.getAttribute("type");
        Td td = new Td(Td.typeToShort(typeString));
        readParagraphBlock(td, element_xml);
        return td;
    }

    public Insert readInsert(Element element_xml) {
        Insert insert;
        try {
            short type = Insert.typeToShort(element_xml.getAttribute("type"));
            insert = new Insert(type);
        } catch (IllegalArgumentException iae) {
            return null;
        }
        insert.setSrc(element_xml.getAttribute("src"));
        insert.setRef(element_xml.getAttribute("ref"));
        String creditString = element_xml.getAttribute("credit");
        if (creditString.length() > 0) {
            insert.getCreditBuilder().addText(creditString);
        }
        insert.setPosition(Insert.positionToString(element_xml.getAttribute("position")));
        try {
            int width = Integer.parseInt(element_xml.getAttribute("width"));
            insert.setWidth(width);
        } catch (NumberFormatException nfe) {
        }
        try {
            int height = Integer.parseInt(element_xml.getAttribute("height"));
            insert.setHeight(height);
        } catch (NumberFormatException nfe) {
        }
        String albumName = element_xml.getAttribute("album");
        if (albumName.length() > 0) {
            try {
                SubsetKey albumKey = SubsetKey.parse(SubsetKey.CATEGORY_ALBUM, albumName);
                String idString = element_xml.getAttribute("idalbum");
                if (idString.length() > 0) {
                    try {
                        int illustrationid = Integer.parseInt(idString);
                        String albumDimName = element_xml.getAttribute("albumdim");
                        insert.setSubsetItem(albumKey, illustrationid, albumDimName);
                    } catch (NumberFormatException nfe) {
                    }
                }
            } catch (ParseException pe) {
            }
        }
        readZoneBlock(insert, element_xml);
        return insert;
    }

    public Div readDiv(Element element_xml) {
        Div div = new Div();
        readZoneBlock(div, element_xml);
        NodeList liste = element_xml.getChildNodes();
        for (int j = 0; j < liste.getLength(); j++) {
            if (liste.item(j).getNodeType() == Node.ELEMENT_NODE) {
                Element el = (Element) liste.item(j);
                String tagname = el.getTagName();
                if (tagname.equals("fbl")) {
                    List<FicheBlock> list = readFicheBlockList(el);
                    for (FicheBlock ficheBlock : list) {
                        div.add(ficheBlock);
                    }
                }
            }
        }

        return div;
    }

    public Cdatadiv readCdatadiv(Element element_xml) {
        Cdatadiv cdatadiv = new Cdatadiv();
        readZoneBlock(cdatadiv, element_xml);
        NodeList liste = element_xml.getChildNodes();
        for (int j = 0; j < liste.getLength(); j++) {
            if (liste.item(j).getNodeType() == Node.ELEMENT_NODE) {
                Element el = (Element) liste.item(j);
                String tagname = el.getTagName();
                if (tagname.equals("cdata")) {
                    String cdata = XMLUtils.getRawData(el);
                    cdatadiv.setCdata(htmlCleaner.cleanHtml(cdata));
                    break;
                }
            }
        }
        return cdatadiv;
    }

    private void readZoneBlock(ZoneBlock zoneBlock, Element element_xml) {
        readOldAtt(zoneBlock, element_xml);
        NodeList liste = element_xml.getChildNodes();
        for (int j = 0; j < liste.getLength(); j++) {
            if (liste.item(j).getNodeType() == Node.ELEMENT_NODE) {
                Element el = (Element) liste.item(j);
                String tagname = el.getTagName();
                if (tagname.equals("numero")) {
                    readContentList(zoneBlock.getNumeroBuilder(), el);
                } else if (tagname.equals("legende")) {
                    readContentList(zoneBlock.getLegendeBuilder(), el);
                } else {
                    break;
                }
            }
        }
    }

    public S readS(Element element_xml) {
        String typeString = element_xml.getAttribute("type");
        short type;
        String subType = null;
        if (typeString.equals("xml")) {
            type = S.DEFINITION;
            subType = "XML";
        } else if (typeString.equals("cmd")) {
            type = S.DEFINITION;
            subType = "CMD";
        } else if (typeString.equals("ui")) {
            type = S.SAMPLE;
            subType = "UI";
        } else {
            try {
                type = S.typeToShort(typeString);
            } catch (IllegalArgumentException iae) {
                return null;
            }
        }
        S s = new S(type);
        s.setValue(XMLUtils.getData(element_xml, false));
        String ref = element_xml.getAttribute("ref");
        if (type == S.IMAGE) {
            String src = element_xml.getAttribute("src");
            s.setRef(src);
            if (ref.length() > 0) {
                s.putAtt("href", ref);
            }
        } else {
            s.setRef(ref);
        }
        if (subType == null) {
            subType = element_xml.getAttribute("subtype");
        }
        readSOldAtt(s, element_xml, subType);
        return s;
    }

    private void readOldAtt(AttConsumer attConsumer, Element element_xml) {
        String className = element_xml.getAttribute("class");
        if (className.length() > 0) {
            attConsumer.putAtt("class", className);
        }
        String id = element_xml.getAttribute("htmlid");
        if (id.length() > 0) {
            attConsumer.putAtt("id", id);
        }
        String rowspan = element_xml.getAttribute("rowspan");
        if (rowspan.length() > 0) {
            attConsumer.putAtt("rowspan", rowspan);
        }
        String colspan = element_xml.getAttribute("colspan");
        if (colspan.length() > 0) {
            attConsumer.putAtt("colspan", colspan);
        }
    }

    private void readSOldAtt(AttConsumer attConsumer, Element element_xml, String subType) {
        StringBuilder classBuf = new StringBuilder();
        if (subType != null) {
            classBuf.append(subType);
        }
        String className = element_xml.getAttribute("class");
        if (className.length() > 0) {
            if (classBuf.length() > 0) {
                classBuf.append(' ');
            }
            classBuf.append(className);
        }
        if (classBuf.length() > 0) {
            attConsumer.putAtt("class", classBuf.toString());
        }
        String id = element_xml.getAttribute("htmlid");
        if (id.length() > 0) {
            attConsumer.putAtt("id", id);
        }
        String title = element_xml.getAttribute("title");
        if (title.length() > 0) {
            attConsumer.putAtt("title", title);
        }
        String lang = element_xml.getAttribute("lang");
        if (lang.length() > 0) {
            attConsumer.putAtt("hreflang", lang);
        }
    }

    private void readParagraphBlock(ParagraphBlock pb, Element element_xml) {
        String className = element_xml.getAttribute("class");
        if (className.length() > 0) {
            pb.putAtt("class", className);
        }
        String id = element_xml.getAttribute("htmlid");
        if (id.length() > 0) {
            pb.putAtt("id", id);
        }
        readContentList(pb, element_xml);
    }

    private void readContentList(TextContentBuilder pb, Element element_xml) {
        NodeList list = element_xml.getChildNodes();
        for (int i = 0; i < list.getLength(); i++) {
            short type = list.item(i).getNodeType();
            if (type == Node.TEXT_NODE) {
                String data = ((Text) list.item(i)).getData();
                data = XMLUtils.cleanString(data, false);
                if (data.length() > 0) {
                    pb.addText(data);
                }
            } else if (type == Node.ELEMENT_NODE) {
                Element element = (Element) list.item(i);
                if (element.getTagName().equals("s")) {
                    S span = readS(element);
                    if (span != null) {
                        pb.addS(span);
                    } else {
                        String data = XMLUtils.getData(element, false);
                        if (data.length() > 0) {
                            pb.addText(data);
                        }
                    }
                }
            }
        }
    }

    private FicheItems readFicheItems(Element element) {
        List<FicheItem> list = new ArrayList<FicheItem>();
        NodeList liste = element.getChildNodes();
        for (int j = 0; j < liste.getLength(); j++) {
            if (liste.item(j).getNodeType() == Node.ELEMENT_NODE) {
                Element el = (Element) liste.item(j);
                FicheItem ficheItem = readFicheItem(el);
                if (ficheItem != null) {
                    try {
                        list.add(ficheItem);
                    } catch (IllegalArgumentException iae) {
                    }
                }
            }
        }
        return FicheUtils.toFicheItems(list);
    }

    public List<FicheBlock> readFicheBlockList(Element element) {
        List<FicheBlock> list = new ArrayList<FicheBlock>();
        NodeList liste = element.getChildNodes();
        for (int j = 0; j < liste.getLength(); j++) {
            if (liste.item(j).getNodeType() == Node.ELEMENT_NODE) {
                Element el = (Element) liste.item(j);
                FicheBlock ficheBlock = readFicheBlock(el);
                if (ficheBlock != null) {
                    list.add(ficheBlock);
                }
            }
        }
        return list;
    }

}
