/* UtilLib - Copyright (c) 2019 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.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;


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

    private final SortedMap<String, CommandDef> commandDefMap = new TreeMap<String, CommandDef>();
    private final SortedMap<Character, InternalParameterDef> parameterDefMap = new TreeMap<Character, InternalParameterDef>();

    public ArgsDefBuilder() {

    }

    public ArgsDefBuilder addCommandDef(CommandDef commandDef) {
        commandDefMap.put(commandDef.getName(), commandDef);
        return this;
    }

    public ArgsDefBuilder addParameter(char character, String titleLocKey, boolean requireValue) {
        parameterDefMap.put(character, new InternalParameterDef(character, titleLocKey, requireValue, null));
        return this;
    }

    public ArgsDefBuilder addParameter(char character, String titleLocKey, Collection<String> values) {
        Set<String> set = new LinkedHashSet<String>(values);
        parameterDefMap.put(character, new InternalParameterDef(character, titleLocKey, true, set));
        return this;
    }

    public static ArgsDefBuilder init() {
        return new ArgsDefBuilder();
    }

    public ArgsDef toArgsDef() {
        List<ParameterDef> parameterDefList = ArgsUtils.wrap(parameterDefMap.values().toArray(new ParameterDef[parameterDefMap.size()]));
        Map<Character, ParameterDef> finalParameterDefMap = new HashMap<Character, ParameterDef>(parameterDefMap);
        List<CommandDef> commandDefList = ArgsUtils.wrap(commandDefMap.values().toArray(new CommandDef[commandDefMap.size()]));
        Map<String, CommandDef> finalCommandDefMap = new HashMap<String, CommandDef>(commandDefMap);
        return new InternalArgsDef(parameterDefList, finalParameterDefMap, commandDefList, finalCommandDefMap);
    }


    private static class InternalArgsDef implements ArgsDef {

        private final List<ParameterDef> parameterDefList;
        private final Map<Character, ParameterDef> parameterDefMap;
        private final List<CommandDef> commandDefList;
        private final Map<String, CommandDef> commandDefMap;

        private InternalArgsDef(List<ParameterDef> parameterDefList, Map<Character, ParameterDef> parameterDefMap, List<CommandDef> commandDefList, Map<String, CommandDef> commandDefMap) {
            this.parameterDefList = parameterDefList;
            this.parameterDefMap = parameterDefMap;
            this.commandDefList = commandDefList;
            this.commandDefMap = commandDefMap;
        }

        @Override
        public ParameterDef getParameterDef(char letter) {
            return parameterDefMap.get(letter);
        }

        @Override
        public List<ParameterDef> getParameterDefList() {
            return parameterDefList;
        }

        @Override
        public CommandDef getCommandDef(String commandName) {
            return commandDefMap.get(commandName);
        }

        @Override
        public List<CommandDef> getCommandDefList() {
            return commandDefList;
        }

    }


    private static class InternalParameterDef implements ParameterDef {

        private final char letter;
        private final String titleLocKey;
        private final boolean requireValue;
        private final Set<String> valueSet;

        private InternalParameterDef(char letter, String titleLocKey, boolean requireValue, Set<String> valueSet) {
            this.letter = letter;
            this.titleLocKey = titleLocKey;
            this.requireValue = requireValue;
            this.valueSet = valueSet;
        }

        @Override
        public char getLetter() {
            return letter;
        }

        @Override
        public String getTitleLocKey() {
            return titleLocKey;
        }

        @Override
        public boolean requireValue() {
            return requireValue;
        }

        @Override
        public boolean isValidValue(String value) {
            if (!requireValue) {
                return false;
            } else if (valueSet == null) {
                return true;
            } else {
                return valueSet.contains(value);
            }
        }

    }


}
