package com.atlassian.bitbucket.scm;

import javax.annotation.Nonnull;
import javax.annotation.concurrent.NotThreadSafe;

/**
 * Augments the {@link CommandBuilder} with SCM-related properties, still supporting creating free-form commands.
 * SCM command builders are specifically intended to be used with binaries such as {@code git}, {@code hg} or
 * {@code svn}, which provide a variety of different commands, each accepting different arguments and input and
 * producing different output, to carry out their functionality.
 */
@NotThreadSafe
public interface ScmCommandBuilder<B extends ScmCommandBuilder<B>> extends CommandBuilder<B> {

    /**
     * Builds a {@link Command} which, when {@link Command#call() executed}, will provide output to the provided
     * {@code outputHandler} for processing.
     * <p>
     * If no {@link #command(String) command} has been set, the first argument is assumed to be the command. For
     * SCMs with unified binaries that have no default command, if no command has been set and no arguments have
     * been provided, implementations <i>may</i> throw an exception rather than executing the process which, most
     * likely, will simply print usage information and exit.
     *
     * @param outputHandler the handler to receive and process output from the command as it executes
     * @return the built command
     * @throws IllegalStateException if no command has been set and no arguments were provided
     * @throws NullPointerException if the provided {@code outputHandler} is {@code null}
     */
    @Nonnull
    @Override
    <T> Command<T> build(@Nonnull CommandOutputHandler<T> outputHandler);

    /**
     * Sets the command to execute.
     * <p>
     * Most SCMs, such as {@code git}, {@code hg} or {@code svn}, have a single unified binary which expects the
     * command to run as its first argument. This property separates that special command argument from the others,
     * allowing other arguments to be {@link #clearArguments() cleared} without clearing the command as well.
     *
     * @param command the SCM command to execute
     * @return {@code this}
     * @throws IllegalArgumentException if the provided {@code command} is empty or blank
     * @throws NullPointerException if the provided {@code command} is {@code null}
     */
    @Nonnull
    B command(@Nonnull String command);
}
