/* BdfServer - Copyright (c) 2009-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.tools.balayage;

import fr.exemole.bdfserver.api.BdfServer;
import java.io.StringReader;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import net.fichotheque.corpus.metadata.FieldKey;
import net.fichotheque.exportation.balayage.BalayageConstants;
import net.fichotheque.exportation.balayage.BalayageDef;
import net.fichotheque.exportation.balayage.BalayageDescription;
import net.fichotheque.exportation.balayage.BalayageUnit;
import net.fichotheque.extraction.FilterParameters;
import net.fichotheque.extraction.def.AddendaExtractDef;
import net.fichotheque.extraction.def.AlbumExtractDef;
import net.fichotheque.extraction.def.CorpusExtractDef;
import net.fichotheque.extraction.def.ExtractionDef;
import net.fichotheque.extraction.def.FicheFilter;
import net.fichotheque.extraction.def.MotcleFilter;
import net.fichotheque.extraction.def.ThesaurusExtractDef;
import net.fichotheque.tools.extraction.builders.AddendaExtractDefBuilder;
import net.fichotheque.tools.extraction.builders.AlbumExtractDefBuilder;
import net.fichotheque.tools.extraction.builders.CorpusExtractDefBuilder;
import net.fichotheque.tools.extraction.builders.ExtractionDefBuilder;
import net.fichotheque.tools.extraction.builders.FicheFilterBuilder;
import net.fichotheque.tools.extraction.builders.MotcleFilterBuilder;
import net.fichotheque.tools.extraction.builders.ThesaurusExtractDefBuilder;
import net.fichotheque.tools.extraction.builders.TitleClauseBuilder;
import net.fichotheque.tools.extraction.dom.ExtractionDOMReader;
import net.fichotheque.utils.ExtractionUtils;
import net.fichotheque.utils.FilterUnits;
import net.fichotheque.xml.extraction.ExtractionXMLUtils;
import net.mapeadores.util.exceptions.SwitchException;
import net.mapeadores.util.xml.DOMUtils;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;


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

    private final static Predicate<String> ACCEPT_ALL_PREDICATE = new AcceptAllExtensionPredicate();
    private final static ExtractionDef CORPUS_DEFAULT_EXTRACTIONDEF = ExtractionDefBuilder.init()
            .setDynamicCorpusExtractDef(CorpusExtractDefBuilder
                    .init(ExtractionXMLUtils.TITLE_FICHEFILTER)
                    .toCorpusExtractDef()
            )
            .toExtractionDef();
    private final static ExtractionDef FICHE_DEFAULT_EXTRACTIONDEF = ExtractionDefBuilder.init()
            .setDynamicCorpusExtractDef(CorpusExtractDefBuilder
                    .init(newFicheInstance())
                    .setClause(CorpusExtractDef.TITLE_CLAUSE, TitleClauseBuilder.DEFAULT)
                    .toCorpusExtractDef()
            )
            .toExtractionDef();
    private final static ExtractionDef MOTCLE_DEFAULT_EXTRACTIONDEF = ExtractionDefBuilder.init()
            .setDynamicThesaurusExtractDef(ThesaurusExtractDefBuilder
                    .init(MotcleFilterBuilder.init(MotcleFilter.DEFAULT_TYPE)
                            .setWithIcon(true)
                            .setWithLabels(true)
                            .addDefaultCorpusExtractDef()
                            .toMotcleFilter())
                    .toThesaurusExtractDef()
            )
            .toExtractionDef();
    private final static ExtractionDef THESAURUS_DEFAULT_EXTRACTIONDEF = ExtractionDefBuilder.init()
            .setDynamicThesaurusExtractDef(ThesaurusExtractDefBuilder
                    .init(MotcleFilterBuilder.init(MotcleFilter.DEFAULT_TYPE)
                            .setWithIcon(true)
                            .setWithLabels(true)
                            .addDefaultCorpusExtractDef()
                            .setChildrenRecursive()
                            .toMotcleFilter())
                    .setBoolean(ThesaurusExtractDef.WITHTHESAURUSTITLE_BOOLEAN, true)
                    .toThesaurusExtractDef()
            )
            .toExtractionDef();
    private final static ExtractionDef UNIQUE_DEFAULT_EXTRACTIONDEF = ExtractionDefBuilder.init().toExtractionDef();


    private BdfBalayageUtils() {
    }

    public static Predicate<String> getExtensionPredicate(BalayageUnit balayageUnit) {
        List<String> extensionList = balayageUnit.getExtensionList();
        if (extensionList.isEmpty()) {
            return ACCEPT_ALL_PREDICATE;
        }
        return new SetExtensionPredicate(new HashSet<String>(extensionList));
    }


    public static ExtractionDef getDefaultExtractionDef(String balayageUnitType) {
        switch (balayageUnitType) {
            case BalayageConstants.CORPUS_TYPE:
                return CORPUS_DEFAULT_EXTRACTIONDEF;
            case BalayageConstants.FICHE_TYPE:
                return FICHE_DEFAULT_EXTRACTIONDEF;
            case BalayageConstants.MOTCLE_TYPE:
                return MOTCLE_DEFAULT_EXTRACTIONDEF;
            case BalayageConstants.THESAURUS_TYPE:
                return THESAURUS_DEFAULT_EXTRACTIONDEF;
            case BalayageConstants.UNIQUE_TYPE:
                return UNIQUE_DEFAULT_EXTRACTIONDEF;
            default:
                throw new SwitchException("wrong balayageUnitType = " + balayageUnitType);
        }
    }

    public static FicheFilter newFicheInstance() {
        CorpusExtractDef corpusExtractDef = CorpusExtractDefBuilder
                .init(ExtractionXMLUtils.TITLE_FICHEFILTER)
                .setClause(CorpusExtractDef.TITLE_CLAUSE, TitleClauseBuilder.DEFAULT)
                .toCorpusExtractDef();
        ThesaurusExtractDef thesaurusExtractDef = ThesaurusExtractDefBuilder
                .init(ExtractionXMLUtils.LABELS_MOTCLEFILTER)
                .toThesaurusExtractDef();
        AlbumExtractDef albumExtractDef = AlbumExtractDefBuilder.init(ExtractionXMLUtils.DEFAULT_ILLUSTRATIONFILTER).toAlbumExtractDef();
        AddendaExtractDef addendaExtractDef = AddendaExtractDefBuilder.init(ExtractionXMLUtils.DEFAULT_DOCUMENTFILTER).toAddendaExtractDef();
        FilterParameters filterParameters = ExtractionUtils.EMPTY_FILTERPARAMETERS;
        return FicheFilterBuilder.init()
                .add(FilterUnits.HEAD_FILTERUNIT)
                .add(FilterUnits.BODY_FILTERUNIT)
                .add(FilterUnits.addendaExtract(addendaExtractDef, filterParameters))
                .add(FilterUnits.thesaurusExtract(thesaurusExtractDef, filterParameters))
                .add(FilterUnits.corpusExtract(corpusExtractDef, filterParameters))
                .add(FilterUnits.albumExtract(albumExtractDef, filterParameters))
                .add(FilterUnits.CHRONO_FILTERUNIT)
                .add(FilterUnits.fieldKey(FieldKey.LANG, filterParameters))
                .add(FilterUnits.FICHEPHRASE_FILTERUNIT)
                .toFicheFilter();
    }

    public static ExtractionDef getExtractionDef(BdfServer bdfServer, BalayageDescription balayageDescription, String extractionPath) throws SAXException {
        String content = bdfServer.getBalayageManager().getBalayageContent(balayageDescription.getName(), "extraction/" + extractionPath);
        if (content == null) {
            return null;
        }
        Document document = DOMUtils.parseDocument(content);
        ExtractionDOMReader extractionDomReader = new ExtractionDOMReader(bdfServer.getFichotheque());
        ExtractionDef extractionDef = extractionDomReader.readExtraction(document.getDocumentElement(), balayageDescription.getIncludeCatalog());
        return extractionDef;
    }

    public static Source getTransformerSource(BdfServer bdfServer, BalayageDef balayageDef, String xsltPath) {
        String content = bdfServer.getBalayageManager().getBalayageContent(balayageDef.getName(), "xslt/" + xsltPath);
        if (content == null) {
            return null;
        }
        return new StreamSource(new StringReader(content), "bdf://this/balayage/" + balayageDef.getName() + "/xslt/" + xsltPath);
    }


    private static class AcceptAllExtensionPredicate implements Predicate<String> {

        private AcceptAllExtensionPredicate() {
        }

        @Override
        public boolean test(String extension) {
            return true;
        }

    }


    private static class SetExtensionPredicate implements Predicate<String> {

        private final Set<String> set;

        private SetExtensionPredicate(Set<String> set) {
            this.set = set;
        }

        @Override
        public boolean test(String extension) {
            return set.contains(extension);
        }

    }

}
