/* FichothequeLib_Srz - Copyright (c) 2006-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 net.fichotheque.srz;

import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import net.fichotheque.SubsetKey;
import net.fichotheque.corpus.fiche.AttConsumer;
import net.fichotheque.corpus.fiche.Atts;
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.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.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.TextContent;
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.utils.FicheUtils;
import net.mapeadores.util.exceptions.SwitchException;
import net.mapeadores.util.html.TrustedHtml;
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.primitives.FuzzyDate;
import net.mapeadores.util.primitives.io.PrimitivesReader;
import net.mapeadores.util.primitives.io.PrimitivesWriter;
import net.fichotheque.corpus.fiche.Prop;


/**
 *
 * @author Vincent Calame
 */
public final class FichePrimitives {

    private FichePrimitives() {
    }

    public static void writePropFicheItem(PrimitivesWriter primitivesWriter, Prop prop) throws IOException {
        if (prop == null) {
            primitivesWriter.writeChar('x');
            return;
        }
        writeFicheItem(primitivesWriter, prop.getFicheItem());
    }

    public static void writeFicheItems(PrimitivesWriter primitivesWriter, FicheItems ficheItems) throws IOException {
        if (ficheItems == null) {
            primitivesWriter.writeInt(0);
            return;
        }
        int size = ficheItems.size();
        primitivesWriter.writeInt(size);
        for (int i = 0; i < size; i++) {
            writeFicheItem(primitivesWriter, ficheItems.get(i));
        }
    }

    public static void writeFicheItem(PrimitivesWriter primitivesWriter, FicheItem ficheItem) throws IOException {
        if (ficheItem == null) {
            primitivesWriter.writeChar('x');
            return;
        }
        if (ficheItem instanceof Item) {
            primitivesWriter.writeChar('i');
            primitivesWriter.writeString(((Item) ficheItem).getValue());
        } else if (ficheItem instanceof LanguageItem) {
            primitivesWriter.writeChar('l');
            primitivesWriter.writeString(((LanguageItem) ficheItem).getLang().toString());
        } else if (ficheItem instanceof CountryItem) {
            primitivesWriter.writeChar('c');
            primitivesWriter.writeString(((CountryItem) ficheItem).getCountry().toString());
        } else if (ficheItem instanceof DateItem) {
            primitivesWriter.writeChar('d');
            primitivesWriter.writeInt(FuzzyDate.toInt(((DateItem) ficheItem).getDate()));
        } else if (ficheItem instanceof LinkItem) {
            primitivesWriter.writeChar('a');
            LinkItem link = (LinkItem) ficheItem;
            primitivesWriter.writeString(link.getHref());
            primitivesWriter.writeString(link.getTitle());
            primitivesWriter.writeString(link.getComment());
        } else if (ficheItem instanceof NumberItem) {
            primitivesWriter.writeChar('n');
            NumberItem numberItem = (NumberItem) ficheItem;
            writeDecimal(primitivesWriter, numberItem.getDecimal());
        } else if (ficheItem instanceof AmountItem) {
            primitivesWriter.writeChar('m');
            AmountItem amountItem = (AmountItem) ficheItem;
            writeDecimal(primitivesWriter, amountItem.getDecimal());
            primitivesWriter.writeString(amountItem.getCurrency().getCurrencyCode());
        } else if (ficheItem instanceof EmailItem) {
            primitivesWriter.writeChar('e');
            EmailItem emailItem = (EmailItem) ficheItem;
            EmailCore emailCore = emailItem.getEmailCore();
            primitivesWriter.writeString(emailCore.getAddrSpec());
            primitivesWriter.writeString(emailCore.getRealName());
        } else if (ficheItem instanceof PersonItem) {
            PersonItem personItem = (PersonItem) ficheItem;
            String redacteurGlobalId = personItem.getRedacteurGlobalId();
            if (redacteurGlobalId != null) {
                primitivesWriter.writeChar('r');
                primitivesWriter.writeString(redacteurGlobalId);
            } else {
                primitivesWriter.writeChar('p');
                PersonCore personCore = personItem.getPersonCore();
                primitivesWriter.writeString(personCore.getSurname());
                primitivesWriter.writeBoolean(personCore.isSurnameFirst());
                primitivesWriter.writeString(personCore.getForename());
                primitivesWriter.writeString(personCore.getNonlatin());
                String organism = personItem.getOrganism();
                if (organism == null) {
                    organism = "";
                }
                primitivesWriter.writeString(organism);
            }
        } else if (ficheItem instanceof GeopointItem) {
            primitivesWriter.writeChar('g');
            GeopointItem geopoint = (GeopointItem) ficheItem;
            writeDegreDecimal(primitivesWriter, geopoint.getLatitude());
            writeDegreDecimal(primitivesWriter, geopoint.getLongitude());
        } else if (ficheItem instanceof ParaItem) {
            primitivesWriter.writeChar('b');
            ParaItem para = (ParaItem) ficheItem;
            writeTextContent(primitivesWriter, para);
        } else if (ficheItem instanceof ImageItem) {
            primitivesWriter.writeChar('s');
            ImageItem image = (ImageItem) ficheItem;
            primitivesWriter.writeString(image.getSrc());
            primitivesWriter.writeString(image.getAlt());
            primitivesWriter.writeString(image.getTitle());
        } else {
            throw new SwitchException("class = " + ficheItem.getClass().getName());
        }

    }

    public static void writeFicheBlocks(PrimitivesWriter primitivesWriter, FicheBlocks ficheBlocks) throws IOException {
        if (ficheBlocks == null) {
            primitivesWriter.writeInt(0);
            return;
        }
        int size = ficheBlocks.size();
        primitivesWriter.writeInt(size);
        for (int i = 0; i < size; i++) {
            writeFicheBlock(primitivesWriter, ficheBlocks.get(i));
        }
    }

    public static void writeTr(PrimitivesWriter primitivesWriter, Tr tr) throws IOException {
        if (tr == null) {
            primitivesWriter.writeInt(0);
            return;
        }
        int size = tr.size();
        primitivesWriter.writeInt(size);
        for (int i = 0; i < size; i++) {
            writeTd(primitivesWriter, tr.get(i));
        }
    }

    public static void writeTd(PrimitivesWriter primitivesWriter, Td td) throws IOException {
        primitivesWriter.writeShort(td.getType());
        FichePrimitives.writeAtts(primitivesWriter, td.getAtts());
        writeTextContent(primitivesWriter, td);
    }

    public static void writeLn(PrimitivesWriter primitivesWriter, Ln ln) throws IOException {
        primitivesWriter.writeString(ln.getValue());
        primitivesWriter.writeInt(ln.getIndentation());
        FichePrimitives.writeAtts(primitivesWriter, ln.getAtts());
    }

    public static void writeFicheBlock(PrimitivesWriter primitivesWriter, FicheBlock ficheBlock) throws IOException {
        if (ficheBlock == null) {
            primitivesWriter.writeChar('x');
            return;
        }
        if (ficheBlock instanceof Cdatadiv) {
            primitivesWriter.writeChar('v');
            Cdatadiv cdatadiv = (Cdatadiv) ficheBlock;
            writeCommonZoneBlock(primitivesWriter, cdatadiv);
            primitivesWriter.writeLongString(cdatadiv.getCdata());
        } else if (ficheBlock instanceof Code) {
            primitivesWriter.writeChar('c');
            Code code = (Code) ficheBlock;
            primitivesWriter.writeShort(code.getType());
            writeCommonZoneBlock(primitivesWriter, code);
            int lnLength = code.size();
            primitivesWriter.writeInt(lnLength);
            for (int i = 0; i < lnLength; i++) {
                writeLn(primitivesWriter, code.get(i));
            }
        } else if (ficheBlock instanceof Div) {
            primitivesWriter.writeChar('d');
            Div div = (Div) ficheBlock;
            Lang lang = div.getLang();
            if (lang != null) {
                primitivesWriter.writeString(lang.toString());
            } else {
                primitivesWriter.writeString("");
            }
            writeCommonZoneBlock(primitivesWriter, div);
            writeFicheBlocks(primitivesWriter, div);
        } else if (ficheBlock instanceof H) {
            primitivesWriter.writeChar('h');
            H h = (H) ficheBlock;
            primitivesWriter.writeInt(h.getLevel());
            FichePrimitives.writeAtts(primitivesWriter, h);
            writeTextContent(primitivesWriter, h);
        } else if (ficheBlock instanceof Insert) {
            primitivesWriter.writeChar('i');
            Insert insert = (Insert) ficheBlock;
            primitivesWriter.writeShort(insert.getType());
            writeCommonZoneBlock(primitivesWriter, insert);
            primitivesWriter.writeString(insert.getSrc());
            primitivesWriter.writeString(insert.getRef());
            primitivesWriter.writeInt(insert.getWidth());
            primitivesWriter.writeInt(insert.getHeight());
            primitivesWriter.writeShort(insert.getPosition());
            SubsetKey subsetKey = insert.getSubsetKey();
            if (subsetKey != null) {
                primitivesWriter.writeString(subsetKey.getKeyString());
                primitivesWriter.writeInt(insert.getId());
                primitivesWriter.writeString(insert.getAlbumDimName());
            } else {
                primitivesWriter.writeString("");
                primitivesWriter.writeInt(0);
                primitivesWriter.writeString("");
            }
            writeTextContent(primitivesWriter, insert.getAlt());
            writeTextContent(primitivesWriter, insert.getCredit());
        } else if (ficheBlock instanceof P) {
            primitivesWriter.writeChar('p');
            P p = (P) ficheBlock;
            primitivesWriter.writeShort(p.getType());
            primitivesWriter.writeString(p.getSource());
            FichePrimitives.writeAtts(primitivesWriter, p);
            writeTextContent(primitivesWriter, p);
        } else if (ficheBlock instanceof Table) {
            primitivesWriter.writeChar('t');
            Table table = (Table) ficheBlock;
            writeCommonZoneBlock(primitivesWriter, table);
            int trLength = table.size();
            primitivesWriter.writeInt(trLength);
            for (int i = 0; i < trLength; i++) {
                Tr tr = table.get(i);
                writeAtts(primitivesWriter, tr.getAtts());
                writeTr(primitivesWriter, tr);
            }
        } else if (ficheBlock instanceof Ul) {
            primitivesWriter.writeChar('u');
            Ul ul = (Ul) ficheBlock;
            int liLength = ul.size();
            primitivesWriter.writeInt(liLength);
            for (int i = 0; i < liLength; i++) {
                Li li = ul.get(i);
                int liBlockSize = li.size();
                primitivesWriter.writeInt(liBlockSize);
                for (int j = 0; j < liBlockSize; j++) {
                    writeFicheBlock(primitivesWriter, li.get(j));
                }
                writeAtts(primitivesWriter, li.getAtts());
            }
            FichePrimitives.writeAtts(primitivesWriter, ul);
        } else {
            throw new SwitchException("class = " + ficheBlock.getClass().getName());
        }

    }

    private static void writeDecimal(PrimitivesWriter primitivesWriter, Decimal decimal) throws IOException {
        primitivesWriter.writeLong(decimal.getPartieEntiere());
        primitivesWriter.writeByte(decimal.getZeroLength());
        primitivesWriter.writeInt(decimal.getPartieDecimale());
    }

    private static void writeDegreDecimal(PrimitivesWriter primitivesWriter, DegreDecimal decimal) throws IOException {
        primitivesWriter.writeInt(decimal.getPartieEntiere());
        primitivesWriter.writeByte(decimal.getZeroLength());
        primitivesWriter.writeInt(decimal.getPartieDecimale());
    }

    private static void writeAtts(PrimitivesWriter primitivesWriter, FicheBlock ficheBlock) throws IOException {
        writeAtts(primitivesWriter, ficheBlock.getAtts());
    }

    private static void writeAtts(PrimitivesWriter primitivesWriter, Atts atts) throws IOException {
        int attLength = atts.size();
        primitivesWriter.writeInt(attLength);
        for (int i = 0; i < attLength; i++) {
            primitivesWriter.writeString(atts.getName(i));
            primitivesWriter.writeString(atts.getValue(i));
        }
    }

    private static void writeCommonZoneBlock(PrimitivesWriter primitivesWriter, ZoneBlock zoneBlock) throws IOException {
        FichePrimitives.writeAtts(primitivesWriter, zoneBlock);
        writeTextContent(primitivesWriter, zoneBlock.getNumero());
        writeTextContent(primitivesWriter, zoneBlock.getLegende());
    }

    private static void writeTextContent(PrimitivesWriter primitivesWriter, TextContent content) throws IOException {
        int size = content.size();
        primitivesWriter.writeInt(size);
        for (int i = 0; i < size; i++) {
            Object obj = content.get(i);
            if (obj instanceof String) {
                primitivesWriter.writeByte((byte) 1);
                primitivesWriter.writeString((String) obj);
            } else if (obj instanceof S) {
                primitivesWriter.writeByte((byte) 2);
                writeS(primitivesWriter, (S) obj);
            }
        }
    }

    private static void writeS(PrimitivesWriter primitivesWriter, S s) throws IOException {
        primitivesWriter.writeShort(s.getType());
        primitivesWriter.writeString(s.getRef());
        primitivesWriter.writeString(s.getValue());
        writeAtts(primitivesWriter, s.getAtts());
    }

    public static Object readField(PrimitivesReader primitivesReader, FieldKey fieldKey) throws IOException {
        switch (fieldKey.getCategory()) {
            case FieldKey.PROP_CATEGORY:
                return readFicheItem(primitivesReader);
            case FieldKey.INFO_CATEGORY:
                return readFicheItems(primitivesReader);
            case FieldKey.SPECIAL_CATEGORY:
                switch (fieldKey.getKeyString()) {
                    case FieldKey.SPECIAL_TITLE: {
                        return primitivesReader.readString();
                    }
                    case FieldKey.SPECIAL_SUBTITLE: {
                        Object obj = readFicheItem(primitivesReader);
                        if (obj != null) {
                            if (!(obj instanceof ParaItem)) {
                                throw new IOException("Not a Para ficheItem : " + obj.getClass().getName());
                            }
                        }
                        return obj;
                    }
                    case FieldKey.SPECIAL_LANG: {
                        Object obj = readFicheItem(primitivesReader);
                        if (obj != null) {
                            if (!(obj instanceof LanguageItem)) {
                                throw new IOException("Not a Langue ficheItem : " + obj.getClass().getName());
                            }
                        }
                        return obj;
                    }
                    case FieldKey.SPECIAL_OWNERS: {
                        return readFicheItems(primitivesReader);
                    }
                }
            default:
                throw new SwitchException("fieldKey = " + fieldKey.getKeyString());
        }
    }

    public static FicheItems readFicheItems(PrimitivesReader primitivesReader) throws IOException {
        int size = primitivesReader.readInt();
        if (size == 0) {
            return null;
        }
        List<FicheItem> list = new ArrayList<FicheItem>(size);
        for (int i = 0; i < size; i++) {
            FicheItem ficheItem = readFicheItem(primitivesReader);
            if (ficheItem != null) {
                list.add(ficheItem);
            }
        }
        if (list.isEmpty()) {
            return null;
        }
        return FicheUtils.toFicheItems(list);
    }

    public static FicheItem readFicheItem(PrimitivesReader primitivesReader) throws IOException {
        char carac = primitivesReader.readChar();
        switch (carac) {
            case 'x':
                return null;
            case 'i':
                String value = primitivesReader.readString();
                return new Item(value);
            case 'l':
                String langString = primitivesReader.readString();
                try {
                    return new LanguageItem(Lang.parse(langString));
                } catch (ParseException pe) {
                    return null;
                }
            case 'c':
                String countryCode = primitivesReader.readString();
                return new CountryItem(Country.build(countryCode));
            case 'd':
                int dateInt = primitivesReader.readInt();
                return new DateItem(FuzzyDate.fromInt(dateInt));
            case 'a':
                String href = primitivesReader.readString();
                String title = primitivesReader.readString();
                String comment = primitivesReader.readString();
                return new LinkItem(href, title, comment);
            case 'e':
                String addrSpec = primitivesReader.readString();
                String realName = primitivesReader.readString();
                try {
                    EmailCore emailCore = EmailCoreUtils.parse(addrSpec, realName);
                    return new EmailItem(emailCore);
                } catch (ParseException pe) {
                    return null;
                }
            case 'n':
                Decimal decimale1 = readDecimal(primitivesReader);
                return new NumberItem(decimale1);
            case 'm':
                Decimal decimale2 = readDecimal(primitivesReader);
                String currencyCode = primitivesReader.readString();
                try {
                    return new AmountItem(decimale2, ExtendedCurrency.parse(currencyCode));
                } catch (ParseException pe) {
                    return null;
                }
            case 'g':
                DegreDecimal latitude = readDegreDecimal(primitivesReader);
                DegreDecimal longitude = readDegreDecimal(primitivesReader);
                return new GeopointItem(latitude, longitude);
            case 'r':
                return new PersonItem(primitivesReader.readString());
            case 'p':
                String surname = primitivesReader.readString();
                boolean surnameFirst = primitivesReader.readBoolean();
                String forename = primitivesReader.readString();
                String nonlatin = primitivesReader.readString();
                String organism = primitivesReader.readString();
                return new PersonItem(PersonCoreUtils.toPersonCore(surname, forename, nonlatin, surnameFirst), organism);
            case 'b':
                return readPara(primitivesReader);
            case 's':
                String src = primitivesReader.readString();
                String alt = primitivesReader.readString();
                String imageTitle = primitivesReader.readString();
                return new ImageItem(src, alt, imageTitle);
            default:
                throw new SwitchException("initiale = " + carac);
        }
    }

    public static FicheBlocks readFicheBlocks(PrimitivesReader primitivesReader) throws IOException {
        int size = primitivesReader.readInt();
        if (size == 0) {
            return FicheUtils.EMPTY_FICHEBLOCKS;
        }
        List<FicheBlock> list = new ArrayList<FicheBlock>(size);
        for (int i = 0; i < size; i++) {
            FicheBlock ficheBlock = readFicheBlock(primitivesReader);
            if (ficheBlock != null) {
                list.add(ficheBlock);
            }
        }
        return FicheUtils.toFicheBlocks(list);
    }

    public static FicheBlock readFicheBlock(PrimitivesReader primitivesReader) throws IOException {
        char carac = primitivesReader.readChar();
        switch (carac) {
            case 'x':
                return null;
            case 'v':
                Cdatadiv cdatadiv = new Cdatadiv();
                readCommonZoneBlock(primitivesReader, cdatadiv);
                String cdata = primitivesReader.readLongString();
                cdatadiv.setCdata(new TrustedHtml(cdata));
                return cdatadiv;
            case 'c':
                short codeType = primitivesReader.readShort();
                Code code = new Code(codeType);
                readCommonZoneBlock(primitivesReader, code);
                int lnSize = primitivesReader.readInt();
                for (int i = 0; i < lnSize; i++) {
                    code.add(readLn(primitivesReader));
                }
                return code;
            case 'd':
                Div div = new Div();
                String langString = primitivesReader.readString();
                if (!langString.isEmpty()) {
                    div.setLang(Lang.build(langString));
                }
                readCommonZoneBlock(primitivesReader, div);
                int divFBCount = primitivesReader.readInt();
                for (int i = 0; i < divFBCount; i++) {
                    div.add(readFicheBlock(primitivesReader));
                }
                return div;
            case 'h':
                int hLevel = primitivesReader.readInt();
                H h = new H(hLevel);
                readAtts(primitivesReader, h);
                readTextContent(primitivesReader, h);
                return h;
            case 'i':
                short insertType = primitivesReader.readShort();
                Insert insert = new Insert(insertType);
                readCommonZoneBlock(primitivesReader, insert);
                insert.setSrc(primitivesReader.readString());
                insert.setRef(primitivesReader.readString());
                insert.setWidth(primitivesReader.readInt());
                insert.setHeight(primitivesReader.readInt());
                insert.setPosition(primitivesReader.readShort());
                String subsetKeyString = primitivesReader.readString();
                int id = primitivesReader.readInt();
                String albumDimName = primitivesReader.readString();
                if (subsetKeyString.length() > 0) {
                    try {
                        SubsetKey subsetKey = SubsetKey.parse(subsetKeyString);
                        insert.setSubsetItem(subsetKey, id, albumDimName);
                    } catch (ParseException pe) {
                    }
                }
                readTextContent(primitivesReader, insert.getAltBuilder());
                readTextContent(primitivesReader, insert.getCreditBuilder());
                return insert;
            case 'p':
                short pType = primitivesReader.readShort();
                P p = new P(pType);
                p.setSource(primitivesReader.readString());
                readAtts(primitivesReader, p);
                readTextContent(primitivesReader, p);
                return p;
            case 't':
                Table table = new Table();
                readCommonZoneBlock(primitivesReader, table);
                int trCount = primitivesReader.readInt();
                for (int i = 0; i < trCount; i++) {
                    Tr tr = new Tr();
                    readAtts(primitivesReader, tr);
                    int trSize = primitivesReader.readInt();
                    for (int j = 0; j < trSize; j++) {
                        tr.add(readTd(primitivesReader));
                    }
                    table.add(tr);
                }
                return table;
            case 'u':
                Ul ul = null;
                int liCount = primitivesReader.readInt();
                for (int i = 0; i < liCount; i++) {
                    int liFBCount = primitivesReader.readInt();
                    P firstP = (P) readFicheBlock(primitivesReader);
                    Li li = new Li(firstP);
                    for (int j = 1; j < liFBCount; j++) {
                        li.add(readFicheBlock(primitivesReader));
                    }
                    readAtts(primitivesReader, li);
                    if (i == 0) {
                        ul = new Ul(li);
                    } else {
                        ul.add(li);
                    }
                }
                readAtts(primitivesReader, ul);
                return ul;
            default:
                throw new SwitchException("initiale = " + carac);
        }
    }

    public static Ln readLn(PrimitivesReader primitivesReader) throws IOException {
        String lnValue = primitivesReader.readString();
        int indentation = primitivesReader.readInt();
        Ln ln = new Ln(lnValue, indentation);
        readAtts(primitivesReader, ln);
        return ln;
    }

    public static Td readTd(PrimitivesReader primitivesReader) throws IOException {
        short tdType = primitivesReader.readShort();
        Td td = new Td(tdType);
        readAtts(primitivesReader, td);
        readTextContent(primitivesReader, td);
        return td;
    }

    private static Decimal readDecimal(PrimitivesReader primitivesReader) throws IOException {
        long partieEntiere = primitivesReader.readLong();
        byte zeroLength = primitivesReader.readByte();
        int partieDecimale = primitivesReader.readInt();
        return new Decimal(partieEntiere, zeroLength, partieDecimale);
    }

    private static DegreDecimal readDegreDecimal(PrimitivesReader primitivesReader) throws IOException {
        int partieEntiere = primitivesReader.readInt();
        byte zeroLength = primitivesReader.readByte();
        int partieDecimale = primitivesReader.readInt();
        return DegreDecimal.newInstance(partieEntiere, zeroLength, partieDecimale);
    }

    private static void readAtts(PrimitivesReader primitivesReader, AttConsumer attConsumer) throws IOException {
        int count = primitivesReader.readInt();
        for (int i = 0; i < count; i++) {
            String name = primitivesReader.readString();
            String value = primitivesReader.readString();
            if (attConsumer != null) {
                attConsumer.putAtt(name, value);
            }
        }
    }

    private static void readCommonZoneBlock(PrimitivesReader primitivesReader, ZoneBlock zoneBlock) throws IOException {
        readAtts(primitivesReader, zoneBlock);
        readTextContent(primitivesReader, zoneBlock.getNumeroBuilder());
        readTextContent(primitivesReader, zoneBlock.getLegendeBuilder());
    }

    private static void readTextContent(PrimitivesReader primitivesReader, TextContentBuilder textContentBuilder) throws IOException {
        int size = primitivesReader.readInt();
        for (int i = 0; i < size; i++) {
            Object part = FichePrimitives.readTextContent(primitivesReader);
            if (part instanceof S) {
                textContentBuilder.addS((S) part);
            } else {
                textContentBuilder.addText((String) part);
            }
        }
    }

    private static Object readTextContent(PrimitivesReader primitivesReader) throws IOException {
        byte b = primitivesReader.readByte();
        switch ((int) b) {
            case 1:
                return primitivesReader.readString();
            case 2:
                short type = primitivesReader.readShort();
                String ref = primitivesReader.readString();
                String value = primitivesReader.readString();
                try {
                    S s = new S(type);
                    s.setRef(ref);
                    s.setValue(value);
                    readAtts(primitivesReader, s);
                    return s;
                } catch (IllegalArgumentException iae) {
                    readAtts(primitivesReader, null);
                    return value;
                }
            default:
                throw new SwitchException("byte = " + b);
        }
    }

    private static ParaItem readPara(PrimitivesReader primitivesReader) throws IOException {
        ParaItem.Builder builder = new ParaItem.Builder();
        int size = primitivesReader.readInt();
        for (int i = 0; i < size; i++) {
            Object textContent = FichePrimitives.readTextContent(primitivesReader);
            if (textContent instanceof S) {
                builder.addS((S) textContent);
            } else {
                builder.addText((String) textContent);
            }
        }
        return builder.toParaItem();
    }


}
