/* 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.implementations;

import fr.exemole.bdfserver.storage.directory.StorageDirectory;
import fr.exemole.bdfserver.storage.directory.bdfdata.BdfdataConstants;
import fr.exemole.bdfserver.storage.directory.bdfdata.BdfdataStorageFileCatalog;
import fr.exemole.bdfserver.storage.directory.bdfdata.Remove;
import fr.exemole.bdfserver.storage.directory.bdfdata.Save;
import fr.exemole.bdfserver.storage.directory.jdbm.FichothequeJdbm;
import fr.exemole.bdfserver.tools.BdfServerUtils;
import fr.exemole.bdfserver.tools.storage.StorageFile;
import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.fichotheque.EditOrigin;
import net.fichotheque.SubsetKey;
import net.fichotheque.corpus.Corpus;
import net.fichotheque.corpus.FicheMeta;
import net.fichotheque.corpus.fiche.Fiche;
import net.fichotheque.corpus.fiche.FicheAPI;
import net.fichotheque.junction.JunctionKey;
import net.fichotheque.history.FicheHistory;
import net.fichotheque.history.HistoryUtils;
import net.fichotheque.impl.CorpusDataSource;
import net.fichotheque.tools.dom.FicheDOMReader;
import net.mapeadores.util.html.HtmlCleaner;
import org.w3c.dom.Document;
import net.fichotheque.history.JunctionHistory;


/**
 *
 * @author Vincent Calame
 */
public class CorpusDataSourceImpl implements CorpusDataSource {

    private final StorageDirectory bdfdataDirectory;
    private final FichothequeJdbm fichothequeJdbm;

    public CorpusDataSourceImpl(StorageDirectory bdfdataDirectory, FichothequeJdbm fichothequeJdbm) {
        this.bdfdataDirectory = bdfdataDirectory;
        this.fichothequeJdbm = fichothequeJdbm;
    }

    @Override
    public void saveMetadata(Corpus corpus, EditOrigin editOrigin) {
        if (editOrigin == null) {
            throw new IllegalArgumentException("editOrigin is null");
        }
        Save.saveCorpusMetadata(bdfdataDirectory, corpus, editOrigin);
    }

    @Override
    public Fiche getFiche(FicheMeta ficheMeta, boolean ficheComplete) {
        return fichothequeJdbm.getFiche(ficheMeta, ficheComplete);
    }

    @Override
    public void removeFiche(Corpus corpus, int id, EditOrigin editOrigin) {
        if (editOrigin == null) {
            throw new IllegalArgumentException("editOrigin is null");
        }
        Remove.removeFiche(bdfdataDirectory, corpus, id, editOrigin);
        fichothequeJdbm.removeFiche(corpus, id);
    }

    @Override
    public void saveFiche(FicheMeta ficheMeta, FicheAPI fiche, EditOrigin editOrigin) {
        if (editOrigin == null) {
            throw new IllegalArgumentException("editOrigin is null");
        }
        Save.saveFiche(bdfdataDirectory, ficheMeta, fiche, editOrigin);
        fichothequeJdbm.updateFiche(ficheMeta, fiche);
    }

    @Override
    public void saveChrono(FicheMeta ficheMeta, EditOrigin editOrigin) {
        Save.saveChrono(bdfdataDirectory, ficheMeta, editOrigin);
    }

    @Override
    public void saveAttributes(FicheMeta ficheMeta, EditOrigin editOrigin) {
        Save.saveAttributes(bdfdataDirectory, ficheMeta, editOrigin);
    }

    @Override
    public void commitChanges() {
        fichothequeJdbm.commitChanges();
    }

    @Override
    public FicheHistory getFicheHistory(SubsetKey corpusKey, int id) {
        StorageFile ficheStorageFile = BdfdataStorageFileCatalog.fiche(bdfdataDirectory, corpusKey, id);
        StorageFile attributesStorageFile = BdfdataStorageFileCatalog.ficheAttributes(bdfdataDirectory, corpusKey, id);
        return HistoryUtils.toFicheHistory(corpusKey, id, ficheStorageFile.getHistoryUnit(), attributesStorageFile.getHistoryUnit());
    }

    @Override
    public FicheAPI getFicheRevision(SubsetKey corpusKey, int id, String revisionName) {
        StorageFile storageFile = BdfdataStorageFileCatalog.fiche(bdfdataDirectory, corpusKey, id);
        Document document = storageFile.readDocument(revisionName);
        if (document == null) {
            return null;
        }
        HtmlCleaner htmlCleaner = BdfServerUtils.DEFAULT_HTMLCLEANER;
        FicheDOMReader ficheDOMReader = new FicheDOMReader(htmlCleaner);
        Fiche fiche = ficheDOMReader.readFiche(document.getDocumentElement());
        return fiche;
    }

    @Override
    public List<FicheHistory> getRemovedFicheHistoryList(Corpus corpus) {
        SubsetKey corpusKey = corpus.getSubsetKey();
        String corpusPath = BdfdataConstants.FICHOTHEQUE + File.separator + "corpus" + File.separator + corpusKey.getSubsetName();
        File backupCorpusDirectory = new File(bdfdataDirectory.getBackupDir(), corpusPath);
        if (!backupCorpusDirectory.exists()) {
            return HistoryUtils.EMPTY_FICHEHISTORYLIST;
        }
        List<FicheHistory> result = new ArrayList<FicheHistory>();
        for (File subdir : backupCorpusDirectory.listFiles()) {
            String name = subdir.getName();
            if ((subdir.isDirectory()) && (name.startsWith("f."))) {
                try {
                    int integer = Integer.parseInt(name.substring(2));
                    if (integer >= 0) {
                        for (File ficheDir : subdir.listFiles()) {
                            try {
                                int ficheId = Integer.parseInt(ficheDir.getName());
                                if (ficheId > 0) {
                                    if (corpus.getSubsetItemById(ficheId) == null) {
                                        result.add(getFicheHistory(corpusKey, ficheId));
                                    }
                                }
                            } catch (NumberFormatException nfe) {

                            }
                        }
                    }
                } catch (NumberFormatException nfe) {
                }
            }
        }
        return result;
    }

    @Override
    public List<JunctionHistory> getJunctionHistoryList(SubsetKey corpusKey, int id, SubsetKey thesaurusKey) {
        StorageFile junctionDirectory = BdfdataStorageFileCatalog.junctionDirectory(bdfdataDirectory, corpusKey, corpusKey);
        if (!junctionDirectory.backupExist()) {
            return HistoryUtils.EMPTY_JUNCTIONHISTORYLIST;
        }
        Set<Integer> otherIdSet = new HashSet<Integer>();
        String fileSuffix = id + "_";
        String dirSuffix = "c." + BdfServerUtils.getMillier(id) + "_";
        for (File subdir : junctionDirectory.getBackupFile().listFiles()) {
            if ((subdir.isDirectory()) && (subdir.getName().startsWith(dirSuffix))) {
                for (File file : subdir.listFiles()) {
                    String name = file.getName();
                    if (name.startsWith(fileSuffix)) {
                        int idx = name.indexOf(".");
                        if (idx > 0) {
                            try {
                                Integer otherId = Integer.parseInt(name.substring(fileSuffix.length(), idx));
                                otherIdSet.add(otherId);
                            } catch (NumberFormatException nfe) {

                            }
                        }
                    }
                }
            }
        }
        List<JunctionHistory> result = new ArrayList<JunctionHistory>();
        for (Integer otherId : otherIdSet) {
            JunctionKey junctionKey = new JunctionKey(corpusKey, thesaurusKey, id, otherId);
            StorageFile junctionStorageFile = BdfdataStorageFileCatalog.junction(bdfdataDirectory, junctionKey);
            result.add(HistoryUtils.toJunctionHistory(junctionKey, junctionStorageFile.getHistoryUnit()));
        }
        return result;
    }

}
