package org.shoushitsu.util.asyncservice;

import java.util.function.Consumer;

/**
 * <p>Interface for asynchronous service callbacks.</p>
 *
 * <p>You specify a callback when submitting a computation task to an asynchronous service
 * (via a {@link org.shoushitsu.util.asyncservice.TaskSink}).
 * One of the callback methods will be called to report the result of the computation.</p>
 *
 * <p><strong>NB! Mind the thread safety</strong> when writing callbacks! Any of the callback's methods may be called
 * on any thread, including but not limited to a worker thread of the asynchronous service, or a special callback
 * handling thread used by the particular service, or even the thread that submits the computation to the service.</p>
 *
 * @param <R> the type of the result of an asynchronous computation that will be reported to this callback.
 */
public interface Callback<R> {

	/**
	 * Called when a computation completes successfully.
	 *
	 * @param data the result of the computation.
	 */
	void success(R data);

	/**
	 * Called if a computation throws an exception. This includes {@link java.lang.InterruptedException}s,
	 * if the computation supports interrupts (which it should).
	 *
	 * @param exception the exception thrown by the computation.
	 */
	void failure(Throwable exception);

	/**
	 * <p>Called if the asynchronous service was closed before the computation could finish.</p>
	 *
	 * <p>Note that the computation might still be running when this method is invoked.
	 * In such a case, regardless of whether the computation succeeds or fails,
	 * the corresponding callback methods <em>will not</em> be called.</p>
	 */
	void terminated();


	/**
	 * A factory method that makes a callback out of three functional objects (for use with lambdas).
	 *
	 * @param onSuccess will be called if the asynchronous task {@linkplain #success(Object) succeeds}.
	 * @param onFailure will be called if the asynchronous task {@linkplain #failure(Throwable) fails}.
	 * @param onTermination will be called if the asynchronous service is {@linkplain #terminated() terminated}
	 * before the task is finished.
	 *
	 * @param <R> the type of the result of the asynchronous computation.
	 *
	 * @return a callback object that calls one of the provided functions depending on the situation.
	 */
	static <R> Callback<R> madeOf(Consumer<R> onSuccess, Consumer<Throwable> onFailure, Runnable onTermination) {
		return new Callback<R>() {
			@Override
			public void success(R data) {
				onSuccess.accept(data);
			}

			@Override
			public void failure(Throwable exception) {
				onFailure.accept(exception);
			}

			@Override
			public void terminated() {
				onTermination.run();
			}
		};
	}

}

@@ -1767,16 +1767,106 @@
 mbdas).%0A
+%09 * Any of the parameters can be %7B@code null%7D; that is equivalent to a do-nothing method.%0A
 %09 *%0A%09 * 
@@ -2570,24 +2570,54 @@
 s(R data) %7B%0A
+%09%09%09%09if (onSuccess != null) %7B%0A%09
 %09%09%09%09onSucces
@@ -2632,16 +2632,22 @@
 (data);%0A
+%09%09%09%09%7D%0A
 %09%09%09%7D%0A%0A%09%09
@@ -2699,24 +2699,54 @@
 xception) %7B%0A
+%09%09%09%09if (onFailure != null) %7B%0A%09
 %09%09%09%09onFailur
@@ -2766,16 +2766,22 @@
 ption);%0A
+%09%09%09%09%7D%0A
 %09%09%09%7D%0A%0A%09%09
@@ -2817,24 +2817,58 @@
 minated() %7B%0A
+%09%09%09%09if (onTermination != null) %7B%0A%09
 %09%09%09%09onTermin
@@ -2880,16 +2880,22 @@
 .run();%0A
+%09%09%09%09%7D%0A
 %09%09%09%7D%0A%09%09%7D

handle nulls in Callback.madeOf() parameters