package com.atlassian.bitbucket.commit.graph;

import com.atlassian.bitbucket.commit.MinimalCommit;
import com.atlassian.bitbucket.util.BuilderSupport;
import com.google.common.collect.ImmutableSet;

import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.Objects;

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

/**
 * An immutable implementation of {@link CommitGraphNode}.
 */
public class SimpleCommitGraphNode implements CommitGraphNode {

    private final MinimalCommit commit;
    private final Collection<MinimalCommit> parents;

    private SimpleCommitGraphNode(MinimalCommit commit, Collection<MinimalCommit> parents) {
        this.commit = commit;
        this.parents = parents;
    }

    @Nonnull
    @Override
    public MinimalCommit getCommit() {
        return commit;
    }

    @Nonnull
    @Override
    public Collection<MinimalCommit> getParents() {
        return parents;
    }


    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof SimpleCommitGraphNode)) {
            return false;
        }

        SimpleCommitGraphNode that = (SimpleCommitGraphNode) o;
        return commit.equals(that.getCommit()) && parents.equals(that.parents);
    }

    @Override
    public int hashCode() {
        return 31 * commit.hashCode() + parents.hashCode();
    }

    @Override
    public String toString() {
        return "SimpleCommitGraphNode{" +
                "commit=" + commit +
                ", parents=" + parents +
                '}';
    }

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

        private final ImmutableSet.Builder<MinimalCommit> parents = ImmutableSet.builder();

        private MinimalCommit commit;

        public Builder() {
        }

        public Builder(@Nonnull SimpleCommitGraphNode value) {
            commit(checkNotNull(value, "node").getCommit());
            parents(value.getParents());
        }

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

            return new SimpleCommitGraphNode(commit, parents.build());
        }

        public Builder commit(@Nonnull MinimalCommit value) {
            this.commit = checkNotNull(value, "value");

            return this;
        }

        public Builder parents(@Nonnull Iterable<MinimalCommit> values) {
            addIf(Objects::nonNull, parents, values);

            return this;
        }

        public Builder parents(@Nonnull MinimalCommit value, @Nonnull MinimalCommit... values) {
            addIf(Objects::nonNull, parents, value, values);

            return this;
        }
    }
}
