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

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

import javax.annotation.Nonnull;
import java.util.LinkedHashSet;
import java.util.Set;

import static java.util.Objects.requireNonNull;

public class DefaultGitLsTreeBuilder extends AbstractGitProcessBuilder<GitLsTreeBuilder> implements GitLsTreeBuilder {

    private final Set<String> paths;

    private boolean nullTerminated;
    private boolean recursive;
    private boolean sizes;
    private String tree;

    public DefaultGitLsTreeBuilder(GitProcessBuilder builder) {
        super(builder.command("ls-tree"));

        paths = new LinkedHashSet<>();
    }

    @Nonnull
    @Override
    public GitLsTreeBuilder clearPaths() {
        paths.clear();

        return self();
    }

    @Nonnull
    @Override
    public GitLsTreeBuilder nullTerminated(boolean value) {
        nullTerminated = value;

        return self();
    }

    @Nonnull
    @Override
    public DefaultGitLsTreeBuilder path(String path) {
        addIfNotBlank(paths, path);

        return self();
    }

    @Nonnull
    @Override
    public GitLsTreeBuilder paths(String value, String... values) {
        addIfNotBlank(paths, value, values);

        return self();
    }

    @Nonnull
    @Override
    public GitLsTreeBuilder paths(Iterable<String> values) {
        addIfNotBlank(paths, values);

        return self();
    }

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

        return self();
    }

    @Nonnull
    @Override
    public GitLsTreeBuilder sizes(boolean value) {
        sizes = value;

        return self();
    }

    @Nonnull
    @Override
    public DefaultGitLsTreeBuilder tree(@Nonnull String value) {
        requireNonNull(value, "tree");

        if (value.indexOf(':') == -1) {
            //If the tree doesn't contain a :, treat it as a SHA or a tag ID (tags can be applied to trees
            //directly, not just commits) and trim both leading and trailing whitespace. This will reject
            //values that are only whitespace
            tree = requireNonBlank(value, "tree");
        } else {
            //If the object ID contains a :, trim leading whitespace but not trailing. The value after
            //the : is treated as a path, and some projects use paths with trailing whitespace
            tree = StringUtils.stripStart(value, null);
        }

        return self();
    }

    @Nonnull
    @Override
    public DefaultGitLsTreeBuilder tree(@Nonnull String rev, String file) {
        return tree(requireNonBlank(rev, "rev") + ":" + StringUtils.defaultString(file));
    }

    @Override
    protected void applyArguments() {
        if (nullTerminated) {
            builder.argument("-z");
        }
        if (recursive) {
            builder.argument("-r");
        }
        if (sizes) {
            builder.argument("-l");
        }

        builder.treeish(tree) //treeish(String) does not trim; trimming is handled by tree(...) above
                .argument("--");
        paths.forEach(builder::rawArgument); //Pass paths verbatim
    }

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