/* BdfServer_Commands - Copyright (c) 2019-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.corpus;

import fr.exemole.bdfserver.api.BdfServer;
import fr.exemole.bdfserver.api.EditSession;
import fr.exemole.bdfserver.api.interaction.Domains;
import fr.exemole.bdfserver.tools.instruction.AbstractBdfCommand;
import fr.exemole.bdfserver.tools.instruction.BdfErrors;
import java.text.ParseException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import net.fichotheque.Subset;
import net.fichotheque.SubsetItem;
import net.fichotheque.SubsetKey;
import net.fichotheque.corpus.FicheMeta;
import net.fichotheque.eligibility.SubsetEligibility;
import net.fichotheque.tools.FichothequeTools;
import net.fichotheque.utils.FichothequeUtils;
import net.mapeadores.util.logging.ErrorMessageException;
import net.mapeadores.util.request.RequestMap;


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

    public final static String COMMANDNAME = "CroisementCopy";
    public final static String COMMANDKEY = "_ CRP-29";
    public final static String DESTINATION_PARAMNAME = "destination";
    public final static String DOCUMENTS_PARAMNAME = "documents";
    public final static String ILLUSTRATIONS_PARAMNAME = "illustrations";
    public final static String MOTCLES_PARAMNAME = "motcles";
    private FicheMeta origin;
    private FicheMeta destination;
    private CroisementSubsetEligibility croisementEligibility;

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

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

    @Override
    protected void doCommand() throws ErrorMessageException {
        try (EditSession session = startEditSession(Domains.ADDENDA, COMMANDNAME)) {
            FichothequeTools.copyCroisements(session.getFichothequeEditor().getCroisementEditor(), origin, destination, croisementEligibility);
        }
        putResultObject(CORPUS_OBJ, origin.getCorpus());
        putResultObject(FICHEMETA_OBJ, origin);
        putResultObject(DESTINATION_OBJ, destination);
        setDone("_ done.corpus.croisementcopy", destination.getGlobalId());
    }

    @Override
    protected void checkParameters() throws ErrorMessageException {
        origin = requestHandler.getMandatoryFicheMeta();
        String destinationParam = getMandatory(DESTINATION_PARAMNAME);
        try {
            destination = (FicheMeta) FichothequeUtils.parseGlobalId(destinationParam, fichotheque, SubsetKey.CATEGORY_CORPUS, origin.getCorpus());
        } catch (ParseException pe) {
            throw BdfErrors.error("_ error.wrong.id", destinationParam);
        }
        getPermissionChecker()
                .checkWrite(origin)
                .checkWrite(destination);
        croisementEligibility = new CroisementSubsetEligibility();
        int count = 0;
        count += checkCroisement(DOCUMENTS_PARAMNAME, SubsetKey.CATEGORY_ADDENDA);
        count += checkCroisement(ILLUSTRATIONS_PARAMNAME, SubsetKey.CATEGORY_ALBUM);
        count += checkCroisement(MOTCLES_PARAMNAME, SubsetKey.CATEGORY_THESAURUS);
        if (count == 0) {
            throw BdfErrors.error("_ error.empty.elementselection");
        }
    }

    private int checkCroisement(String paramName, short subsetCategory) throws ErrorMessageException {
        String[] values = requestHandler.getTokens(paramName);
        int count = 0;
        for (String value : values) {
            try {
                SubsetItem subsetItem = FichothequeUtils.parseGlobalId(value, fichotheque, subsetCategory, null);
                croisementEligibility.add(subsetItem);
                count++;
            } catch (ParseException pe) {

            }
        }
        return count;
    }


    private static class CroisementSubsetEligibility implements SubsetEligibility {

        private final Map<SubsetKey, CroisementPredicate> map = new HashMap<SubsetKey, CroisementPredicate>();

        private CroisementSubsetEligibility() {

        }

        @Override
        public boolean accept(SubsetKey subsetKey) {
            return map.containsKey(subsetKey);
        }

        @Override
        public Predicate<SubsetItem> getPredicate(Subset subset) {
            return map.get(subset.getSubsetKey());
        }

        private void add(SubsetItem subsetItem) {
            SubsetKey subsetKey = subsetItem.getSubsetKey();
            CroisementPredicate predicate = map.get(subsetKey);
            if (predicate == null) {
                predicate = new CroisementPredicate();
                map.put(subsetKey, predicate);
            }
            predicate.add(subsetItem);
        }

    }


    private static class CroisementPredicate implements Predicate<SubsetItem> {

        private final Set<SubsetItem> set = new HashSet<SubsetItem>();

        private CroisementPredicate() {

        }

        private void add(SubsetItem subsetItem) {
            set.add(subsetItem);
        }

        @Override
        public boolean test(SubsetItem subsetItem) {
            return set.contains(subsetItem);
        }

    }

}
