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

import fr.exemole.bdfserver.api.storage.BdfStorageException;
import fr.exemole.bdfserver.storage.directory.StorageFactory;
import fr.exemole.bdfserver.storage.directory.implementations.FichothequeDataSourceImpl;
import fr.exemole.bdfserver.storage.directory.jdbm.EnteteFiche;
import fr.exemole.bdfserver.storage.directory.jdbm.FichothequeJdbm;
import fr.exemole.bdfserver.storage.directory.oldversions.AlbumDOMReader;
import fr.exemole.bdfserver.storage.directory.oldversions.OldCroisementDOMReader;
import fr.exemole.bdfserver.storage.directory.oldversions.OldFicheDOMReader;
import fr.exemole.bdfserver.storage.directory.oldversions.SphereDOMReader;
import fr.exemole.bdfserver.storage.directory.oldversions.ThesaurusDOMReader;
import fr.exemole.bdfserver.tools.storage.StorageFile;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.imageio.IIOException;
import jdbm.RecordManager;
import jdbm.RecordManagerFactory;
import jdbm.RecordManagerOptions;
import net.fichotheque.ExistingIdException;
import net.fichotheque.ExistingSubsetException;
import net.fichotheque.Fichotheque;
import net.fichotheque.FichothequeEditorProvider;
import net.fichotheque.Subset;
import net.fichotheque.SubsetItem;
import net.fichotheque.SubsetKey;
import net.fichotheque.addenda.AddendaEditor;
import net.fichotheque.album.Album;
import net.fichotheque.album.AlbumEditor;
import net.fichotheque.album.Illustration;
import net.fichotheque.corpus.Corpus;
import net.fichotheque.corpus.CorpusEditor;
import net.fichotheque.corpus.FicheMeta;
import net.fichotheque.corpus.NoMasterIdException;
import net.fichotheque.corpus.fiche.Fiche;
import net.fichotheque.croisement.Croisement;
import net.fichotheque.croisement.Croisements;
import net.fichotheque.impl.FichothequeImpl;
import net.fichotheque.sphere.Redacteur;
import net.fichotheque.sphere.Sphere;
import net.fichotheque.sphere.SphereEditor;
import net.fichotheque.thesaurus.Motcle;
import net.fichotheque.thesaurus.Thesaurus;
import net.fichotheque.thesaurus.ThesaurusEditor;
import net.fichotheque.tools.dom.AddendaMetadataDOMReader;
import net.fichotheque.tools.dom.AlbumMetadataDOMReader;
import net.fichotheque.tools.dom.CorpusMetadataDOMReader;
import net.fichotheque.tools.dom.CroisementDOMReader;
import net.fichotheque.tools.dom.DocumentDOMReader;
import net.fichotheque.tools.dom.FicheAttributesDOMReader;
import net.fichotheque.tools.dom.FicheDOMReader;
import net.fichotheque.tools.dom.FichothequeMetadataDOMReader;
import net.fichotheque.tools.dom.IllustrationDOMReader;
import net.fichotheque.tools.dom.MotcleDOMReader;
import net.fichotheque.tools.dom.RedacteurDOMReader;
import net.fichotheque.tools.dom.SphereListDOMReader;
import net.fichotheque.tools.dom.SphereMetadataDOMReader;
import net.fichotheque.tools.dom.ThesaurusMetadataDOMReader;
import net.fichotheque.tools.dom.ThesaurusTreeDOMReader;
import net.fichotheque.utils.FichothequeUtils;
import net.fichotheque.xml.storage.FicheStorageXMLPart;
import net.mapeadores.util.exceptions.ImplementationException;
import net.mapeadores.util.io.FileUtils;
import net.mapeadores.util.localisation.LocalisationUtils;
import net.mapeadores.util.logging.ErrorMessageException;
import net.mapeadores.util.logging.MultiMessageHandler;
import net.mapeadores.util.primitives.FuzzyDate;
import net.mapeadores.util.primitives.PrimUtils;
import net.mapeadores.util.xml.AppendableXMLWriter;
import net.mapeadores.util.xml.XMLUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import net.mapeadores.util.html.HtmlCleaner;


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

    private DirectoryFichotheque() {
    }

    public static Fichotheque buildReadOnly(BdfdataDirectory bdfdataDirectory, HtmlCleaner htmlCleaner, MultiMessageHandler messageHandler, ExceptionHandler exceptionHandler) {
        return buildReadAndWrite(bdfdataDirectory, htmlCleaner, messageHandler, exceptionHandler).getFichotheque();
    }

    public static FichothequeEditorProvider buildReadAndWrite(BdfdataDirectory bdfdataDirectory, HtmlCleaner htmlCleaner, MultiMessageHandler messageHandler, ExceptionHandler exceptionHandler) {
        FichothequeImpl.InitEditor initEditor = FichothequeImpl.init();
        FichothequeInitializer fichothequeInitializer = new FichothequeInitializer(bdfdataDirectory, htmlCleaner, messageHandler, initEditor);
        fichothequeInitializer.init();
        return initEditor.endInit(new FichothequeDataSourceImpl(bdfdataDirectory, bdfdataDirectory.getCacheDir(), fichothequeInitializer.getFichothequeJdbm()), htmlCleaner);
    }


    private static class FichothequeInitializer {

        private final FichothequeImpl.InitEditor fichothequeInitEditor;
        private final BdfdataDirectory bdfdataDirectory;
        private final Fichotheque fichotheque;
        private final HtmlCleaner htmlCleaner;
        private final MultiMessageHandler messageHandler;
        private final Properties recManagerProps = new Properties();
        private boolean initFromJdbm = false;
        private String fichothequeJdbmPath;
        private RecordManager initRecordManager;
        private FichothequeJdbm fichothequeJdbm;

        private FichothequeInitializer(BdfdataDirectory bdfdataDirectory, HtmlCleaner htmlCleaner, MultiMessageHandler messageHandler, FichothequeImpl.InitEditor initEditor) {
            this.bdfdataDirectory = bdfdataDirectory;
            this.htmlCleaner = htmlCleaner;
            this.messageHandler = messageHandler;
            this.fichotheque = initEditor.getFichotheque();
            this.fichothequeInitEditor = initEditor;
        }

        private void initFichothequeJdbm() {
            File cacheDirectory = bdfdataDirectory.getCacheDir();
            File jdbmFile = new File(cacheDirectory, "fichotheque.db");
            if (jdbmFile.exists()) {
                initFromJdbm = true;
            }
            fichothequeJdbmPath = (new File(cacheDirectory, "fichotheque")).getPath();
            recManagerProps.setProperty(RecordManagerOptions.PROVIDER_FACTORY, "fr.exemole.bdfserver.storage.directory.jdbm.Provider");
            recManagerProps.setProperty(RecordManagerOptions.DISABLE_TRANSACTIONS, "true");
            initRecordManager = null;
            try {
                initRecordManager = RecordManagerFactory.createRecordManager(fichothequeJdbmPath, recManagerProps);
            } catch (IOException ioe) {
                if (initFromJdbm) {
                    jdbmFile.delete();
                    initFromJdbm = false;
                    try {
                        initRecordManager = RecordManagerFactory.createRecordManager(fichothequeJdbmPath, recManagerProps);
                    } catch (IOException ioe2) {
                        throw new BdfStorageException(ioe2);
                    }
                }
                throw new BdfStorageException(ioe);
            }
            if (initFromJdbm) {
                fichothequeJdbm = FichothequeJdbm.checkJdbmVersion(initRecordManager);
                if (fichothequeJdbm == null) {
                    jdbmFile.delete();
                    initFromJdbm = false;
                    try {
                        initRecordManager = RecordManagerFactory.createRecordManager(fichothequeJdbmPath, recManagerProps);
                        fichothequeJdbm = FichothequeJdbm.initEmptyInstance(initRecordManager);
                    } catch (IOException ioe2) {
                        throw new BdfStorageException(ioe2);
                    }
                }
            } else {
                fichothequeJdbm = FichothequeJdbm.initEmptyInstance(initRecordManager);
            }
        }

        private void setCurrentURI(StorageFile storageFile) {
            messageHandler.setCurrentSource(storageFile.toURI());
        }

        private FichothequeJdbm getFichothequeJdbm() {
            return fichothequeJdbm;
        }

        void init() {
            initFichothequeJdbm();
            initFichothequeMetadata();
            initSphereList();
            initThesaurusList();
            initAlbumList();
            initAddendaList();
            initCorpusList();
            initFiches();
            Subset[] subsetArray = FichothequeUtils.getSortedSubsetArray(fichotheque, null);
            int subsetCount = subsetArray.length;
            for (int i = 0; i < subsetCount; i++) {
                Subset firstSubset = subsetArray[i];
                for (int j = i; j < subsetCount; j++) {
                    Subset secondSubset = subsetArray[j];
                    initCroisement(firstSubset, secondSubset);
                }
            }
            fichothequeJdbm.commitChanges();
            try {
                initRecordManager.close();
                recManagerProps.setProperty(RecordManagerOptions.DISABLE_TRANSACTIONS, "false");
                RecordManager recordManager = RecordManagerFactory.createRecordManager(fichothequeJdbmPath, recManagerProps);
                fichothequeJdbm.setRecordManager(recordManager);
            } catch (IOException ioe2) {
                throw new BdfStorageException(ioe2);
            }
        }

        private void initFichothequeMetadata() {
            StorageFile storageFile = BdfdataStorageFileCatalog.fichothequeMetadata(bdfdataDirectory);
            Document doc = storageFile.readDocument();
            if (doc != null) {
                setCurrentURI(storageFile);
                FichothequeMetadataDOMReader domReader = new FichothequeMetadataDOMReader(fichothequeInitEditor.getFichothequeMetadataEditor(), messageHandler);
                domReader.fillMetadata(doc.getDocumentElement());
            }
        }

        private void initSphereList() {
            List<SphereEditor> sphereEditorList = new ArrayList<SphereEditor>();
            List<Sphere> oldVersionList = new ArrayList<Sphere>();
            SubsetInfoList infoList = BdfdataStorageFileCatalog.getSubsetInfoList(bdfdataDirectory, SubsetKey.CATEGORY_SPHERE);
            int standardlCount = infoList.getStandardSubsetCount();
            for (int i = 0; i < standardlCount; i++) {
                SubsetInfo subsetInfo = infoList.getStandardSubsetInfo(i);
                SubsetKey sphereKey = subsetInfo.getSubsetKey();
                StorageFile storageFile = subsetInfo.getStorageFile();
                setCurrentURI(storageFile);
                Document document = storageFile.readDocument();
                SphereEditor sphereEditor;
                boolean parseList = false;
                try {
                    Element root = document.getDocumentElement();
                    String tagName = root.getTagName();
                    sphereEditor = fichothequeInitEditor.createSphere(sphereKey);
                    if (tagName.equals("sphere")) {
                        SphereDOMReader sphereDOMReader = new SphereDOMReader(sphereEditor, messageHandler);
                        sphereDOMReader.fillSphere(document.getDocumentElement());
                        oldVersionList.add(sphereEditor.getSphere());
                    } else {
                        parseList = true;
                        SphereMetadataDOMReader sphereMetadataDOMReader = new SphereMetadataDOMReader(sphereEditor.getSphereMetadataEditor(), messageHandler);
                        sphereMetadataDOMReader.fillMetadata(root);
                    }
                    sphereEditorList.add(sphereEditor);
                } catch (ExistingSubsetException ese) {
                    throw new ImplementationException(ese);
                }
                if (parseList) {
                    StorageFile listStorageFile = BdfdataStorageFileCatalog.sphereList(bdfdataDirectory, sphereEditor.getSphere().getSubsetKey());
                    if (listStorageFile.exists()) {
                        setCurrentURI(listStorageFile);
                        Document listDocument = listStorageFile.readDocument();
                        SphereListDOMReader sphereListDOMReader = new SphereListDOMReader(sphereEditor, messageHandler);
                        sphereListDOMReader.fillSphere(listDocument.getDocumentElement());
                    }
                }
            }
            for (SphereEditor sphereEditor : sphereEditorList) {
                SubsetKey sphereKey = sphereEditor.getSphere().getSubsetKey();
                RedacteurDOMReader redacteurDOMReader = new RedacteurDOMReader(sphereEditor, messageHandler);
                for (Redacteur redacteur : sphereEditor.getSphere().getRedacteurList()) {
                    StorageFile storageFile = BdfdataStorageFileCatalog.redacteur(bdfdataDirectory, sphereKey, redacteur.getId());
                    if (storageFile.exists()) {
                        setCurrentURI(storageFile);
                        Document document = storageFile.readDocument();
                        redacteurDOMReader.fillRedacteur(redacteur, document.getDocumentElement());
                    }
                }
            }
            if (!oldVersionList.isEmpty()) {
                for (Sphere sphere : oldVersionList) {
                    Save.saveSphereMetadata(bdfdataDirectory, sphere, null);
                    Save.saveSphereList(bdfdataDirectory, sphere, null);
                    for (Redacteur redacteur : sphere.getRedacteurList()) {
                        Save.saveRedacteur(bdfdataDirectory, redacteur, null);
                    }
                }
            }
        }

        private void initThesaurusList() {
            List<ThesaurusEditor> thesaurusEditorList = new ArrayList<ThesaurusEditor>();
            List<Thesaurus> oldVersionList = new ArrayList<Thesaurus>();
            SubsetInfoList infoList = BdfdataStorageFileCatalog.getSubsetInfoList(bdfdataDirectory, SubsetKey.CATEGORY_THESAURUS);
            int standardCount = infoList.getStandardSubsetCount();
            for (int i = 0; i < standardCount; i++) {
                SubsetInfo subsetInfo = infoList.getStandardSubsetInfo(i);
                SubsetKey thesaurusKey = subsetInfo.getSubsetKey();
                StorageFile storageFile = subsetInfo.getStorageFile();
                setCurrentURI(storageFile);
                Document document = storageFile.readDocument();
                boolean parseTree = false;
                ThesaurusEditor thesaurusEditor;
                try {
                    Element root = document.getDocumentElement();
                    String tagName = root.getTagName();
                    short thesaurusType = ThesaurusMetadataDOMReader.getThesaurusType(root);
                    thesaurusEditor = fichothequeInitEditor.createThesaurus(thesaurusKey, thesaurusType);
                    if (tagName.equals("thesaurus")) {
                        ThesaurusDOMReader thesaurusDOMReader = new ThesaurusDOMReader(thesaurusEditor, messageHandler);
                        thesaurusDOMReader.fillThesaurus(root);
                        oldVersionList.add(thesaurusEditor.getThesaurus());
                    } else {
                        parseTree = true;
                        ThesaurusMetadataDOMReader thesaurusMetadataDOMReader = new ThesaurusMetadataDOMReader(thesaurusEditor.getThesaurusMetadataEditor(), messageHandler);
                        thesaurusMetadataDOMReader.fillMetadata(root);
                    }
                    thesaurusEditorList.add(thesaurusEditor);
                } catch (ExistingSubsetException ese) {
                    throw new ImplementationException(ese);
                }
                if (parseTree) {
                    StorageFile treeStorageFile = BdfdataStorageFileCatalog.thesaurusTree(bdfdataDirectory, thesaurusEditor.getThesaurus().getSubsetKey());
                    if (treeStorageFile.exists()) {
                        setCurrentURI(treeStorageFile);
                        Document treeDocument = treeStorageFile.readDocument();
                        ThesaurusTreeDOMReader thesaurusTreeDOMReader = new ThesaurusTreeDOMReader(thesaurusEditor, messageHandler);
                        thesaurusTreeDOMReader.fillThesaurus(treeDocument.getDocumentElement());
                    }
                }
            }
            for (ThesaurusEditor thesaurusEditor : thesaurusEditorList) {
                SubsetKey thesaurusKey = thesaurusEditor.getThesaurus().getSubsetKey();
                MotcleDOMReader motcleDOMReader = new MotcleDOMReader(thesaurusEditor, messageHandler);
                for (Motcle motcle : thesaurusEditor.getThesaurus().getMotcleList()) {
                    StorageFile motcleStorageFile = BdfdataStorageFileCatalog.motcle(bdfdataDirectory, thesaurusKey, motcle.getId());
                    if (motcleStorageFile.exists()) {
                        setCurrentURI(motcleStorageFile);
                        Document document = motcleStorageFile.readDocument();
                        motcleDOMReader.fillMotcle(motcle, document.getDocumentElement());
                    }
                }
            }
            if (!oldVersionList.isEmpty()) {
                for (Thesaurus thesaurus : oldVersionList) {
                    Save.saveThesaurusMetadata(bdfdataDirectory, thesaurus, null);
                    Save.saveThesaurusTree(bdfdataDirectory, thesaurus, null);
                    for (Motcle motcle : thesaurus.getMotcleList()) {
                        Save.saveMotcle(bdfdataDirectory, motcle, null);
                    }
                }
            }
        }

        private void initAlbumList() {
            SubsetInfoList infoList = BdfdataStorageFileCatalog.getSubsetInfoList(bdfdataDirectory, SubsetKey.CATEGORY_ALBUM);
            List<Album> oldVersionList = new ArrayList<Album>();
            int standardCount = infoList.getStandardSubsetCount();
            for (int i = 0; i < standardCount; i++) {
                SubsetInfo subsetInfo = infoList.getStandardSubsetInfo(i);
                SubsetKey albumKey = subsetInfo.getSubsetKey();
                StorageFile storageFile = subsetInfo.getStorageFile();
                setCurrentURI(storageFile);
                Document document = storageFile.readDocument();
                try {
                    Element root = document.getDocumentElement();
                    AlbumEditor albumEditor = fichothequeInitEditor.createAlbum(albumKey);
                    String tagName = root.getTagName();
                    if (tagName.equals("album")) {
                        AlbumDOMReader albumDOMReader = new AlbumDOMReader(albumEditor, messageHandler);
                        albumDOMReader.fillAlbum(root);
                        oldVersionList.add(albumEditor.getAlbum());
                    } else {
                        AlbumMetadataDOMReader albumMetadataDOMReader = new AlbumMetadataDOMReader(albumEditor.getAlbumMetadataEditor(), messageHandler);
                        albumMetadataDOMReader.fillMetadata(root);
                    }
                    IllustrationDOMReader illustrationDOMReader = new IllustrationDOMReader(albumEditor, messageHandler);
                    List<IllustrationDirectory.IllustrationInfo> illustrationInfoList = IllustrationDirectory.getIllustrationInfoList(bdfdataDirectory, albumKey);
                    for (IllustrationDirectory.IllustrationInfo illustrationInfo : illustrationInfoList) {
                        int illustrationId = illustrationInfo.getId();
                        Illustration illustration;
                        try {
                            illustration = albumEditor.createIllustration(illustrationId, illustrationInfo.getType());
                        } catch (ExistingIdException eie) {
                            throw new ImplementationException(eie);
                        }
                        try (FileInputStream is = new FileInputStream(illustrationInfo.getFile());) {
                            albumEditor.updateIllustration(illustration, is, illustrationInfo.getType());
                        } catch (IIOException iioe) {
                            messageHandler.setCurrentSource(illustrationInfo.getFile().getPath());
                            addMessage("IMAGE FORMAT", "_ error.exception.iio", iioe.getMessage());
                        } catch (ErrorMessageException eme) {
                            messageHandler.setCurrentSource(illustrationInfo.getFile().getPath());
                            messageHandler.addMessage("IMAGE FORMAT", eme.getErrorMessage());
                        } catch (IOException ioe) {
                            throw new BdfStorageException(ioe);
                        }
                        StorageFile illustrationStorageFile = BdfdataStorageFileCatalog.illustration(bdfdataDirectory, albumKey, illustrationId);
                        if (illustrationStorageFile.exists()) {
                            setCurrentURI(illustrationStorageFile);
                            Document xmlDocument = illustrationStorageFile.readDocument();
                            illustrationDOMReader.fillIllustration(illustration, xmlDocument.getDocumentElement());
                        }
                    }
                } catch (ExistingSubsetException ese) {
                    throw new ImplementationException(ese);
                }
            }
            if (!oldVersionList.isEmpty()) {
                for (Album album : oldVersionList) {
                    Save.saveAlbumMetadata(bdfdataDirectory, album, null);
                }
            }
        }

        private void initAddendaList() {
            SubsetInfoList infoList = BdfdataStorageFileCatalog.getSubsetInfoList(bdfdataDirectory, SubsetKey.CATEGORY_ADDENDA);
            int standardCount = infoList.getStandardSubsetCount();
            for (int i = 0; i < standardCount; i++) {
                SubsetInfo subsetInfo = infoList.getStandardSubsetInfo(i);
                SubsetKey addendaKey = subsetInfo.getSubsetKey();
                StorageFile storageFile = subsetInfo.getStorageFile();
                setCurrentURI(storageFile);
                Document document = storageFile.readDocument();
                try {
                    Element root = document.getDocumentElement();
                    AddendaEditor addendaEditor = fichothequeInitEditor.createAddenda(addendaKey);
                    AddendaMetadataDOMReader addendaMetadataDOMReader = new AddendaMetadataDOMReader(addendaEditor.getAddendaMetadataEditor(), messageHandler);
                    addendaMetadataDOMReader.fillMetadata(root);
                    DocumentDOMReader documentDOMReader = new DocumentDOMReader(addendaEditor, messageHandler);
                    List<DocumentDirectory.DocumentInfo> documentInfoList = DocumentDirectory.getDocumentInfoList(bdfdataDirectory, addendaKey);
                    for (DocumentDirectory.DocumentInfo documentInfo : documentInfoList) {
                        int documentid = documentInfo.getId();
                        net.fichotheque.addenda.Document bdfDoc;
                        try {
                            bdfDoc = addendaEditor.createDocument(documentid, documentInfo.getVersionInfoList());
                        } catch (ExistingIdException eie) {
                            throw new ImplementationException(eie);
                        }
                        StorageFile documentStorageFile = BdfdataStorageFileCatalog.document(bdfdataDirectory, addendaKey, documentid);
                        if (documentStorageFile.exists()) {
                            setCurrentURI(documentStorageFile);
                            Document xmlDocument = documentStorageFile.readDocument();
                            documentDOMReader.fillDocument(bdfDoc, xmlDocument.getDocumentElement());
                        }
                    }
                } catch (ExistingSubsetException ese) {
                    throw new ImplementationException(ese);
                }
            }
        }

        private void initCorpusList() {
            SubsetInfoList infoList = BdfdataStorageFileCatalog.getSubsetInfoList(bdfdataDirectory, SubsetKey.CATEGORY_CORPUS);
            int standardCount = infoList.getStandardSubsetCount();
            for (int i = 0; i < standardCount; i++) {
                SubsetInfo subsetInfo = infoList.getStandardSubsetInfo(i);
                SubsetKey corpusKey = subsetInfo.getSubsetKey();
                StorageFile storageFile = subsetInfo.getStorageFile();
                setCurrentURI(storageFile);
                Document document = storageFile.readDocument();
                try {
                    CorpusEditor corpusEditor = fichothequeInitEditor.createCorpus(corpusKey, null);
                    CorpusMetadataDOMReader domReader = new CorpusMetadataDOMReader(corpusEditor.getCorpusMetadataEditor(), messageHandler);
                    domReader.fillMetadata(document.getDocumentElement());
                } catch (ExistingSubsetException ese) {
                    throw new ImplementationException(ese);
                }
            }
            int satelliteCount = infoList.getSatelliteSubsetCount();
            for (int i = 0; i < satelliteCount; i++) {
                SubsetInfo subsetInfo = infoList.getSatelliteSubsetInfo(i);
                SubsetKey corpusKey = subsetInfo.getSubsetKey();
                StorageFile storageFile = subsetInfo.getStorageFile();
                setCurrentURI(storageFile);
                if (fichotheque.containsSubset(corpusKey)) {
                    addMessage(StorageFactory.SEVERE_FILENAME, "_ error.existing.corpus", corpusKey.getKeyString());
                    continue;
                }
                Subset masterSubset = fichotheque.getSubset(subsetInfo.getMasterSubsetKey());
                if (masterSubset == null) {
                    addMessage(StorageFactory.SEVERE_FILENAME, "_ error.unknown.subset", subsetInfo.getMasterSubsetKey());
                    continue;
                }
                Document document = storageFile.readDocument();
                try {
                    CorpusEditor corpusEditor = fichothequeInitEditor.createCorpus(corpusKey, masterSubset);
                    CorpusMetadataDOMReader domReader = new CorpusMetadataDOMReader(corpusEditor.getCorpusMetadataEditor(), messageHandler);
                    domReader.fillMetadata(document.getDocumentElement());
                } catch (ExistingSubsetException ese) {
                    throw new ImplementationException(ese);
                }
            }
        }

        private void initFiches() {
            List<Corpus> satelliteCorpus = new ArrayList<Corpus>();
            for (Corpus corpus : fichotheque.getCorpusList()) {
                if (corpus.getMasterSubset() != null) {
                    satelliteCorpus.add(corpus);
                } else {
                    if (initFromJdbm) {
                        initFichesFromJdbm(corpus);
                    } else {
                        initFichesFromXml(corpus);
                    }
                }
            }
            for (Corpus corpus : satelliteCorpus) {
                if (initFromJdbm) {
                    initFichesFromJdbm(corpus);
                } else {
                    initFichesFromXml(corpus);
                }
            }

        }

        private void initFichesFromJdbm(Corpus corpus) {
            CorpusEditor corpusInitEditor = fichothequeInitEditor.getCorpusEditor(corpus);
            FicheAttributesDOMReader attributesDOMReader = new FicheAttributesDOMReader(corpusInitEditor, messageHandler);
            EnteteFiche[] array = fichothequeJdbm.getEnteteFicheArray(corpus);
            int length = array.length;
            for (int i = 0; i < length; i++) {
                EnteteFiche enteteFiche = array[i];
                try {
                    FicheMeta ficheMeta = corpusInitEditor.createFiche(enteteFiche.getId());
                    corpusInitEditor.saveFiche(ficheMeta, enteteFiche.getFiche());
                    initChrono(corpusInitEditor, ficheMeta);
                    initAttributes(attributesDOMReader, ficheMeta);
                } catch (ExistingIdException | NoMasterIdException e) {
                }
            }
        }

        private void initFichesFromXml(Corpus corpus) {
            CorpusEditor corpusInitEditor = fichothequeInitEditor.getCorpusEditor(corpus);
            SubsetKey corpusKey = corpus.getSubsetKey();
            OldFicheDOMReader oldFicheDOMReader = new OldFicheDOMReader(fichotheque, htmlCleaner);
            FicheDOMReader ficheDOMReader = new FicheDOMReader(htmlCleaner);
            FicheAttributesDOMReader attributesDOMReader = new FicheAttributesDOMReader(corpusInitEditor, messageHandler);
            String corpusPath = BdfdataConstants.FICHOTHEQUE + File.separator + "corpus" + File.separator + corpusKey.getSubsetName();
            File corpusDirectory = bdfdataDirectory.getDataFile(corpusPath);
            if (!corpusDirectory.exists()) {
                corpusDirectory.mkdir();
                return;
            }
            SortedMap<Integer, File> sortedDir = new TreeMap<Integer, File>();
            File[] list = corpusDirectory.listFiles();
            int listLength = list.length;
            for (int i = 0; i < listLength; i++) {
                File f = list[i];
                String name = f.getName();
                if ((f.isDirectory()) && (name.startsWith("f."))) {
                    try {
                        int integer = Integer.parseInt(name.substring(2));
                        if (integer >= 0) {
                            sortedDir.put(integer, f);
                        }
                    } catch (NumberFormatException nfe) {
                    }
                }
            }
            for (File fDir : sortedDir.values()) {
                String fPath = corpusPath + File.separator + fDir.getName();
                File[] list2 = fDir.listFiles();
                int length2 = list2.length;
                SortedSet<Integer> sortedSet = new TreeSet<Integer>();
                for (int j = 0; j < length2; j++) { //Conversion de l'ancienne version
                    File ficheFile = list2[j];
                    String name = ficheFile.getName();
                    if (ficheFile.isDirectory()) {
                        continue;
                    }
                    int idxpoint = name.indexOf('.');
                    if (idxpoint == -1) {
                        continue;
                    }
                    String extension = name.substring(idxpoint + 1);
                    if (!extension.equals("xml")) {
                        continue;
                    }
                    try {
                        int ficheid = Integer.parseInt(name.substring(0, idxpoint));
                        StorageFile fsf = bdfdataDirectory.getStorageFile(fPath + File.separator + name);
                        setCurrentURI(fsf);
                        Document document = fsf.readDocument();
                        Fiche fiche = oldFicheDOMReader.readFiche(document.getDocumentElement());
                        StorageFile storageFile = BdfdataStorageFileCatalog.fiche(bdfdataDirectory, corpusKey, ficheid);
                        try (BufferedWriter buf = storageFile.getWriter()) {
                            AppendableXMLWriter xmlWriter = XMLUtils.toXMLWriter(buf);
                            xmlWriter.appendXMLDeclaration();
                            FicheStorageXMLPart ficheStorageXMLPart = new FicheStorageXMLPart(xmlWriter);
                            ficheStorageXMLPart.appendFiche(fiche);
                        } catch (IOException ioe) {
                            throw new BdfStorageException(ioe);
                        }
                        fsf.delete();
                    } catch (NumberFormatException nfe) {
                    }
                }
                list2 = fDir.listFiles();
                length2 = list2.length;
                for (int j = 0; j < length2; j++) {
                    File ficheDir = list2[j];
                    if (!ficheDir.isDirectory()) {
                        continue;
                    }
                    String name = ficheDir.getName();
                    try {
                        int ficheid = Integer.parseInt(name);
                        sortedSet.add(ficheid);
                    } catch (NumberFormatException nfe) {
                    }
                }
                for (int ficheid : sortedSet) {
                    StorageFile fsf = BdfdataStorageFileCatalog.fiche(bdfdataDirectory, corpusKey, ficheid);
                    setCurrentURI(fsf);
                    try {
                        FicheMeta ficheMeta = corpusInitEditor.createFiche(ficheid);
                        Document document = fsf.readDocument();
                        Fiche fiche = ficheDOMReader.readFiche(document.getDocumentElement());
                        fichothequeJdbm.updateFiche(ficheMeta, fiche);
                        corpusInitEditor.saveFiche(ficheMeta, fiche);
                        initChrono(corpusInitEditor, ficheMeta);
                        initAttributes(attributesDOMReader, ficheMeta);
                    } catch (ExistingIdException eie) {
                        addMessage(StorageFactory.SEVERE_FILENAME, "_ error.existing.id", String.valueOf(ficheid));
                    } catch (NoMasterIdException nmie) {
                        addMessage(StorageFactory.SEVERE_FILENAME, "_ error.unknown.mastersubsetitem", String.valueOf(ficheid), corpus.getMasterSubset().getSubsetKeyString());
                    }
                }
            }
        }

        private void initCroisement(Subset firstSubset, Subset secondSubset) {
            SubsetKey subsetKey1 = firstSubset.getSubsetKey();
            SubsetKey subsetKey2 = secondSubset.getSubsetKey();
            StorageFile oldStorageFile = BdfdataStorageFileCatalog.getOldCroisementStorageFile(bdfdataDirectory, subsetKey1, subsetKey2);
            if (oldStorageFile.exists()) {
                setCurrentURI(oldStorageFile);
                OldCroisementDOMReader croisementDOMReader = new OldCroisementDOMReader(messageHandler);
                Document document = oldStorageFile.readDocument();
                croisementDOMReader.readCroisement(fichothequeInitEditor.getCroisementEditor(), firstSubset, secondSubset, document.getDocumentElement());
                boolean same = subsetKey1.equals(subsetKey2);
                for (SubsetItem subsetItem : firstSubset.getSubsetItemList()) {
                    Croisements croisements = fichotheque.getCroisements(subsetItem, secondSubset);
                    for (Croisements.Entry entry : croisements.getEntryList()) {
                        Croisement croisement = entry.getCroisement();
                        if (same) {
                            SubsetItem otherSubsetItem = entry.getSubsetItem();
                            if (otherSubsetItem.getId() < subsetItem.getId()) {
                                continue;
                            }
                        }
                        Save.saveCroisement(bdfdataDirectory, croisement, null);
                    }

                }
                oldStorageFile.delete();
                return;
            }
            StorageFile croisementDirectory = BdfdataStorageFileCatalog.croisementDirectory(bdfdataDirectory, subsetKey1, subsetKey2);
            if (!croisementDirectory.exists()) {
                return;
            }
            String path = croisementDirectory.getRelativePath();
            CroisementDOMReader croisementDOMReader = new CroisementDOMReader(fichothequeInitEditor.getCroisementEditor(), messageHandler);
            SortedMap<Long, File> sortedDir = new TreeMap<Long, File>();
            File[] list = croisementDirectory.getFile().listFiles();
            int dirLength = list.length;
            for (int i = 0; i < dirLength; i++) {
                File f = list[i];
                String name = f.getName();
                if ((f.isDirectory()) && (name.startsWith("c."))) {
                    int idx = name.indexOf('_');
                    if (idx < 3) {
                        continue;
                    }
                    try {
                        int plage1 = Integer.parseInt(name.substring(2, idx));
                        int plage2 = Integer.parseInt(name.substring(idx + 1));
                        if ((plage1 >= 0) && (plage2 >= 0)) {
                            sortedDir.put(PrimUtils.toLong(plage1, plage2), f);
                        }
                    } catch (NumberFormatException nfe) {
                    }
                }
            }
            for (File cDir : sortedDir.values()) {
                String cPath = path + File.separator + cDir.getName();
                File[] subList = cDir.listFiles();
                SortedMap<Long, String> sortedFileName = new TreeMap<Long, String>();
                int subLength = subList.length;
                for (int j = 0; j < subLength; j++) {
                    File croisementFile = subList[j];
                    if (croisementFile.isDirectory()) {
                        continue;
                    }
                    String name = croisementFile.getName();
                    int idxpoint = name.indexOf('.');
                    if (idxpoint == -1) {
                        continue;
                    }
                    String extension = name.substring(idxpoint + 1);
                    if (!extension.equals("xml")) {
                        continue;
                    }
                    int idxtiret = name.indexOf('_');
                    if ((idxtiret == -1) || (idxtiret > idxpoint) || (idxtiret == 0)) {
                        continue;
                    }
                    try {
                        int id1 = Integer.parseInt(name.substring(0, idxtiret));
                        int id2 = Integer.parseInt(name.substring(idxtiret + 1, idxpoint));
                        long l = PrimUtils.toLong(id1, id2);
                        sortedFileName.put(l, name);
                    } catch (NumberFormatException nfe) {
                    }
                }
                for (Map.Entry<Long, String> entry : sortedFileName.entrySet()) {
                    long l = entry.getKey();
                    int id1 = PrimUtils.getInt1(l);
                    int id2 = PrimUtils.getInt2(l);
                    String name = entry.getValue();
                    StorageFile fsf = bdfdataDirectory.getStorageFile(cPath + File.separator + name);
                    setCurrentURI(fsf);
                    SubsetItem subsetItem1 = firstSubset.getSubsetItemById(id1);
                    SubsetItem subsetItem2 = secondSubset.getSubsetItemById(id2);
                    boolean ok = true;
                    if (subsetItem1 == null) {
                        addMessage(StorageFactory.SEVERE_FILENAME, "_ error.unknown.id", id1);
                        ok = false;
                    }
                    if (subsetItem2 == null) {
                        addMessage(StorageFactory.SEVERE_FILENAME, "_ error.unknown.id", id2);
                        ok = false;
                    }
                    if (!ok) {
                        continue;
                    }
                    Document document = fsf.readDocument();
                    croisementDOMReader.readCroisement(document.getDocumentElement(), subsetItem1, subsetItem2);
                }
            }
        }

        private void initChrono(CorpusEditor corpusInitEditor, FicheMeta ficheMeta) {
            StorageFile storageFile = BdfdataStorageFileCatalog.ficheChrono(bdfdataDirectory, ficheMeta.getSubsetKey(), ficheMeta.getId());
            if (!storageFile.exists()) {
                return;
            }
            setCurrentURI(storageFile);
            File file = storageFile.getFile();
            try {
                String chronoString = FileUtils.readFileToString(file, "UTF-8");
                String creationDateString;
                String modificationDateString;
                int idx = chronoString.indexOf('\n');
                if (idx > 0) {
                    creationDateString = chronoString.substring(0, idx);
                    modificationDateString = chronoString.substring(idx + 1);
                } else {
                    creationDateString = chronoString;
                    modificationDateString = "";
                }
                try {
                    FuzzyDate creationDate = FuzzyDate.parse(creationDateString);
                    corpusInitEditor.setDate(ficheMeta, creationDate, false);
                    if (modificationDateString.length() > 0) {
                        try {
                            FuzzyDate modificationDate = FuzzyDate.parse(modificationDateString);
                            if (modificationDate.compareTo(creationDate) > 0) {
                                corpusInitEditor.setDate(ficheMeta, modificationDate, true);
                            }
                        } catch (ParseException pe2) {
                            addMessage("severe.date.format", "_ error.wrong.date", modificationDateString);
                        }
                    }
                } catch (ParseException pe1) {
                    addMessage("severe.date.format", "_ error.wrong.date", creationDateString);
                }
            } catch (IOException ioe) {
            }
        }

        private void initAttributes(FicheAttributesDOMReader attributesDOMReader, FicheMeta ficheMeta) {
            StorageFile storageFile = BdfdataStorageFileCatalog.ficheAttributes(bdfdataDirectory, ficheMeta.getSubsetKey(), ficheMeta.getId());
            if (!storageFile.exists()) {
                return;
            }
            setCurrentURI(storageFile);
            Document document = storageFile.readDocument();
            attributesDOMReader.fillFicheMeta(ficheMeta, document.getDocumentElement());
        }

        private void addMessage(String category, String messageKey, Object... messageValues) {
            messageHandler.addMessage(category, LocalisationUtils.toMessage(messageKey, messageValues));
        }

    }

}
