package com.atlassian.bitbucket.repository;

import com.atlassian.bitbucket.commit.Commit;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

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

/**
 * Describes a simple reference, which could be a {@link SimpleBranch branch}, {@link SimpleTag tag} or something
 * else altogether. This base type defines attributes that all references are expected to have in common:
 * <ul>
 *     <li>An ID: Typically, this will be a <i>fully-qualified</i> name in the SCM (such as "refs/heads/master")</li>
 *     <li>A display ID: Typically, this is a shortened (but still unique) name in the SCM (such as "master")</li>
 *     <li>A hash: This will be commit referred to</li>
 * </ul>
 */
public class SimpleRef extends SimpleMinimalRef implements Ref {

    private final String latestCommit;

    protected SimpleRef(@Nonnull AbstractRefBuilder<?, ?> builder, @Nonnull RefType refType) {
        super(builder, refType);

        latestCommit = builder.latestCommit;
    }

    @Nonnull
    @Override
    public String getLatestCommit() {
        return latestCommit;
    }

    /**
     * Builder to construct an {@link SimpleRef}.
     */
    public static class Builder extends AbstractRefBuilder<Builder, Ref> {

        private RefType type;

        public Builder() {
        }

        public Builder(Ref ref) {
            super(ref);

            type = ref.getType();
        }

        @Nonnull
        @Override
        public SimpleRef build() {
            return new SimpleRef(this, type);
        }

        @Nonnull
        public Builder type(@Nonnull RefType value) {
            type = checkNotNull(value, "type");

            return self();
        }

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

    @Nonnull
    @Override
    protected String fieldsToString() {
        return super.fieldsToString() + ", latestCommit=" + getLatestCommit();
    }

    /**
     * Common base class for creating builders which return objects derived from {@link SimpleRef}.
     *
     * @param <B> the builder's type, used to provide a fluent interface
     * @param <R> the ref's type, used to define the {@link #build() built} type
     */
    protected abstract static class AbstractRefBuilder<B extends AbstractRefBuilder<B, R>, R extends Ref>
            extends AbstractMinimalRefBuilder<B, R> {

        private String latestCommit;

        protected AbstractRefBuilder() {
        }

        protected AbstractRefBuilder(@Nonnull R ref) {
            super(ref);

            latestCommit = ref.getLatestCommit();
        }

        /**
         * @param value the {@link Commit#getId ID} of the commit at the tip of the ref
         * @return {@code this}
         */
        @Nonnull
        public B latestCommit(@Nullable String value) {
            latestCommit = value;

            return self();
        }
    }
}
