/* UtilLib - Copyright (c) 2019-2021 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 net.mapeadores.util.exec;

import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.mapeadores.util.logging.ErrorMessageException;
import net.mapeadores.util.text.StringUtils;


/**
 *
 * @author Vincent Calame
 */
public class ArgsBuilder {

    private final ArgsDef argsDef;
    private final Set<String> valueSet = new LinkedHashSet<String>();
    private final Map<Character, String> characterParameterMap = new HashMap<Character, String>();
    private final Map<String, String> parameterMap = new HashMap<String, String>();
    private CommandDef commandDef;

    public ArgsBuilder(ArgsDef argsDef) {
        this.argsDef = argsDef;
    }

    public ArgsBuilder setCommandDef(CommandDef commandDef) {
        this.commandDef = commandDef;
        return this;
    }

    public ArgsBuilder addValues(String... values) {
        for (String value : values) {
            if ((value != null) && (value.length() > 0)) {
                valueSet.add(value);
            }
        }
        return this;
    }

    public ArgsBuilder addCharacterParameter(char character) {
        characterParameterMap.put(character, "");
        addParameter(Character.toString(character));
        return this;
    }

    public ArgsBuilder addCharacterParameter(char character, String value) {
        characterParameterMap.put(character, value);
        addParameter(Character.toString(character), value);
        return this;
    }

    public ArgsBuilder addParameter(String paramName) {
        parameterMap.put(paramName, "");
        return this;
    }

    public ArgsBuilder addParameter(String paramName, String paramValue) {
        parameterMap.put(paramName, paramValue);
        return this;
    }

    public Args toArgs() throws ErrorMessageException {
        if (commandDef == null) {
            throw new ErrorMessageException("_ error.empty.args.command");
        }
        for (CommandDef.UsedParameter usedParameter : commandDef.getUsedParameterList()) {
            if (usedParameter.isMandatory()) {
                if (!characterParameterMap.containsKey(usedParameter.getLetter())) {
                    throw new ErrorMessageException("_ error.empty.args.mandatoryparameter", "-" + usedParameter.getLetter());
                }
            }
        }
        List<String> valueList = StringUtils.toList(valueSet);
        Map<Character, String> finalCharacterParameterMap = new HashMap<Character, String>(characterParameterMap);
        Map<String, String> finalParameterMap = new HashMap<String, String>(parameterMap);
        return new InternalArgs(commandDef, finalCharacterParameterMap, finalParameterMap, valueList);
    }

    public static ArgsBuilder init(ArgsDef argsDef) {
        return new ArgsBuilder(argsDef);
    }


    private static class InternalArgs implements Args {

        private final CommandDef commandDef;
        private final Map<Character, String> characterParameterMap;
        private final Map<String, String> parameterMap;
        private final List<String> valueList;

        private InternalArgs(CommandDef commandDef, Map<Character, String> characterParameterMap, Map<String, String> parameterMap, List<String> valueList) {
            this.commandDef = commandDef;
            this.characterParameterMap = characterParameterMap;
            this.parameterMap = parameterMap;
            this.valueList = valueList;
        }

        @Override
        public CommandDef getCommandDef() {
            return commandDef;
        }

        @Override
        public boolean containsParameter(char parameterChar) {
            return characterParameterMap.containsKey(parameterChar);
        }

        @Override
        public String getParameterValue(char parameterChar) {
            return characterParameterMap.get(parameterChar);
        }

        @Override
        public boolean containsParameter(String parameterName) {
            return parameterMap.containsKey(parameterName);
        }

        @Override
        public String getParameterValue(String parameterName) {
            return parameterMap.get(parameterName);
        }

        @Override
        public List<String> getValueList() {
            return valueList;
        }

    }

}
