package nl.andrewlalis.simply_scheduled.schedule;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Optional;

/**
 * A schedule which repeatedly executes a task at a regular interval specified
 * as some integer multiple of a unit of time, such as 5 seconds, or 2 minutes.
 */
public class RepeatingSchedule implements Schedule {
	private final ChronoUnit unit;
	private final long multiple;
	private long elapsedIntervals = 0;
	private final Instant start;

	/**
	 * Constructs a new repeating schedule.
	 * @param unit The unit of time that the interval consists of.
	 * @param multiple The number of units of time that each interval consists of.
	 * @param start The starting point for this schedule.
	 */
	public RepeatingSchedule(ChronoUnit unit, long multiple, Instant start) {
		this.unit = unit;
		this.multiple = multiple;
		this.start = start;
	}

	/**
	 * Constructs a new repeating schedule, using {@link Instant#now()} as the
	 * starting point.
	 * @param unit The unit of time that the interval consists of.
	 * @param multiple The number of units of time that each interval consists of.
	 */
	public RepeatingSchedule(ChronoUnit unit, long multiple) {
		this(unit, multiple, Instant.now());
	}

	/**
	 * Computes the next execution time for a task. This keeps track of the last
	 * execution time, so that tasks repeat at an exact interval.
	 * @param referenceInstant The instant representing the current time.
	 * @return The next instant to execute the task at.
	 */
	@Override
	public Optional<Instant> getNextExecutionTime(Instant referenceInstant) {
		return Optional.of(this.start.plus(elapsedIntervals * multiple, unit));
	}

	@Override
	public void markExecuted(Instant instant) {
		this.elapsedIntervals++;
	}
}