/* BdfServer - Copyright (c) 2019-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.tools.exportation.transformation.compilers;

import fr.exemole.bdfserver.api.BdfServer;
import fr.exemole.bdfserver.api.configuration.PathConfiguration;
import fr.exemole.bdfserver.api.exportation.transformation.TransformationConstants;
import fr.exemole.bdfserver.api.storage.TemplateStorage;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import net.fichotheque.exportation.transformation.TemplateContentDescription;
import net.fichotheque.exportation.transformation.TemplateKey;
import net.fichotheque.extraction.def.ExtractionDef;
import net.fichotheque.tools.exportation.transformation.TemplateContentDescriptionBuilder;
import net.fichotheque.tools.extraction.dom.ExtractionDOMReader;
import net.mapeadores.opendocument.css.parse.LogCssErrorHandler;
import net.mapeadores.opendocument.elements.ElementMaps;
import net.mapeadores.opendocument.elements.OdLog;
import net.mapeadores.util.exceptions.NestedLibraryException;
import net.mapeadores.util.logging.LogUtils;
import net.mapeadores.util.logging.MessageHandler;
import net.mapeadores.util.xml.XMLUtils;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;


/**
 *
 * @author Vincent Calame
 */
public abstract class TemplateCompiler {

    protected final BdfServer bdfServer;
    protected final PathConfiguration pathConfiguration;
    protected final TemplateKey templateKey;
    protected final MessageHandler messageHandler;
    private final List<TemplateContentDescriptionBuilder> builderList = new ArrayList<TemplateContentDescriptionBuilder>();

    public TemplateCompiler(BdfServer bdfServer, PathConfiguration pathConfiguration, TemplateKey templateKey, MessageHandler messageHandler) {
        this.bdfServer = bdfServer;
        this.pathConfiguration = pathConfiguration;
        this.templateKey = templateKey;
        this.messageHandler = messageHandler;
    }

    public void addError(String messageKey, Object... messageValues) {
        messageHandler.addMessage(TransformationConstants.ERROR_CATEGORY, messageKey, messageValues);
    }


    public void addWarning(String messageKey, Object... messageValues) {
        messageHandler.addMessage(TransformationConstants.WARNING_CATEGORY, messageKey, messageValues);
    }

    public TemplateContentDescriptionBuilder newTemplateContentDescriptionBuilder(String contentPath, boolean mandatory) {
        return newTemplateContentDescriptionBuilder(contentPath, mandatory, false);
    }

    public TemplateContentDescriptionBuilder newTemplateContentDescriptionBuilder(String contentPath, boolean mandatory, boolean binary) {
        String type = (binary) ? TemplateContentDescription.BINARY_TYPE : TemplateContentDescription.TEXT_TYPE;
        TemplateContentDescriptionBuilder builder = TemplateContentDescriptionBuilder.init(templateKey, contentPath, type)
                .setMandatory(mandatory);
        builderList.add(builder);
        return builder;
    }

    public List<TemplateContentDescription> flushTemplateContentDescriptionList() {
        List<TemplateContentDescription> result = new ArrayList<TemplateContentDescription>();
        for (TemplateContentDescriptionBuilder builder : builderList) {
            result.add(builder.toTemplateContentDescription());
        }
        return result;
    }

    public ExtractionDef getExtractionDef(TemplateStorage.Unit storageUnit, String contentPath, boolean mandatory) {
        String category;
        if (mandatory) {
            category = TransformationConstants.ERROR_CATEGORY;
        } else {
            category = TransformationConstants.WARNING_CATEGORY;
        }
        InputStream inputStream;
        try {
            inputStream = TemplateCompilerUtils.getContentInputStream(storageUnit, contentPath);
            if (inputStream == null) {
                if (mandatory) {
                    messageHandler.addMessage(category, "_ error.empty.transformation.ressource", contentPath);
                }
                return null;
            }
        } catch (IOException ioe) {
            messageHandler.addMessage(category, "_ error.exception.transformation_io", contentPath, ioe.getMessage());
            return null;
        }
        TemplateContentDescriptionBuilder templateContentDescriptionBuilder = newTemplateContentDescriptionBuilder(contentPath, mandatory);
        try (InputStream is = inputStream) {
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docbuilder = documentBuilderFactory.newDocumentBuilder();
            Document document = docbuilder.parse(new InputSource(is));
            ExtractionDOMReader extractionDomReader = new ExtractionDOMReader(bdfServer.getFichotheque());
            return extractionDomReader.readExtraction(document.getDocumentElement(), XMLUtils.EMPTY_DOCUMENTFRAGMENTHOLDER);
        } catch (IOException ioe) {
            messageHandler.addMessage(category, "_ error.exception.transformation_io", contentPath, ioe.getMessage());
        } catch (SAXException se) {
            LogUtils.handleSAXException(TemplateCompilerUtils.SEVERE_XML, se, templateContentDescriptionBuilder);
        } catch (ParserConfigurationException pce) {
            throw new NestedLibraryException(pce);
        }
        return null;
    }

    public ElementMaps parseCss(String cssString, String baseURI, String sourceName) {
        LogCssErrorHandler logCssErrorHandler = new LogCssErrorHandler();
        ElementMaps elementMaps = TemplateCompilerUtils.parseCss(bdfServer, pathConfiguration, cssString, baseURI, sourceName, logCssErrorHandler);
        for (OdLog.LogItem logItem : logCssErrorHandler.getLogItemArray()) {
            addWarning("_ warning.transformation.css", sourceName, logItem.toString());
        }
        if (logCssErrorHandler.hasFatalError()) {
            addError("_ error.wrong.transformation.css", sourceName, logCssErrorHandler.getFatalErrorLogItem().toString());
        }
        return elementMaps;
    }


}
