package com.atlassian.bitbucket.scm;

import javax.annotation.Nonnull;
import java.util.concurrent.Future;

/**
 * Wraps an operation which may be run {@link #start() asynchronously} or {@link #synchronous() synchronously}. When run
 * asynchronously, execution and idle timeouts must be applied by the calling code; they are not built in.
 * <p>
 * When the operation completes, it will return an object of type {@code T}. If {@code T} is {@code Void}, the operation
 * will return {@code null} on completion. Typically this means the operation uses some form of callback, allowing the
 * caller to process the results as they are produced rather than returning them on completion.
 *
 * @param <T> the type of value that the operation will produce.
 */
public interface AsyncCommand<T> {

    /**
     * Starts the operation and returns a {@code Future}, which can be used to cancel the operation or block until it
     * has finished.
     *
     * @return a {@code Future} instance for the operation result
     * @throws IllegalStateException if this {@code AsyncCommand} has been transformed to {@link #synchronous()}
     */
    @Nonnull
    Future<T> start();

    /**
     * Transforms this {@code AsyncCommand} into a {@link Command} which may be called synchronously. Timeouts may be
     * set on the returned {@link Command} before it is called.
     * <p>
     * Once an {@code AsyncCommand} has been transformed for synchronous use, it may no longer be used
     * {@link #start() asynchronously}.
     *
     * @return a {@link Command} for running the operation embodied by this {@code AsyncCommand} synchronously
     */
    @Nonnull
    Command<T> synchronous();
}
