/* BdfServer_DirectoryStorage - Copyright (c) 2010-2022 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.jdbm;

import fr.exemole.bdfserver.api.storage.BdfStorageException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import jdbm.helper.Serializer;
import net.fichotheque.corpus.fiche.Fiche;
import net.fichotheque.corpus.fiche.FicheAPI;
import net.fichotheque.corpus.fiche.FicheItem;
import net.fichotheque.corpus.fiche.FicheItems;
import net.fichotheque.corpus.fiche.ParaItem;
import net.fichotheque.corpus.metadata.FieldKey;
import net.fichotheque.srz.FichePrimitives;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.primitives.io.PrimitivesIOFactory;
import net.mapeadores.util.primitives.io.PrimitivesReader;
import net.mapeadores.util.primitives.io.PrimitivesWriter;
import net.fichotheque.corpus.fiche.Prop;
import net.fichotheque.corpus.fiche.Info;


/**
 *
 * @author Vincent Calame
 */
public class EnteteFicheSerializer implements Serializer {

    private final FieldKeyCoder fieldKeyCoder;

    public EnteteFicheSerializer(FieldKeyCoder fieldKeyCoder) {
        this.fieldKeyCoder = fieldKeyCoder;
    }

    @Override
    public byte[] serialize(Object obj) throws IOException {
        Input input = (Input) obj;
        FicheAPI fiche = input.getFicheAPI();
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        PrimitivesWriter primWriter = PrimitivesIOFactory.newWriter(output);
        primWriter.writeInt(input.getId());
        Lang lang = fiche.getLang();
        if (lang != null) {
            primWriter.writeString(lang.toString());
        } else {
            primWriter.writeString("");
        }
        primWriter.writeString(fiche.getTitle());
        FichePrimitives.writeFicheItem(primWriter, fiche.getSubtitle());
        FichePrimitives.writeFicheItems(primWriter, fiche.getOwners());
        List<Prop> propList = fiche.getPropList();
        int propSize = propList.size();
        primWriter.writeInt(propSize);
        for (int i = 0; i < propSize; i++) {
            Prop prop = propList.get(i);
            int fieldKeyCode = fieldKeyCoder.askForCode(prop);
            primWriter.writeInt(fieldKeyCode);
            FichePrimitives.writePropFicheItem(primWriter, prop);
        }
        List<Info> infoList = fiche.getInfoList();
        int infoSize = infoList.size();
        primWriter.writeInt(infoSize);
        for (int i = 0; i < infoSize; i++) {
            Info info = infoList.get(i);
            int fieldKeyCode = fieldKeyCoder.askForCode(info);
            primWriter.writeInt(fieldKeyCode);
            FichePrimitives.writeFicheItems(primWriter, info);
        }
        return output.toByteArray();
    }

    @Override
    public Object deserialize(byte[] serialized) {
        PrimitivesReader primReader = PrimitivesIOFactory.newReader(serialized);
        try {
            int ficheid = primReader.readInt();
            Fiche fiche = new Fiche();
            EnteteFiche enteteFiche = new EnteteFiche(ficheid, fiche);
            String langString = primReader.readString();
            if (!langString.isEmpty()) {
                fiche.setLang(Lang.build(langString));
            }
            String titre = primReader.readString();
            fiche.setTitle(titre);
            ParaItem subtitlePara = (ParaItem) FichePrimitives.readFicheItem(primReader);
            fiche.setSubtitle(subtitlePara);
            FicheItems redacteurList = FichePrimitives.readFicheItems(primReader);
            fiche.setOwners(redacteurList);
            int propCount = primReader.readInt();
            for (int i = 0; i < propCount; i++) {
                int fieldKeyCode = primReader.readInt();
                FicheItem ficheItem = FichePrimitives.readFicheItem(primReader);
                if (ficheItem != null) {
                    FieldKey fieldKey = fieldKeyCoder.getFieldKey(fieldKeyCode);
                    if ((fieldKey != null) && (fieldKey.isProp())) {
                        fiche.setProp(fieldKey, ficheItem);
                    }
                }
            }
            int infoCount = primReader.readInt();
            for (int i = 0; i < infoCount; i++) {
                int fieldKeyCode = primReader.readInt();
                FicheItems ficheItems = FichePrimitives.readFicheItems(primReader);
                if (ficheItems != null) {
                    FieldKey fieldKey = fieldKeyCoder.getFieldKey(fieldKeyCode);
                    if ((fieldKey != null) && (fieldKey.isInfo())) {
                        fiche.setInfo(fieldKey, ficheItems);
                    }
                }
            }
            return enteteFiche;
        } catch (IOException ioe) {
            throw new BdfStorageException(ioe);
        }
    }


    public static class Input {

        private final int id;
        private final FicheAPI ficheAPI;

        public Input(int id, FicheAPI ficheAPI) {
            this.id = id;
            this.ficheAPI = ficheAPI;
        }

        public int getId() {
            return id;
        }

        public FicheAPI getFicheAPI() {
            return ficheAPI;
        }

    }

}
