package com.atlassian.bitbucket.mesh.git.builder.diff;

import com.atlassian.bitbucket.mesh.git.builder.GitProcessBuilder;
import org.apache.commons.lang3.StringUtils;

import javax.annotation.Nonnull;

public class DefaultGitDiffTreeBuilder
        extends AbstractGitDiffCoreBuilder<GitDiffTreeBuilder>
        implements GitDiffTreeBuilder {

    private boolean always;
    private String format;
    private boolean merges;
    private boolean recursive;
    private boolean root;
    private boolean stdin;

    public DefaultGitDiffTreeBuilder(GitProcessBuilder builder) {
        super(builder.command("diff-tree"));
    }

    @Nonnull
    @Override
    public GitDiffTreeBuilder always(boolean value) {
        always = value;

        return self();
    }

    @Nonnull
    @Override
    public GitDiffTreeBuilder format(String value) {
        format = value;

        return self();
    }

    @Nonnull
    @Override
    public DefaultGitDiffTreeBuilder merges(boolean value) {
        merges = value;

        return self();
    }

    @Nonnull
    @Override
    public DefaultGitDiffTreeBuilder recursive(boolean value) {
        recursive = value;

        return self();
    }

    @Nonnull
    @Override
    public DefaultGitDiffTreeBuilder root(boolean value) {
        root = value;

        return self();
    }

    @Nonnull
    @Override
    public DefaultGitDiffTreeBuilder stdin(boolean value) {
        stdin = value;

        return self();
    }

    @Override
    protected void applyArguments() {
        super.applyArguments();

        if (merges) {
            builder.argument("-m");
        }
        if (recursive) {
            builder.argument("-r");
        }

        if (always) {
            //--always ensures that we get a diff-tree for each of the parents, even when there are no changes
            //this allows us to match the diff-tree to the parent.
            builder.argument("--always");
        }
        //Context is handled here rather than in the base class because the null case is treated differently for diff
        //than for diff-tree.
        if (context != null) {
            builder.argument("-U" + context); //Unified diff with explicit context
        }
        if (StringUtils.isNotBlank(format)) {
            builder.argument("--format=" + format);
        }
        if (root) {
            //For root commits, we can only provide a commit ID and no parents (because there are none). However,
            //by default git diff-tree doesn't display anything for root commits. Adding --root shows root commits
            //as a big add.
            builder.argument("--root");
        }

        if (stdin) {
            //If an input handler was provided, enable input handling on diff-tree
            builder.argument("--stdin");
        } else {
            if (StringUtils.isNotBlank(ancestor)) {
                //If a ancestor is given, we don't need -m; even for merge commits, diff-tree will show a diff to the
                //provided parent revision
                builder.commitish(ancestor);
            }
            builder.commitish(rev);
        }

        applyPaths();
    }

    @Nonnull
    @Override
    protected DefaultGitDiffTreeBuilder self() {
        return this;
    }
}
