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


/**
 *
 * @author Vincent Calame
 */
public final class ArgsParser {

    private final ArgsDef argsDef;
    private final ArgsBuilder argsBuilder;
    private final String[] args;
    private final int argsLength;
    private boolean commandDone;

    private ArgsParser(ArgsDef argsDef, ArgsBuilder argsBuilder, String[] args) {
        this.argsDef = argsDef;
        this.argsBuilder = argsBuilder;
        this.args = args;
        this.argsLength = args.length;
    }

    public static Args parse(String[] args, ArgsDef argsDef) throws ErrorMessageException {
        ArgsBuilder argsBuilder = new ArgsBuilder(argsDef);
        ArgsParser parser = new ArgsParser(argsDef, argsBuilder, args);
        parser.parseAt(0);
        return argsBuilder.toArgs();
    }

    private void parseAt(int index) throws ErrorMessageException {
        if (index >= argsLength) {
            return;
        }
        String value = args[index];
        if (value.startsWith("--")) {
            int idx = value.indexOf('=');
            if (idx == -1) {
                argsBuilder.addParameter(value.substring(2));
            } else {
                argsBuilder.addParameter(value.substring(2, idx), value.substring(idx + 1));
            }
        } else if (!value.startsWith("-")) {
            if (!commandDone) {
                CommandDef commandDef = argsDef.getCommandDef(value);
                if (commandDef == null) {
                    throw new ErrorMessageException("_ error.unknown.args.command", value);
                } else {
                    argsBuilder.setCommandDef(commandDef);
                    commandDone = true;
                }
            } else {
                argsBuilder.addValues(value);
            }
        } else {
            int valueLength = value.length();
            switch (valueLength) {
                case 1:
                    throw new ErrorMessageException("_ error.unsupported.args.alonedash");
                case 2:
                    index = testUniqueParameter(index, value.charAt(1));
                    break;
                default:
                    for (int i = 1; i < valueLength; i++) {
                        char parameterChar = value.charAt(i);
                        ParameterDef parameterDef = argsDef.getParameterDef(parameterChar);
                        if (parameterDef == null) {
                            throw new ErrorMessageException("_ error.unknown.args.parameter", "-" + parameterChar);
                        }
                        if (parameterDef.requireValue()) {
                            throw new ErrorMessageException("_ error.empty.args.parametervalue", "-" + parameterChar);
                        }
                        argsBuilder.addCharacterParameter(parameterDef.getLetter());
                    }

            }
        }
        parseAt(index + 1);
    }

    private int testUniqueParameter(int index, char parameterChar) throws ErrorMessageException {
        ParameterDef parameterDef = argsDef.getParameterDef(parameterChar);
        if (parameterDef == null) {
            throw new ErrorMessageException("_ error.unknown.args.parameter", "-" + parameterChar);
        }
        if (parameterDef.requireValue()) {
            if (index == (argsLength - 1)) {
                throw new ErrorMessageException("_ error.empty.args.parametervalue", "-" + parameterChar);
            }
            String value = args[index + 1];
            if (value.startsWith("-")) {
                throw new ErrorMessageException("_ error.empty.args.parametervalue", "-" + parameterChar);
            }
            if (!parameterDef.isValidValue(value)) {
                throw new ErrorMessageException("_ error.wrong.args.parametervalue", "-" + parameterChar, value);
            }
            argsBuilder.addCharacterParameter(parameterDef.getLetter(), value);
            return index + 1;
        } else {
            argsBuilder.addCharacterParameter(parameterDef.getLetter());
            return index;
        }
    }

}
