package com.atlassian.bitbucket.scm.git.command;

import com.atlassian.bitbucket.scm.Command;
import com.atlassian.bitbucket.scm.CommandOutputHandler;
import com.atlassian.bitbucket.scm.ScmCommandBuilder;
import org.slf4j.Logger;

import javax.annotation.Nonnull;

/**
 * A simple extension of {@code BaseOutputHandler} which reads any bytes on the {@code OutputStream} and logs them
 * as a UTF-8 decoded {@code String}.
 * <p>
 * If output is produced, it will be logged at debug level. The reasoning behind the level used is that this handler
 * is intended to be used only with commands that produce no output, or trivial output; any command that produces
 * useful output should use an {@code OutputHandler} implementation that parses that output in a meaningful way. If
 * the command does not produce any output, a simple trace statement to that effect will be logged.
 * <p>
 * {@link ScmCommandBuilder#build(CommandOutputHandler) Building a
 * command} requires the output handler to be provided, so, unfortunately, the only way to provide the {@link Command}
 * to this handler is after the fact. <b>{@link #setCommand(Command)} must be invoked to set the command before the
 * command is {@link Command#call() called}.</b>
 */
public class LoggingCommandOutputHandler extends AbstractLoggingCommandOutputHandler<Void> {

    /**
     * Constructs a new {@code LoggingCommandOutputHandler} which will retrieve its {@code Logger} based on the
     * class of the {@link Command} that is {@link #setCommand(Command) set}.
     */
    public LoggingCommandOutputHandler() {
    }

    /**
     * Constructs a new {@code LoggingCommandOutputHandler} which will write to the specified {@code Logger}, rather
     * than retrieving one based on the {@link Command}'s class.
     *
     * @param log the logger to write to
     * @throws NullPointerException if the provided {@code log} is {@code null}
     */
    public LoggingCommandOutputHandler(@Nonnull Logger log) {
        super(log);
    }

    /**
     * {@link GitScmCommandBuilder#build(CommandOutputHandler) Builds} and {@link Command#call() calls} the
     * provided builder using a {@code LoggingOutputHandler}. Since output is logged, nothing is returned.
     *
     * @param builder the prepared builder to {@link GitScmCommandBuilder#build(CommandOutputHandler) build} and
     *                {@link Command#call() call}
     */
    public static void call(@Nonnull GitScmCommandBuilder builder) {
        LoggingCommandOutputHandler outputHandler = new LoggingCommandOutputHandler();
        outputHandler.setCommand(builder.build(outputHandler))
                .call();
    }

    /**
     * Output is directly logged, not accumulated or parsed, so this always returns {@code null}.
     *
     * @return {@code null}
     */
    @Override
    public Void getOutput() {
        return null;
    }

}
