/* BdfServer_HtmlProducers - Copyright (c) 2012-2026 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.htmlproducers.edition;

import fr.exemole.bdfserver.api.ficheform.FicheFormParameters;
import fr.exemole.bdfserver.api.ficheform.FormEntryProvider;
import fr.exemole.bdfserver.api.instruction.BdfInstructionConstants;
import fr.exemole.bdfserver.api.instruction.OutputParameters;
import fr.exemole.bdfserver.api.interaction.InteractionConstants;
import fr.exemole.bdfserver.api.interaction.domains.EditionDomain;
import fr.exemole.bdfserver.api.namespaces.CommandSpace;
import fr.exemole.bdfserver.html.BdfServerHtmlProducer;
import fr.exemole.bdfserver.tools.ficheform.FicheFormParametersBuilder;
import fr.exemole.bdfserver.tools.ficheform.FicheFormUtils;
import fr.exemole.bdfserver.tools.ficheform.FormEntryProviderFactory;
import fr.exemole.bdfserver.tools.filesupload.FilesUploadResult;
import fr.exemole.bdfserver.tools.instruction.BdfErrors;
import fr.exemole.bdfserver.tools.instruction.BdfInstructionUtils;
import fr.exemole.bdfserver.tools.instruction.OutputRequestHandler;
import fr.exemole.bdfserver.tools.instruction.PermissionChecker;
import java.util.function.Predicate;
import net.fichotheque.Subset;
import net.fichotheque.SubsetItem;
import net.fichotheque.SubsetKey;
import net.fichotheque.corpus.Corpus;
import net.fichotheque.corpus.FicheMeta;
import net.fichotheque.corpus.metadata.FieldKey;
import net.fichotheque.eligibility.SubsetEligibility;
import net.fichotheque.pointeurs.FichePointeur;
import net.fichotheque.tools.duplication.DuplicationFilter;
import net.fichotheque.tools.duplication.DuplicationFilterParser;
import net.fichotheque.utils.EligibilityUtils;
import net.fichotheque.utils.PointeurUtils;
import net.fichotheque.utils.pointeurs.PointeurFactory;
import net.mapeadores.util.attr.Attribute;
import net.mapeadores.util.logging.ErrorMessageException;


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

    private final static Predicate<FieldKey> ALL_FIELDKEY_PREDICATE = (FieldKey fieldKey) -> {
        return true;
    };

    private EditionHtmlProducerFactory() {
    }

    public static BdfServerHtmlProducer getHtmlProducer(OutputParameters parameters) throws ErrorMessageException {
        OutputRequestHandler requestHandler = OutputRequestHandler.init(parameters);
        PermissionChecker permissionChecker = requestHandler.getPermissionChecker();
        String page = parameters.getOutput();
        switch (page) {
            case EditionDomain.ZOOMEDIT_PAGE: {
                String callKey = requestHandler.getCallKey();
                String corpusName = requestHandler.getMandatoryParameter("corpus");
                return new ZoomEditHtmlProducer(parameters, callKey, corpusName);
            }
            case EditionDomain.FICHE_RESULT_PAGE: {
                FicheResultHandler ficheResultHandler = FicheResultHandler.build(requestHandler.getFicheMeta(), requestHandler);
                return new FicheResultHtmlProducer(parameters, ficheResultHandler);
            }
            case EditionDomain.FICHE_INDEXATION_PAGE: {
                FicheMeta ficheMeta = requestHandler.getFicheMeta();
                permissionChecker.checkSubsetAdmin(ficheMeta.getCorpus());
                FichePointeur fichePointeur = PointeurFactory.newFichePointeur(ficheMeta.getCorpus()).setCurrentFicheMeta(ficheMeta);
                FormEntryProvider formEntryProvider = FormEntryProviderFactory.newInstance(FicheFormParametersBuilder.build(parameters)
                        .toFicheFormParameters());
                return new FicheIndexationHtmlProducer(parameters, fichePointeur, formEntryProvider);
            }
            case EditionDomain.FICHE_CREATION_PAGE: {
                Corpus corpus = requestHandler.getCorpus();
                permissionChecker.checkFicheCreate(corpus);
                String prefill = requestHandler.getTrimedParameter(EditionDomain.PREFILL_PARAMNAME);
                boolean isDuplicate = (prefill.equals("duplicate"));
                if (corpus.getMasterSubset() != null) {
                    if (isDuplicate) {
                        throw BdfErrors.error("_ error.unsupported.satellitecorpus", corpus.getSubsetName());
                    } else {
                        return new SatelliteFicheCreationHtmlProducer(parameters, corpus);
                    }
                } else {
                    FichePointeur fichePointeur = PointeurFactory.newFichePointeur(corpus, true);
                    if (isDuplicate) {
                        FicheMeta ficheMeta = requestHandler.getFicheMeta();
                        fichePointeur.setCurrentSubsetItem(ficheMeta);
                        boolean isWritable = requestHandler.getPermissionSummary().canWrite(ficheMeta);
                        fichePointeur = filterDuplicateFichePointeur(corpus, fichePointeur, !isWritable);
                    }
                    FicheFormParameters ficheFormParameters = FicheFormUtils.initFicheFormParametersBuilder(parameters)
                            .setDuplicate(isDuplicate)
                            .toFicheFormParameters();
                    FormEntryProvider formEntryProvider = FormEntryProviderFactory.newInstance(ficheFormParameters);
                    FicheFormHtmlProducer ficheFormHtmlProducer = FicheFormHtmlProducer.newCreationInstance(parameters, fichePointeur, formEntryProvider);
                    checkOptions(ficheFormHtmlProducer, requestHandler);
                    return ficheFormHtmlProducer;
                }
            }
            case EditionDomain.FICHE_CHANGE_PAGE: {
                Corpus corpus = requestHandler.getCorpus();
                FichePointeur fichePointeur = PointeurFactory.newFichePointeur(corpus, true);
                int id = -1;
                FicheMeta ficheMeta = (FicheMeta) parameters.getResultObject(BdfInstructionConstants.FICHEMETA_OBJ);
                if (ficheMeta == null) {
                    id = requestHandler.getMandatoryId();
                    ficheMeta = corpus.getFicheMetaById(id);
                }
                if (ficheMeta != null) {
                    permissionChecker.checkWrite(ficheMeta);
                    fichePointeur.setCurrentSubsetItem(ficheMeta);
                    FicheFormParameters ficheFormParameters = FicheFormUtils.initFicheFormParametersBuilder(parameters).toFicheFormParameters();
                    FormEntryProvider formEntryProvider = FormEntryProviderFactory.newInstance(ficheFormParameters);
                    FicheFormHtmlProducer ficheFormHtmlProducer = FicheFormHtmlProducer.newChangeInstance(parameters, fichePointeur, formEntryProvider);
                    checkOptions(ficheFormHtmlProducer, requestHandler);
                    return ficheFormHtmlProducer;
                } else {
                    permissionChecker.checkFicheCreate(corpus);
                    SubsetItem masterSubsetItem = BdfInstructionUtils.checkMasterSubsetItem(corpus, id, parameters.getBdfUser());
                    boolean force = requestHandler.isTrue(EditionDomain.FORCE_PARAMNAME);
                    if (!force) {
                        return new CreationConfirmHtmlProducer(parameters, corpus, id, masterSubsetItem);
                    }
                    FormEntryProvider formEntryProvider = FormEntryProviderFactory.newInstance(FicheFormUtils.initFicheFormParametersBuilder(parameters).setMasterSubsetItem(masterSubsetItem).toFicheFormParameters());
                    FicheFormHtmlProducer ficheFormHtmlProducer;
                    if (masterSubsetItem != null) {
                        ficheFormHtmlProducer = FicheFormHtmlProducer.newCreationInstance(parameters, fichePointeur, masterSubsetItem, formEntryProvider);
                    } else {
                        ficheFormHtmlProducer = FicheFormHtmlProducer.newCreationInstance(parameters, fichePointeur, id, formEntryProvider);
                    }
                    checkOptions(ficheFormHtmlProducer, requestHandler);
                    return ficheFormHtmlProducer;
                }
            }
            case EditionDomain.SECTIONPREVIEW_PAGE: {
                Corpus corpus = requestHandler.getCorpus();
                return new SectionPreviewHtmlProducer(parameters, corpus);
            }
            case EditionDomain.FILESUPLOAD_FORM_PAGE: {
                return new FilesUploadFormHtmlProducer(parameters, requestHandler.getMode(), requestHandler.getCallKey());
            }
            case EditionDomain.FILESUPLOAD_RESULT_PAGE: {
                FilesUploadResult filesUploadResult = (FilesUploadResult) parameters.getResultObject(BdfInstructionConstants.FILESUPLOADRESULT_OBJ);
                if (filesUploadResult == null) {
                    throw BdfErrors.missingCommandResultPage(EditionDomain.FILESUPLOAD_RESULT_PAGE);
                }
                return new FilesUploadResultHtmlProducer(parameters, filesUploadResult, requestHandler.getCallKey());
            }
            default:
                return null;
        }
    }

    private static void checkOptions(FicheFormHtmlProducer ficheFormHtmlProducer, OutputRequestHandler requestHandler) throws ErrorMessageException {
        String resultPage = requestHandler.getTrimedParameter(InteractionConstants.PAGE_RESULT_PARAMNAME);
        if (!resultPage.isEmpty()) {
            ficheFormHtmlProducer.setFicheResultPage(resultPage);
        }
        String resultPageOptions = requestHandler.getTrimedParameter(InteractionConstants.PAGE_RESULT_OPTIONS_PARAMNAME);
        if (!resultPageOptions.isEmpty()) {
            ficheFormHtmlProducer.setResultPageOptions(resultPageOptions);
        }
        ficheFormHtmlProducer.setGotoAtStart(requestHandler.getTrimedParameter(InteractionConstants.GOTO_PARAMNAME));
    }

    private static FichePointeur filterDuplicateFichePointeur(Corpus corpus, FichePointeur originalFichePointeur, boolean excludeJunctionTest) {
        Attribute excludeAttribute = corpus.getCorpusMetadata().getAttributes().getAttribute(CommandSpace.DUPLICATION_EXCLUDE_KEY);
        if ((excludeAttribute == null) && (!excludeJunctionTest)) {
            return originalFichePointeur;
        }
        SubsetEligibility subsetEligibility = EligibilityUtils.ALL_SUBSET_ELIGIBILITY;
        Predicate<FieldKey> fieldKeyPredicate = ALL_FIELDKEY_PREDICATE;
        if (excludeAttribute != null) {
            DuplicationFilter duplicationFilter = DuplicationFilterParser.parseExclude(excludeAttribute);
            subsetEligibility = duplicationFilter.getSubsetEligibility();
            fieldKeyPredicate = duplicationFilter.getFieldPredicate();
        }
        if (excludeJunctionTest) {
            subsetEligibility = new FilterSubsetEligibility(subsetEligibility);
        }
        return PointeurUtils.filter(originalFichePointeur, subsetEligibility, fieldKeyPredicate);
    }


    private static class FilterSubsetEligibility implements SubsetEligibility {

        private final SubsetEligibility originalSubsetEligibility;

        private FilterSubsetEligibility(SubsetEligibility originalSubsetEligibility) {
            this.originalSubsetEligibility = originalSubsetEligibility;
        }

        @Override
        public boolean accept(SubsetKey subsetKey) {
            switch (subsetKey.getCategory()) {
                case SubsetKey.CATEGORY_ADDENDA:
                case SubsetKey.CATEGORY_ALBUM:
                    return false;
                default:
                    return originalSubsetEligibility.accept(subsetKey);
            }
        }

        @Override
        public Predicate<SubsetItem> getPredicate(Subset subset) {
            switch (subset.getSubsetKey().getCategory()) {
                case SubsetKey.CATEGORY_ADDENDA:
                case SubsetKey.CATEGORY_ALBUM:
                    return EligibilityUtils.NONE_SUBSETITEM_PREDICATE;
                default:
                    return originalSubsetEligibility.getPredicate(subset);
            }
        }


    }

}
