package org.implab.gradle.common.exec;

import java.util.function.Consumer;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.implab.gradle.common.utils.Values;

/** Command builder interface, used to specify the executable and parameters */
@NonNullByDefault
public interface CommandBuilder {

    /** Sets the executable, the parameters are left intact. */
    CommandBuilder executable(String executable);

    /**
     * Sets the specified executable and parameters, old executable and parameters
     * are discarded.
     */
    default CommandBuilder commandLine(String executable, String... args) {
        return executable(executable)
                .arguments(args);
    }

    /**
     * Sets the specified executable and parameters, old executable and parameters
     * are discarded.
     * 
     * @param command The command line. Must contain at least one element
     *                (executable).
     * 
     */
    default CommandBuilder commandLine(Iterable<? extends String> command) {
        var iterator = command.iterator();

        // set executable
        executable(Values.take(iterator).orElseThrow());
        // cleat arguments
        arguments();

        // set new arguments
        while (iterator.hasNext())
            addArguments(iterator.next());

        return this;
    }

    default Consumer<Boolean> flag(String name) {
        return f -> {
            if (f)
                addArguments(name);
        };
    }

    default Consumer<String> param(String name) {
        return v -> {
            if (v != null && v.length() > 0)
                addArguments(name, v);
        };
    }

    /** Adds the specified arguments to this builder */
    CommandBuilder addArguments(String... args);

    default CommandBuilder addArguments(Iterable<String> args) {
        for (String arg : args)
            addArguments(arg);

        return this;
    }

    /** Replaces arguments in the builder with the specified one. */
    default CommandBuilder arguments(String... args) {
        return arguments(Values.iterable(args));
    }

    /** Replaces arguments in the builder with the specified one. */
    CommandBuilder arguments(Iterable<String> args);

    default CommandBuilder from(CommandSpec commandSpec) {
        return executable(commandSpec.executable())
                .arguments(commandSpec.arguments());
    }
}
