/* BdfServer - Copyright (c) 2022-2023 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;

import fr.exemole.bdfserver.api.BdfServer;
import fr.exemole.bdfserver.api.managers.TransformationManager;
import fr.exemole.bdfserver.api.storage.StorageContent;
import fr.exemole.bdfserver.api.storage.TemplateStorage;
import fr.exemole.bdfserver.tools.configuration.PathConfigurationBuilder;
import fr.exemole.bdfserver.tools.exportation.transformation.defaulttemplates.DefaultOptions;
import fr.exemole.bdfserver.tools.exportation.transformation.defaulttemplates.TemplateStorageUnitFactory;
import fr.exemole.bdfserver.tools.instruction.BdfErrors;
import fr.exemole.bdfserver.tools.storage.TemplateStorageUnitBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.text.ParseException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import net.fichotheque.EditOrigin;
import net.fichotheque.exportation.transformation.TemplateDef;
import net.fichotheque.exportation.transformation.TemplateDescription;
import net.fichotheque.exportation.transformation.TemplateKey;
import net.fichotheque.utils.TransformationUtils;
import net.mapeadores.util.exceptions.NestedTransformerException;
import net.mapeadores.util.io.IOUtils;
import net.mapeadores.util.logging.ErrorMessageException;
import net.mapeadores.util.text.ValidExtension;


/**
 *
 * @author Vincent Calame
 */
public class ConvertToOdtEngine {

    private final BdfServer bdfServer;
    private final TransformationManager transformationManager;
    private final TemplateDescription originTemplateDescription;
    private final TemplateKey originKey;
    private final TemplateKey destinationKey;

    private ConvertToOdtEngine(BdfServer bdfServer, TemplateDescription originTemplateDescription, TemplateKey destinationKey) {
        this.bdfServer = bdfServer;
        this.transformationManager = bdfServer.getTransformationManager();
        this.originTemplateDescription = originTemplateDescription;
        this.originKey = originTemplateDescription.getTemplateKey();
        this.destinationKey = destinationKey;
    }

    public TemplateDescription run(EditOrigin editOrigin) throws IOException {
        if (transformationManager.containsTemplate(destinationKey)) {
            return update(editOrigin);
        } else {
            return create(editOrigin);
        }
    }

    private TemplateDescription update(EditOrigin editOrigin) throws IOException {
        String extractionXml = transformationManager.getTemplateContent(originKey, "extraction.xml");
        if (extractionXml != null) {
            try (InputStream is = IOUtils.toInputStream(extractionXml, "UTF-8")) {
                transformationManager.putTemplateContent(destinationKey, "extraction.xml", is, editOrigin);

            }
        }
        String convertXslt = convertXslt();
        try (InputStream is = IOUtils.toInputStream(convertXslt, "UTF-8")) {
            return transformationManager.putTemplateContent(destinationKey, "content.xsl", is, editOrigin);
        }
    }

    private TemplateDescription create(EditOrigin editOrigin) throws IOException {
        TemplateDef originalTemplateDef = originTemplateDescription.getTemplateDef();
        TemplateDef destinationTemplateDef = TransformationUtils.deriveTemplateDef(originalTemplateDef, destinationKey);
        TemplateStorageUnitBuilder builder = TemplateStorageUnitBuilder.init(originTemplateDescription.getType(), destinationTemplateDef);
        TemplateStorage.Unit defaultTemplateStorageUnit = TemplateStorageUnitFactory.newXsltOdt(bdfServer, destinationKey, DefaultOptions.init(), originalTemplateDef.getAttributes());
        for (StorageContent defaultContent : defaultTemplateStorageUnit.getStorageContentList()) {
            switch (defaultContent.getPath()) {
                case "content.xsl":
                case "extraction.xml":
                    break;
                default:
                    builder.addStorageContent(defaultContent);
            }
        }
        StorageContent extractionXml = transformationManager.getTemplateStorageContent(originKey, "extraction.xml");
        if (extractionXml != null) {
            builder.addStorageContent(extractionXml);
        }
        builder.addStorageContent("content.xsl", convertXslt());
        return transformationManager.createTemplate(builder.toTemplateStorageUnit(), editOrigin);
    }

    private String convertXslt() {
        String htmlTransformerSource = transformationManager.getTemplateContent(originKey, "transformer.xsl");
        TransformerFactory transformerFactory = BdfTransformationUtils.newTransformationFactory(bdfServer, PathConfigurationBuilder.build(bdfServer));
        try {
            Transformer conversion = transformerFactory.newTransformer(transformerFactory.getURIResolver().resolve("bdf://this/xslt/conversions/odtstylesheet/conversion.xsl", null));
            StringWriter stringWriter = new StringWriter();
            conversion.transform(new StreamSource(new StringReader(htmlTransformerSource)), new StreamResult(stringWriter));
            return stringWriter.toString();
        } catch (TransformerException te) {
            throw new NestedTransformerException(te);
        }
    }

    public static ConvertToOdtEngine build(BdfServer bdfServer, TemplateDescription originTemplateDescription) throws ErrorMessageException {
        TemplateKey templateKey = originTemplateDescription.getTemplateKey();
        if (!templateKey.isSimpleTemplate()) {
            throw BdfErrors.error("_ error.unsupported.streamtemplate", templateKey.getKeyString());
        }
        TemplateKey destinationKey = null;
        try {
            destinationKey = TemplateKey.parse(templateKey.getTransformationKey(), ValidExtension.ODT, templateKey.getName());
        } catch (ParseException pe) {

        }
        if (!TransformationAvailabilities.isValidTemplateType("xslt", destinationKey)) {
            throw BdfErrors.error("_ error.unknown.transformation.templatetype", "odt_xslt");
        }
        return new ConvertToOdtEngine(bdfServer, originTemplateDescription, destinationKey);
    }

}
