/* BdfServer_Commands - Copyright (c) 2011-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 net.fichotheque.corpus.Corpus;
import net.fichotheque.corpus.metadata.CorpusField;
import net.fichotheque.corpus.metadata.CorpusMetadata;
import net.fichotheque.corpus.metadata.CorpusMetadataEditor;
import net.fichotheque.corpus.metadata.FieldGeneration;
import net.fichotheque.corpus.metadata.FieldKey;
import net.fichotheque.corpus.metadata.FieldOptionConstants;
import net.fichotheque.corpus.metadata.FieldOptionException;
import net.fichotheque.tools.corpus.FieldGenerationParser;
import net.fichotheque.utils.CorpusMetadataUtils;
import net.fichotheque.utils.FieldOptionUtils;
import net.mapeadores.util.exceptions.ImplementationException;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.logging.CommandMessageBuilder;
import net.mapeadores.util.logging.ErrorMessageException;
import net.mapeadores.util.logging.LineMessage;
import net.mapeadores.util.logging.LineLogsBuilder;
import net.mapeadores.util.request.RequestMap;


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

    public final static String COMMANDNAME = "FieldOptions";
    public final static String COMMANDKEY = "_ CRP-07";
    public final static String DEFAULTSPHERE_SUFFIX = "|defaultsphere";
    public final static String BLOCKDISPLAY_SUFFIX = "|blockdisplay";
    public final static String SUBFIELDDISPLAY_SUFFIX = "|subfielddisplay";
    public final static String CURRENCIES_SUFFIX = "|currencies";
    public final static String BASEURL_SUFFIX = "|baseurl";
    public final static String FIELDGENERATION_PARAMNAME = "fieldgeneration";
    public final static String ADDRESSFIELDARRAY_SUFFIX = "|addressfieldarray";
    public final static String GEOLOCALISATIONFIELD_PARAMNAME = "geolocalisationfield";
    public final static String LANGSCOPE_SUFFIX = "|langscope";
    public final static String LANGS_SUFFIX = "|langs";
    public final static String ALL_LANGSCOPE = "all";
    public final static String CONFIG_LANGSCOPE = "config";
    public final static String MULTILANG_LANGSCOPE = "mul";
    public final static String NOLINGUISTICCONTENT_LANGSCOPE = "zxx";
    public final static String LIST_LANGSCOPE = "list";
    private final static Lang[] MULTILANG_ARRAY = {Lang.build("mul")};
    private final static Lang[] NOLINGUISTICCONTENT_ARRAY = {Lang.build("zxx")};
    private Corpus corpus;
    private boolean initGeolocalisationField = false;
    private CorpusField geolocalisationField = null;
    private FieldGeneration fieldGeneration;


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

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

    @Override
    protected void doCommand() throws ErrorMessageException {
        boolean done = false;
        try (EditSession session = startEditSession(Domains.CORPUS, COMMANDNAME)) {
            CorpusMetadata corpusMetadata = corpus.getCorpusMetadata();
            CorpusMetadataEditor corpusMetadataEditor = session.getFichothequeEditor().getCorpusEditor(corpus).getCorpusMetadataEditor();
            if (fieldGeneration != null) {
                boolean fieldGenerationDone = corpusMetadataEditor.setFieldGeneration(fieldGeneration);
                if (fieldGenerationDone) {
                    done = true;
                }
            }
            if (initGeolocalisationField) {
                boolean geoDone;
                try {
                    geoDone = corpusMetadataEditor.setGeolocalisationField(geolocalisationField);
                    if (geoDone) {
                        done = true;
                    }
                } catch (IllegalArgumentException iae) {
                    throw new ImplementationException(iae);
                }
            }
            for (CorpusField corpusField : corpusMetadata.getPropList()) {
                if (setOptions(corpusMetadataEditor, corpusField)) {
                    done = true;
                }
            }
            for (CorpusField corpusField : corpusMetadata.getInfoList()) {
                if (setOptions(corpusMetadataEditor, corpusField)) {
                    done = true;
                }
            }
            CorpusField langCorpusField = corpusMetadata.getCorpusField(FieldKey.LANG);
            boolean langDone = setLangOption(corpusMetadataEditor, langCorpusField);
            if (langDone) {
                done = true;
            }
        }
        putResultObject(CORPUS_OBJ, corpus);
        if (done) {
            setDone("_ done.corpus.fieldoptions");
            bdfServer.getTransformationManager().clearDistTransformer();
        }
    }

    @Override
    protected void checkParameters() throws ErrorMessageException {
        corpus = requestHandler.getMandatoryCorpus();
        checkSubsetAdmin(corpus);
        CorpusMetadata corpusMetadata = corpus.getCorpusMetadata();
        if (requestHandler.hasParameter(FIELDGENERATION_PARAMNAME)) {
            String fieldGenerationRawString = requestHandler.getMandatoryParameter(FIELDGENERATION_PARAMNAME);
            LineLogsBuilder lineLogsBuilder = new LineLogsBuilder();
            fieldGeneration = FieldGenerationParser.parse(fieldGenerationRawString, lineLogsBuilder);
            if (lineLogsBuilder.hasMessage()) {
                CommandMessageBuilder commandMessageBuilder = CommandMessageBuilder.init();
                for (LineMessage lineMessage : lineLogsBuilder.toLineMessageList()) {
                    commandMessageBuilder.addMultiError(lineMessage);
                }
                throw BdfErrors.error(commandMessageBuilder, "_ error.list.options");
            }
        }
        if (!requestHandler.hasParameter(GEOLOCALISATIONFIELD_PARAMNAME)) {
            initGeolocalisationField = false;
        } else {
            initGeolocalisationField = true;
            String geolocalisationFieldString = requestHandler.getTrimedParameter(GEOLOCALISATIONFIELD_PARAMNAME);
            if (geolocalisationFieldString.isEmpty()) {
                geolocalisationField = null;
            } else {
                boolean done = false;
                try {
                    FieldKey fieldKey = FieldKey.parse(geolocalisationFieldString);
                    if (fieldKey.isProp()) {
                        CorpusField corpusField = corpusMetadata.getCorpusField(fieldKey);
                        if ((corpusField != null) && (corpusField.isType(CorpusField.GEOPOINT_FIELD))) {
                            done = true;
                            geolocalisationField = corpusField;
                        }
                    }
                } catch (java.text.ParseException pe) {
                }
                if (!done) {
                    throw BdfErrors.wrongParameterValue(GEOLOCALISATIONFIELD_PARAMNAME, geolocalisationFieldString);
                }
            }
        }
    }

    private boolean setOptions(CorpusMetadataEditor corpusMetadataEditor, CorpusField corpusField) throws ErrorMessageException {
        OptionEngine optionEngine = new OptionEngine(corpusMetadataEditor, corpusField);
        return optionEngine.run();
    }


    private boolean setLangOption(CorpusMetadataEditor corpusMetadataEditor, CorpusField corpusField) throws ErrorMessageException {
        OptionEngine optionEngine = new OptionEngine(corpusMetadataEditor, corpusField);
        return optionEngine.runLang();
    }


    private class OptionEngine {

        private final CorpusMetadataEditor corpusMetadataEditor;
        private final CorpusField corpusField;
        private boolean oneDone = false;

        private OptionEngine(CorpusMetadataEditor corpusMetadataEditor, CorpusField corpusField) {
            this.corpusMetadataEditor = corpusMetadataEditor;
            this.corpusField = corpusField;
        }

        private boolean run() throws ErrorMessageException {
            setDisplay();
            setSubfieldDisplay();
            setOption(FieldOptionConstants.DEFAULTSPHEREKEY_OPTION, DEFAULTSPHERE_SUFFIX);
            setOption(FieldOptionConstants.CURRENCYARRAY_OPTION, CURRENCIES_SUFFIX);
            setOption(FieldOptionConstants.ADDRESSFIELDARRAY_OPTION, ADDRESSFIELDARRAY_SUFFIX);
            setOption(FieldOptionConstants.BASEURL_OPTION, BASEURL_SUFFIX);
            return oneDone;
        }

        private boolean runLang() throws ErrorMessageException {
            String param = requestHandler.getTrimedParameter(corpusField.getFieldString() + LANGSCOPE_SUFFIX);
            String langScope;
            Lang[] langArray = null;
            switch (param) {
                case ALL_LANGSCOPE:
                    langScope = FieldOptionConstants.ALL_SCOPE;
                    break;
                case CONFIG_LANGSCOPE:
                    langScope = FieldOptionConstants.CONFIG_SCOPE;
                    break;
                case MULTILANG_LANGSCOPE:
                    langScope = FieldOptionConstants.LIST_SCOPE;
                    langArray = MULTILANG_ARRAY;
                    break;
                case NOLINGUISTICCONTENT_LANGSCOPE:
                    langScope = FieldOptionConstants.LIST_SCOPE;
                    langArray = NOLINGUISTICCONTENT_ARRAY;
                    break;
                case LIST_LANGSCOPE:
                    langScope = FieldOptionConstants.LIST_SCOPE;
                    langArray = (Lang[]) getOptionObject(FieldOptionConstants.LANGARRAY_OPTION, LANGS_SUFFIX);
                    if (langArray == null) {
                        langScope = FieldOptionConstants.CONFIG_SCOPE;
                    }
                    break;
                default:
                    return false;

            }
            if (langScope.equals(CorpusMetadataUtils.getDefaultLangScope(corpusField.getFieldKey()))) {
                langScope = null;
            }
            try {
                boolean done1 = corpusMetadataEditor.setFieldOption(corpusField, FieldOptionConstants.LANGSCOPE_OPTION, langScope);
                boolean done2 = corpusMetadataEditor.setFieldOption(corpusField, FieldOptionConstants.LANGARRAY_OPTION, langArray);
                if ((done1) || (done2)) {
                    oneDone = true;
                }
            } catch (FieldOptionException foe) {
                throw new ImplementationException(foe);
            }
            return oneDone;
        }

        private void setDisplay() {
            String optionName = FieldOptionConstants.INFODISPLAY_OPTION;
            if (!FieldOptionUtils.testFieldOption(optionName, corpusField)) {
                return;
            }
            String value = null;
            if (requestHandler.isTrue(corpusField.getFieldString() + BLOCKDISPLAY_SUFFIX)) {
                value = FieldOptionConstants.BLOCK_DISPLAY;
            }
            try {
                boolean done = corpusMetadataEditor.setFieldOption(corpusField, optionName, value);
                if (done) {
                    oneDone = true;
                }
            } catch (FieldOptionException foe) {
                throw new ImplementationException(foe);
            }
        }

        private void setSubfieldDisplay() {
            String optionName = FieldOptionConstants.SUBFIELDDISPLAY_OPTION;
            if (!FieldOptionUtils.testFieldOption(optionName, corpusField)) {
                return;
            }
            try {
                String value = (requestHandler.isTrue(corpusField.getFieldString() + SUBFIELDDISPLAY_SUFFIX)) ? "1" : null;
                boolean done = corpusMetadataEditor.setFieldOption(corpusField, optionName, value);
                if (done) {
                    oneDone = true;
                }
            } catch (FieldOptionException foe) {
                throw new ImplementationException(foe);
            }
        }


        private void setOption(String optionName, String paramSuffix) throws ErrorMessageException {
            if (!FieldOptionUtils.testFieldOption(optionName, corpusField)) {
                return;
            }
            Object optionObject = getOptionObject(optionName, paramSuffix);
            try {
                boolean done = corpusMetadataEditor.setFieldOption(corpusField, optionName, optionObject);
                if (done) {
                    oneDone = true;
                }
            } catch (FieldOptionException foe) {
                throw new ImplementationException(foe);
            }
        }

        private Object getOptionObject(String optionName, String paramSuffix) throws ErrorMessageException {
            String param = requestHandler.getTrimedParameter(corpusField.getFieldString() + paramSuffix);
            try {
                return FieldOptionUtils.parseOptionValue(optionName, param);
            } catch (FieldOptionException foe) {
                return null;
            }
        }

    }


}
