/* 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.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.List;
import net.fichotheque.Subset;
import net.fichotheque.corpus.Corpus;
import net.fichotheque.corpus.FicheMeta;
import net.fichotheque.sphere.Sphere;
import net.fichotheque.tools.reponderation.ReponderationEngine;
import net.fichotheque.tools.reponderation.ReponderationLog;
import net.fichotheque.tools.reponderation.ReponderationParameters;
import net.fichotheque.utils.CorpusUtils;
import net.mapeadores.util.exceptions.ShouldNotOccurException;
import net.mapeadores.util.logging.CommandMessageBuilder;
import net.mapeadores.util.logging.ErrorMessageException;
import net.mapeadores.util.request.RequestMap;
import net.mapeadores.util.text.StringUtils;


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

    public final static String COMMANDNAME = "Reponderation";
    public final static String COMMANDKEY = "_ CRP-24";
    public final static String MODE_PARAMNAME = "mode";
    public final static String SELECTION_MODE_PARAMVALUE = "selection";
    public final static String LIST_MODE_PARAMVALUE = "list";
    public final static String IDTOKENS_PARAMNAME = "idtokens";
    public final static String JUNCTIONSUBSET_PARAMNAME = "junctionsubset";
    public final static String OLDMODE_PARAMNAME = "oldmode";
    public final static String NEWMODE_PARAMNAME = "newmode";
    public final static String OLDWEIGHT_PARAMNAME = "oldweight";
    public final static String NEWWEIGHT_PARAMNAME = "newweight";
    private ReponderationParameters reponderationParameters;

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

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

    @Override
    protected void doCommand() {
        ReponderationLog reponderationLog;
        try (EditSession session = startEditSession(Domains.CORPUS, COMMANDNAME)) {
            reponderationLog = ReponderationEngine.run(reponderationParameters, session.getFichothequeEditor());
            if (reponderationLog.getErrorCount() > 0) {
                throw new ShouldNotOccurException("test done before");
            }
        }
        putResultObject(REPONDERATIONLOG_OBJ, reponderationLog);
        setDone("_ done.corpus.reponderation", reponderationParameters.getOriginSubsetKey(), reponderationParameters.getJunctionSubsetKey(), reponderationLog.getResultCount());
    }

    @Override
    protected void checkParameters() throws ErrorMessageException {
        checkFichothequeAdmin();
        Corpus corpus = requestHandler.getMandatoryCorpus();
        String mode = getMandatory(MODE_PARAMNAME);
        String destinationString = requestHandler.getTrimedParameter(JUNCTIONSUBSET_PARAMNAME);
        Subset junctionSubset;
        if (!destinationString.isEmpty()) {
            junctionSubset = requestHandler.getMandatorySubset(JUNCTIONSUBSET_PARAMNAME);
            if (junctionSubset instanceof Sphere) {
                throw BdfErrors.unsupportedParameterValue(JUNCTIONSUBSET_PARAMNAME, destinationString);
            }
        } else {
            junctionSubset = corpus;
        }
        String oldMode = getMandatory(OLDMODE_PARAMNAME).trim();
        String newMode = getMandatory(NEWMODE_PARAMNAME).trim();
        reponderationParameters = new ReponderationParameters(corpus.getSubsetKey(), junctionSubset.getSubsetKey());
        try {
            reponderationParameters.setOldMode(oldMode);
        } catch (ParseException pe) {
            throw BdfErrors.error("_ error.wrong.mode", oldMode);
        }
        try {
            reponderationParameters.setNewMode(newMode);
        } catch (ParseException pe) {
            throw BdfErrors.error("_ error.wrong.mode", newMode);
        }
        String oldWeightString = getMandatory(OLDWEIGHT_PARAMNAME).trim();
        int oldWeight = -1;
        if (oldWeightString.length() > 0) {
            try {
                oldWeight = Integer.parseInt(oldWeightString);
            } catch (NumberFormatException nfe) {
                throw BdfErrors.error("_ error.wrong.weight", oldWeightString);
            }
        }
        reponderationParameters.setOldWeight(oldWeight);
        String newWeightString = getMandatory(NEWWEIGHT_PARAMNAME);
        int newWeight = -1;
        if (newWeightString.length() > 0) {
            try {
                newWeight = Integer.parseInt(newWeightString);
            } catch (NumberFormatException nfe) {
                throw BdfErrors.error("_ error.wrong.weight", newWeightString);
            }
        }
        reponderationParameters.setNewWeight(newWeight);
        if ((oldMode.equals(newMode)) && (oldWeight == newWeight)) {
            throw BdfErrors.error("_ error.unsupported.samereponderation");
        }
        if (mode.equals(SELECTION_MODE_PARAMVALUE)) {
            List<FicheMeta> ficheMetaList = CorpusUtils.getFicheMetaListByCorpus(bdfUser.getSelectedFiches(), corpus);
            if (ficheMetaList.isEmpty()) {
                throw BdfErrors.error("_ error.empty.originselection");
            }
            for (FicheMeta ficheMeta : ficheMetaList) {
                reponderationParameters.addOriginId(ficheMeta.getId());
            }
        } else if (mode.equals(LIST_MODE_PARAMVALUE)) {
            String idTokens = getMandatory(IDTOKENS_PARAMNAME);
            StringBuilder tokenErrorBuffer = new StringBuilder();
            String[] tokens = StringUtils.getTechnicalTokens(idTokens, true);
            int tokenLength = tokens.length;
            if (tokenLength == 0) {
                throw BdfErrors.error("_ error.empty.idtokens");
            }
            for (int i = 0; i < tokenLength; i++) {
                String token = tokens[i];
                boolean done = false;
                try {
                    int id = Integer.parseInt(token);
                    if (id > 0) {
                        done = true;
                        reponderationParameters.addOriginId(id);
                    }
                } catch (NumberFormatException nfe) {
                }
                if (!done) {
                    if (tokenErrorBuffer.length() > 0) {
                        tokenErrorBuffer.append("; ");
                    }
                    tokenErrorBuffer.append(token);
                }
            }
            if (tokenErrorBuffer.length() > 0) {
                throw BdfErrors.error("_ error.wrong.idtokens", tokenErrorBuffer.toString());
            }
        }
        ReponderationLog reponderationLog = ReponderationEngine.test(this.reponderationParameters, fichotheque);
        int errorCount = reponderationLog.getErrorCount();
        if (errorCount > 0) {
            CommandMessageBuilder commandMessageBuilder = CommandMessageBuilder.init();
            for (int i = 0; i < errorCount; i++) {
                ReponderationLog.ReponderationError error = reponderationLog.getError(i);
                Object value = getErrorValue(error);
                String errorKey = error.getErrorKey();
                if (errorKey.equals(ReponderationLog.MISSING_ORIGIN_ID_ERROR)) {
                    commandMessageBuilder.addMultiError("_ error.unknown.id", value);
                } else {
                    commandMessageBuilder.addMultiError("_ error.exception.internalerror", errorKey);
                }
            }
            throw BdfErrors.error(commandMessageBuilder, "_ error.list.reponderation");
        }
    }

    private Object getErrorValue(ReponderationLog.ReponderationError error) {
        int idCount = error.getIdCount();
        if (idCount == 0) {
            return null;
        }
        StringBuilder buf = new StringBuilder();
        for (int i = 0; i < idCount; i++) {
            if (i > 0) {
                buf.append("; ");
            }
            buf.append(error.getId(i));
        }
        return buf.toString();
    }

}
