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

import com.atlassian.bitbucket.mesh.rpc.v1.RpcRevListWalk;

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

import static java.util.Objects.requireNonNull;

/**
 * Enumerates the possible traversal (walk) modes for {@code git rev-list}, controlling use of the {@code --do-walk}
 * and {@code --no-walk} flags.
 */
public enum GitRevListWalk {

    /**
     * Apply {@code git rev-list}'s default behaviour. For Git 1.x and 2.x, this is a synonym for {@link #DO_WALK}.
     */
    DEFAULT,
    /**
     * Walk commit ancestors.
     */
    DO_WALK("--do-walk"),
    /**
     * Do not walk commit ancestry; instead, only return the explicitly-requested commits. Commits are <i>sorted</i>
     * when using this flag, so, while only requested commits will be returned, they may not be returned in the same
     * order they were requested in. To maintain the order, use {@link #NO_WALK_UNSORTED --no-walk=unsorted} instead.
     * <p>
     * Note: When using this mode, <i>no excludes can be provided</i>; processing excludes requires walking ancestry.
     */
    NO_WALK("--no-walk"),
    /**
     * A variant of {@link #NO_WALK --no-walk} introduced in Git 1.8.0 which returns the commits in the same order
     * they were requested in where {@code --no-walk} sorts them by date.
     * <p>
     * Note: When using this mode, <i>no excludes can be provided</i>; processing excludes requires walking ancestry.
     */
    NO_WALK_UNSORTED("--no-walk=unsorted");

    private final String flag;

    GitRevListWalk() {
        flag = null;
    }

    GitRevListWalk(String flag) {
        this.flag = flag;
    }

    @Nonnull
    public static GitRevListWalk fromRpc(@Nonnull RpcRevListWalk rpc) {
        switch (requireNonNull(rpc, "rpc")) {
            case WALK_DO:
                return DO_WALK;
            case WALK_NO:
                return NO_WALK;
            case WALK_NO_UNSORTED:
                return NO_WALK_UNSORTED;
            default:
                return DEFAULT;
        }
    }

    @Nullable
    public String getFlag() {
        return flag;
    }

    public boolean isFlagged() {
        return flag != null;
    }
}
