/* FichothequeLib_Tools - Copyright (c) 2012-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.tools.extraction;

import java.io.IOException;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import net.fichotheque.SubsetItem;
import net.fichotheque.corpus.FicheMeta;
import net.fichotheque.extraction.ExtractParameters;
import net.fichotheque.extraction.ExtractionSource;
import net.fichotheque.extraction.def.ExtractionDef;
import net.fichotheque.utils.EligibilityUtils;
import net.fichotheque.utils.ExtractionUtils;
import net.fichotheque.xml.extraction.ExtractionXMLPart;
import net.mapeadores.util.xml.AppendableXMLWriter;
import net.mapeadores.util.xml.XMLUtils;


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

    private final ExtractParameters extractParameters;
    private final ExtractionDef extractionDef;
    private boolean prettyXml = false;
    private boolean omitXmlDeclaration = false;
    private String extraXml = null;


    public ExtractionEngine(ExtractParameters extractParameters, ExtractionDef extractionDef) {
        this.extractParameters = extractParameters;
        this.extractionDef = extractionDef;
    }

    public ExtractionEngine prettyXml(boolean prettyXml) {
        this.prettyXml = prettyXml;
        return this;
    }

    public ExtractionEngine omitXmlDeclaration(boolean omitXmlDeclaration) {
        this.omitXmlDeclaration = omitXmlDeclaration;
        return this;
    }

    public ExtractionEngine extraXml(String extraXml) {
        this.extraXml = extraXml;
        return this;
    }

    public String run(ExtractionSource extractionSource) {
        StringBuilder buf = new StringBuilder(1024);
        try {
            append(extractionSource, buf);
        } catch (IOException ioe) {
        }
        return buf.toString();
    }

    public void append(ExtractionSource extractionSource, Appendable appendable) throws IOException {
        AppendableXMLWriter xmlWriter = XMLUtils.toXMLWriter(appendable, (prettyXml) ? 0 : -999);
        ExtractionXMLPart extractionXMLPart = new ExtractionXMLPart(xmlWriter, extractParameters);
        if (!omitXmlDeclaration) {
            xmlWriter.appendXMLDeclaration();
        }
        extractionXMLPart.startExtraction(extractionDef);
        extractionXMLPart.addExtraction(extractionDef, extractionSource);
        if (extraXml != null) {
            if (prettyXml) {
                appendable.append("\n\t");
            }
            appendable.append(extraXml);
        }
        extractionXMLPart.endExtraction(extractionDef);
    }

    public static BiFunction<SubsetItem, Predicate<SubsetItem>, String> getExtractionFunction(ExtractParameters extractParameters, ExtractionDef extractionDef) {
        return new ExtractionFunction(extractionDef, extractParameters);
    }

    public static ExtractionEngine init(ExtractParameters extractParameters, ExtractionDef extractionDef) {
        return new ExtractionEngine(extractParameters, extractionDef);
    }


    private static class ExtractionFunction implements BiFunction<SubsetItem, Predicate<SubsetItem>, String> {

        private final ExtractionDef extractionDef;
        private final ExtractParameters extractParameters;

        private ExtractionFunction(ExtractionDef extractionDef, ExtractParameters extractParameters) {
            this.extractionDef = extractionDef;
            this.extractParameters = extractParameters;
        }

        @Override
        public String apply(SubsetItem subsetItem, Predicate<SubsetItem> predicate) {
            Predicate<FicheMeta> ficheMetaPredicate;
            if (predicate == null) {
                ficheMetaPredicate = EligibilityUtils.ALL_FICHE_PREDICATE;
            } else {
                ficheMetaPredicate = EligibilityUtils.toFichePredicate(predicate);
            }
            ExtractParameters derivedExtractParameters = ExtractionUtils.derive(extractParameters, ficheMetaPredicate);
            ExtractionSource extractionSource = ExtractionEngineUtils.getExtractionSource(subsetItem, derivedExtractParameters.getExtractionContext(), extractionDef, null);
            return ExtractionEngine.init(derivedExtractParameters, extractionDef).omitXmlDeclaration(true).run(extractionSource);
        }


    }

}
