package com.atlassian.bitbucket.mesh.transaction;

import com.google.common.collect.ImmutableSet;

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

import static java.util.Objects.requireNonNull;

public enum TransactionState {

    ROLLED_BACK(70, true, true),
    ROLLING_BACK(60, false, true, ROLLED_BACK),
    COMMITTED(50, true, false),
    COMMITTING(40, false, false, ROLLED_BACK, COMMITTED),
    PREPARED(30, false, false, ROLLING_BACK, ROLLED_BACK, COMMITTING),
    PREPARING(20, false, false, PREPARED, ROLLING_BACK, ROLLED_BACK, COMMITTING),
    INITIAL(10, false, false, PREPARING, PREPARED, ROLLING_BACK, ROLLED_BACK);

    private final boolean finished;
    private final int id;
    private final Set<TransactionState> nextStates;
    private final boolean rollbackOnly;

    TransactionState(int id, boolean finished, boolean rollbackOnly, TransactionState... nextStates) {
        this.finished = finished;
        this.id = id;
        this.nextStates = ImmutableSet.copyOf(nextStates);
        this.rollbackOnly = rollbackOnly;
    }

    @Nonnull
    public static TransactionState fromId(int id) {
        for (TransactionState value : values()) {
            if (id == value.id) {
                return value;
            }
        }
        throw new IllegalArgumentException("Unknown TransactionState ID " + id);
    }

    public boolean canTransitionTo(@Nonnull TransactionState state) {
        return nextStates.contains(requireNonNull(state, "state"));
    }

    public boolean isFinished() {
        return finished;
    }

    public boolean isRollbackOnly() {
        return rollbackOnly;
    }

    public int getId() {
        return id;
    }
}
