package com.atlassian.bitbucket.commit.graph;

import com.atlassian.bitbucket.commit.CommitService;
import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.util.BuilderSupport;
import com.google.common.collect.ImmutableSet;

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

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

/**
 * A request for a traversal of the commit graph starting with the {@link Builder#include included} commits and
 * excluding any subgraph starting with {@link Builder#exclude excluded} commits.
 *
 * @see CommitService#traverse(TraversalRequest, TraversalCallback)
 */
public class TraversalRequest {

    private final Set<String> excludes;
    private final Set<String> includes;
    private final Repository repository;

    private TraversalRequest(Set<String> excludes, Set<String> includes, Repository repository) {
        this.excludes = excludes;
        this.includes = includes;
        this.repository = repository;
    }

    /**
     * @return the commit IDs starting any subgraphs to be excluded from traversal
     */
    @Nonnull
    public Set<String> getExcludes() {
        return excludes;
    }

    /**
     * @return the commit IDs starting the subgraph to be traversed. If empty the whole commit graph
     * will be traversed.
     */
    @Nonnull
    public Set<String> getIncludes() {
        return includes;
    }

    /**
     * @return the repository on which the commit graph traversal will be performed
     */
    @Nonnull
    public Repository getRepository() {
        return repository;
    }

    /**
     * A builder for a {@link TraversalRequest}.
     */
    public static class Builder extends BuilderSupport {

        private final ImmutableSet.Builder<String> excludes = ImmutableSet.builder();
        private final ImmutableSet.Builder<String> includes = ImmutableSet.builder();
        private Repository repository;

        public TraversalRequest build() {
            checkState(repository != null, "A repository must be supplied");

            return new TraversalRequest(excludes.build(), includes.build(), repository);
        }

        public Builder exclude(@Nonnull Iterable<String> values) {
            addIf(NOT_BLANK, excludes, values);

            return this;
        }

        public Builder exclude(@Nonnull String value, @Nonnull String... values) {
            addIf(NOT_BLANK, excludes, value, values);

            return this;
        }

        public Builder include(@Nonnull Iterable<String> values) {
            addIf(NOT_BLANK, includes, values);

            return this;
        }

        public Builder include(@Nonnull String value, @Nonnull String... values) {
            addIf(NOT_BLANK, includes, value, values);

            return this;
        }

        public Builder repository(@Nonnull Repository value) {
            repository = checkNotNull(value, "repository");

            return this;
        }
    }
}
