/* BdfServer_Commands - 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 fr.exemole.bdfserver.commands.exportation;

import fr.exemole.bdfserver.api.BdfServer;
import fr.exemole.bdfserver.api.interaction.Domains;
import fr.exemole.bdfserver.api.interaction.InteractionConstants;
import fr.exemole.bdfserver.api.storage.TemplateStorage;
import fr.exemole.bdfserver.tools.configuration.PathConfigurationBuilder;
import fr.exemole.bdfserver.tools.exportation.transformation.BdfTransformationUtils;
import fr.exemole.bdfserver.tools.exportation.transformation.TransformationAvailabilities;
import fr.exemole.bdfserver.tools.exportation.transformation.defaulttemplates.DefaultOptions;
import fr.exemole.bdfserver.tools.exportation.transformation.defaulttemplates.TemplateStorageUnitFactory;
import fr.exemole.bdfserver.tools.instruction.AbstractBdfCommand;
import fr.exemole.bdfserver.tools.instruction.BdfErrors;
import java.io.IOException;
import java.text.ParseException;
import java.util.LinkedHashSet;
import java.util.Set;
import net.fichotheque.EditOrigin;
import net.fichotheque.SubsetKey;
import net.fichotheque.exportation.transformation.TemplateDescription;
import net.fichotheque.exportation.transformation.TemplateKey;
import net.fichotheque.exportation.transformation.TransformationDescription;
import net.fichotheque.exportation.transformation.TransformationKey;
import net.fichotheque.extraction.ExtractionConstants;
import net.fichotheque.namespaces.TransformationSpace;
import net.mapeadores.util.attr.Attributes;
import net.mapeadores.util.attr.AttributesBuilder;
import net.mapeadores.util.exceptions.NestedIOException;
import net.mapeadores.util.exceptions.ShouldNotOccurException;
import net.mapeadores.util.logging.ErrorMessageException;
import net.mapeadores.util.request.RequestMap;
import net.mapeadores.util.text.StringUtils;
import net.mapeadores.util.text.ValidExtension;


/**
 *
 * @author Vincent Calame
 */
public class TemplateCreationCommand extends AbstractBdfCommand {

    public final static String COMMANDNAME = "TemplateCreation";
    public final static String COMMANDKEY = "_ EXP-31";
    public final static String NEW_TEMPLATE_PARAMNAME = "newtemplate";
    public final static String NOEMPTYCOMPONENTS_PARAMNAME = "noemptycomponents";
    public final static String TYPE_PARAMNAME = "type";
    public final static String HTML_XSLT_TYPE_PARAMVALUE = "html_xslt";
    public final static String FRAGMENT_XSLT_TYPE_PARAMVALUE = "fragment_xslt";
    public final static String ODT_XSLT_TYPE_PARAMVALUE = "odt_xslt";
    public final static String ODT_PROPERTIES_TYPE_PARAMVALUE = "odt_properties";
    public final static String WITHEXTRACTION_PARAMNAME = "withextraction";
    public final static String COMPACTSTYLE_PARAMNAME = "compactstyle";
    public final static String TABLEXPORT_PARAMNAME = "tableexportname";
    public final static String CORPUSLIST_PARAMNAME = "corpuslist";
    private TemplateKey templateKey;
    private String creationType;
    private String templateType;
    private String tableExportName;
    private DefaultOptions options;
    private Attributes initAttributes;

    public TemplateCreationCommand(BdfServer bdfServer, RequestMap requestMap) {
        super(bdfServer, requestMap);
    }

    @Override
    public boolean needSynchronisation() {
        return true;
    }

    @Override
    protected void doCommand() {
        EditOrigin editOrigin = bdfUser.newEditOrigin(Domains.EXPORTATION, COMMANDNAME);
        TemplateStorage.Unit defaultTemplateStorageUnit = getDefaultTemplateStorageUnit();
        try {
            TemplateDescription templateDescription = bdfServer.getTransformationManager().createTemplate(defaultTemplateStorageUnit, editOrigin);
            putResultObject(TEMPLATEDESCRIPTION_OBJ, templateDescription);
            setDone("_ done.exportation.templatecreation", templateKey.getKeyString());
        } catch (IOException ioe) {
            throw new NestedIOException(ioe);
        }

    }

    @Override
    protected void checkParameters() throws ErrorMessageException {
        checkFichothequeAdmin();
        TransformationDescription transformationDescription = requestHandler.getMandatoryTransformationDescription();
        TransformationKey transformationKey = transformationDescription.getTransformationKey();
        String templateName = getMandatory(NEW_TEMPLATE_PARAMNAME);
        templateName = templateName.trim();
        if (templateName.length() == 0) {
            throw BdfErrors.error("_ error.empty.templatename", templateName);
        }
        if (!StringUtils.isTechnicalName(templateName, true)) {
            throw BdfErrors.error("_ error.wrong.templatename", templateName);
        }
        options = DefaultOptions.init()
                .withExtractionDef(requestHandler.isTrue(WITHEXTRACTION_PARAMNAME))
                .compactStyle(requestHandler.isTrue(COMPACTSTYLE_PARAMNAME));
        creationType = getMandatory(TYPE_PARAMNAME);
        ValidExtension validExtension = getValidExtension(creationType);
        templateType = getTemplateType(creationType);
        tableExportName = requestHandler.getTrimedParameter(TABLEXPORT_PARAMNAME);
        try {
            templateKey = TemplateKey.parse(transformationKey, validExtension, templateName);
        } catch (ParseException pe) {
            throw new ShouldNotOccurException("Test done before");
        }
        if (bdfServer.getTransformationManager().containsTemplate(templateKey)) {
            throw BdfErrors.error("_ error.existing.template", templateName);
        }
        if (transformationKey.isCorpusTransformationKey()) {
            if (!fichotheque.containsSubset(transformationKey.toCorpusKey())) {
                throw BdfErrors.unknownParameterValue(InteractionConstants.TRANSFORMATION_PARAMNAME, transformationKey.toCorpusKey().getKeyString());
            }
        }
        if (!TransformationAvailabilities.isValidTemplateType(templateType, templateKey)) {
            throw BdfErrors.error("_ error.unknown.transformation.templatetype", creationType);
        }
        int extractVersion = ExtractionConstants.INTERNATIONAL_VERSION;
        if (templateName.endsWith("v2")) {
            extractVersion = ExtractionConstants.PLURAL_VERSION;
        }
        testDefaultTemplateAvailable(creationType, transformationKey);
        initAttributes = initAttributes(transformationKey, extractVersion);
    }

    private Attributes initAttributes(TransformationKey transformationKey, int extractVersion) throws ErrorMessageException {
        AttributesBuilder attributesBuilder;
        if (!creationType.equals(ODT_PROPERTIES_TYPE_PARAMVALUE)) {
            attributesBuilder = AttributesBuilder.init().appendValue(TransformationSpace.EXTRACTVERSION_KEY, String.valueOf(extractVersion));
            if (TransformationAvailabilities.hasDefaultExtractionDef(transformationKey)) {
                String emptyComponents;
                if (requestHandler.isTrue(NOEMPTYCOMPONENTS_PARAMNAME)) {
                    emptyComponents = "false";
                } else {
                    emptyComponents = "true";
                }
                attributesBuilder.appendValue(TransformationSpace.EMPTYCOMPONENTS_KEY, emptyComponents);
            }
            if (creationType.equals(ODT_XSLT_TYPE_PARAMVALUE)) {
                BdfTransformationUtils.checkOdtTransformerAttributes(attributesBuilder, bdfServer, transformationKey);
            }
        } else {
            attributesBuilder = new AttributesBuilder();
        }
        if (TransformationAvailabilities.useCorpusListAttribute(transformationKey)) {
            String[] corpusNameArray = requestHandler.getTokens(CORPUSLIST_PARAMNAME);
            if (corpusNameArray.length > 0) {
                Set<SubsetKey> set = new LinkedHashSet<SubsetKey>();
                for (String corpusName : corpusNameArray) {
                    SubsetKey corpusKey;
                    try {
                        corpusKey = SubsetKey.parse(SubsetKey.CATEGORY_CORPUS, corpusName);
                        if (fichotheque.containsSubset(corpusKey)) {
                            set.add(corpusKey);
                        }
                    } catch (ParseException pe) {
                    }
                }
                if (!set.isEmpty()) {
                    for (SubsetKey corpusKey : set) {
                        attributesBuilder.appendValue(TransformationSpace.CORPUS_KEY, corpusKey.getSubsetName());
                    }
                }
            }
        }
        return attributesBuilder.toAttributes();
    }

    private static ValidExtension getValidExtension(String creationType) throws ErrorMessageException {
        switch (creationType) {
            case HTML_XSLT_TYPE_PARAMVALUE:
            case FRAGMENT_XSLT_TYPE_PARAMVALUE:
                return null;
            case ODT_XSLT_TYPE_PARAMVALUE:
            case ODT_PROPERTIES_TYPE_PARAMVALUE:
                return ValidExtension.ODT;
            default:
                throw BdfErrors.wrongParameterValue(TYPE_PARAMNAME, creationType);
        }
    }

    private static String getTemplateType(String creationType) throws ErrorMessageException {
        switch (creationType) {
            case HTML_XSLT_TYPE_PARAMVALUE:
            case FRAGMENT_XSLT_TYPE_PARAMVALUE:
            case ODT_XSLT_TYPE_PARAMVALUE:
                return "xslt";
            case ODT_PROPERTIES_TYPE_PARAMVALUE:
                return "properties";
            default:
                throw BdfErrors.wrongParameterValue(TYPE_PARAMNAME, creationType);
        }
    }

    private static void testDefaultTemplateAvailable(String creationType, TransformationKey transformationKey) throws ErrorMessageException {
        switch (creationType) {
            case FRAGMENT_XSLT_TYPE_PARAMVALUE:
                if (!TransformationAvailabilities.hasDefaultFragment(transformationKey)) {
                    throw BdfErrors.wrongParameterValue(TYPE_PARAMNAME, creationType);
                }

        }
    }

    private TemplateStorage.Unit getDefaultTemplateStorageUnit() {
        switch (creationType) {
            case HTML_XSLT_TYPE_PARAMVALUE:
                return TemplateStorageUnitFactory.newXsltHtml(bdfServer, templateKey, options, initAttributes);
            case FRAGMENT_XSLT_TYPE_PARAMVALUE:
                return TemplateStorageUnitFactory.newXsltFragment(bdfServer, templateKey, initAttributes);
            case ODT_XSLT_TYPE_PARAMVALUE:
                return TemplateStorageUnitFactory.newXsltOdt(bdfServer, templateKey, options, initAttributes);
            case ODT_PROPERTIES_TYPE_PARAMVALUE:
                return TemplateStorageUnitFactory.newPropertiesOdt(bdfServer, PathConfigurationBuilder.build(bdfServer), templateKey, tableExportName, initAttributes);
            default:
                throw new ShouldNotOccurException("test done before");
        }
    }

}
