package cz.xtf.core.waiting;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DurationFormatUtils;

import java.util.concurrent.TimeUnit;

/**
 * An object that waits on condition to be met.
 */
public interface Waiter {
	long DEFAULT_INTERVAL = 1_000L;
	long DEFAULT_TIMEOUT = 60_000;

	/**
	 * Sets waiter timeout after which waiters stops waiting. Timeout is logged
	 * in case of setting {@link Waiter#logPoint(LogPoint)} to anything else then
	 * {@link LogPoint#NONE}
	 *
	 * @param millis timeout in milliseconds
	 * @return this
	 */
	Waiter timeout(long millis);

	/**
	 * Sets waiter timeout after which waiters stops waiting. Timeout is logged
	 * in case of setting {@link Waiter#logPoint(LogPoint)} to anything else then
	 * {@link LogPoint#NONE}
	 *
	 * @param timeUnit timeUnit that is converts time {@code t} to milliseconds
	 * @param t timeout in {@code timeUnit}
	 * @return this
	 */
	Waiter timeout(TimeUnit timeUnit, long t);

	/**
	 * Sets waiter conditions check interval.
	 *
	 * @param millis interval in milliseconds
	 * @return this
	 */
	Waiter interval(long millis);

	/**
	 * Sets waiter conditions check interval.
	 *
	 * @param timeUnit timeUnit that is converts time {@code t} to milliseconds
	 * @param t interval in milliseconds
	 * @return this
	 */
	Waiter interval(TimeUnit timeUnit, long t);

	/**
	 * Sets waiting reason.
	 *
	 * @param reason what the waiters what upon.
	 * @return this
	 */
	Waiter reason(String reason);

	/**
	 * Sets waiters logPoints.
	 * @see LogPoint
	 *
	 * @param logPoint what points of waiting should be logged.
	 * @return this
	 */
	Waiter logPoint(LogPoint logPoint);

	/**
	 * Waits till condition is met.
	 *
	 * @return true if wanted condition was met, false if unwanted state condition was met
	 */
	boolean waitFor();

	/**
	 * Waits till condition is met. This method calls {@link Waiter#waitFor} and false result or declared exception is rethrown as AssertionError.
	 *
	 * @see Waiter#waitFor
	 *
	 * @throws AssertionError in case that {@link Waiter#waitFor} returns false or throws declared exception
	 */
	default void waitForOrAssertFail() {
		waitForOrAssertFail("Waiter met failure condition.");
	}

	/**
	 * Waits till condition is met. This method calls {@link Waiter#waitFor} and false result or declared exception is rethrown as AssertionError.
	 *
	 * @see Waiter#waitFor
	 *
	 * @throws AssertionError in case that {@link Waiter#waitFor} returns false or throws declared exception
	 */
	default void waitForOrAssertFail(String failMessage) {
		try {
			if(!waitFor()) throw new AssertionError(failMessage);
		} catch (WaiterException e) {
			throw new AssertionError("Waiter has timed out (" + e.getMessage() + ")!");
		}
	}

	/**
	 * Object for configurable conditional logging of waiting.
	 */
	@Slf4j
	enum LogPoint {
		NONE, START, END, BOTH;

		/**
		 * Logs start of waiting. Its time and reason in case of {@link LogPoint#START} or {@link LogPoint#BOTH}
		 *
		 * @param reason reason of waiting
		 * @param millis waiting timeout on condition
		 */
		public void logStart(String reason, long millis) {
			if(this.equals(START) || this.equals(BOTH)) log.info("Waiting up to {}. Reason: {}", DurationFormatUtils.formatDurationWords(millis, true, true), reason);
		}

		/**
		 * Logs end of waiting. Its time and reason in case of {@link LogPoint#END} or {@link LogPoint#BOTH}
		 *
		 * @param reason reason of waiting
		 * @param millis waiting timeout on condition
		 */
		public void logEnd(String reason, long millis) {
			if(this.equals(END) || this.equals(BOTH)) log.info("Finished waiting after {}. Reason: {}", DurationFormatUtils.formatDurationWords(millis, true, true), reason);
		}
	}
}

@@ -1796,951 +1796,80 @@
 %0A%09 *
-/%0A%09boolean waitFor();%0A%0A%09/**%0A%09 * Waits till condition is met. This method calls %7B@link Waiter#waitFor%7D and false result or declared exception is rethrown as AssertionError.%0A%09 *%0A%09 * @see Waiter#waitFor%0A%09 *%0A%09 * @throws AssertionError in case that %7B@link Waiter#waitFor%7D returns false or throws declared exception%0A%09 */%0A%09default void waitForOrAssertFail() %7B%0A%09%09waitForOrAssertFail(%22Waiter met failure condition.%22);%0A%09%7D%0A%0A%09/**%0A%09 * Waits till condition is met. This method calls %7B@link Waiter#waitFor%7D and false result or declared exception is rethrown as AssertionError.
+%0A%09 * @throws WaiterException in case of timeout
 %0A%09 *
+/
 %0A%09
- * @see Waiter#waitFor%0A%09 *%0A%09 * @throws AssertionError in case that %7B@link Waiter#waitFor%7D returns false or throws declared exception%0A%09 */%0A%09default void waitForOrAssertFail(String failMessage) %7B%0A%09%09try %7B%0A%09%09%09if(!waitFor()) throw new AssertionError(failMessage);%0A%09%09%7D catch (WaiterException e) %7B%0A%09%09%09throw new AssertionError(%22Waiter has timed out (%22 + e.getMessage() + %22)!%22);%0A%09%09%7D%0A%09%7D
+boolean waitFor();
 %0A%0A%09/

Remove waitForOrAssertFail() in favor of waitFor()