package com.atlassian.bitbucket.scm;

import com.atlassian.bitbucket.i18n.KeyedMessage;

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

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

/**
 * A simple implementation of {@link ScmStatus} which provides static factory methods for constructing
 * {@link #available(KeyedMessage) available} and {@link #unavailable(KeyedMessage) unavailable} statuses.
 * The status is immutable after construction.
 */
public class SimpleScmStatus implements ScmStatus {

    private final boolean available;
    private final KeyedMessage message;

    private SimpleScmStatus(boolean available, KeyedMessage message) {
        this.available = available;
        this.message = message;
    }

    /**
     * Retrieves the status message for the SCM.
     * <p>
     * If the SCM is {@link #isAvailable() available}, its status message may be {@code null}. Otherwise, if it is
     * unavailable, the message <i>must</i> be provided.
     *
     * @return a brief message describing the SCM's status, potentially {@code null} if the SCM is available
     */
    @Override
    public KeyedMessage getMessage() {
        return message;
    }

    /**
     * Retrieves a flag indicating whether the SCM is available or some internal issue prevents its use.
     * <p>
     * Available SCMs are not required to provide a {@link #getMessage() message}, but they are <i>encouraged</i> to
     * do so. Such a message might contain the version of the SCM being used, or the version of the plugin itself.
     * If the SCM is unavailable, a message is <i>required</i> to be provided indicating why the SCM is unavailable.
     *
     * @return {@code true} if the SCM is available; otherwise, {@code false} if an internal issue prevents the SCM
     *         from being used
     */
    @Override
    public boolean isAvailable() {
        return available;
    }

    /**
     * Constructs a new {@code SimpleScmStatus} indicating the SCM is available. The provided message may be
     * {@code null}, though it is encouraged for a message describing the SCM be provided instead.
     *
     * @param message the status message, or {@code null}
     * @return a {@code SimpleScmStatus} which will return {@code true} from {@link #isAvailable()}
     */
    public static SimpleScmStatus available(@Nullable KeyedMessage message) {
        return new SimpleScmStatus(true, message);
    }

    /**
     * Constructs a new {@code SimpleScmStatus} indicating that the SCM is not available. The provided message is
     * <i>required</i>, and should describe the issue or issues affecting the SCM to make it unavailable.
     *
     * @param message a status message describing why the SCM is unavailable
     * @return a {@code SimpleScmStatus} which will return {@code false} from {@link #isAvailable()}
     * @throws NullPointerException if the provided {@code message} is {@code null}
     */
    public static SimpleScmStatus unavailable(@Nonnull KeyedMessage message) {
        return new SimpleScmStatus(false, checkNotNull(message, "message"));
    }
}
