package com.supaham.commons.bukkit; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import org.bukkit.plugin.Plugin; import java.util.Collection; import java.util.Iterator; import java.util.NoSuchElementException; import javax.annotation.Nonnull; /** * Represents a delayed iterator using {@link TickerTask}. Similar to an iterator, this class * iterates over a {@link Collection} which is supplied through a {@link Supplier}, at a set * interval. * <p /> * Since this functionality is delayed, each iteration may be accessed through * {@link #onRun(Object)} and once the iterator is done, {@link #onDone()} is called, which by * default, is an empty implementation. * <p /> * Although this class extends {@link TickerTask}, delay is not supported as it is unnecessary. The * iterator may be controlled through {@link TickerTask}'s state changing methods. * <p /> * Although this class has the word iterator in it, it is anything but {@link Iterator}. Since * the whole iteration is delayed, the implementation of {@link Iterator} would be invalid for the * following reasons: this class does not support element removals (write), only read. And the * {@link Iterator} requires {@link Iterator#next()}, which does exist in this class * ({@link #next()}), but is NOT recommended to be used as it may cause instability issues across * implementations, but is there for whatever reason someone might wish to use it for. * * @see #DelayedIterator(Plugin, Supplier, long) * @since 0.2 */ public abstract class DelayedIterator<T> extends TickerTask { private final Supplier<Collection<T>> supplier; private Iterator<T> iterator; /** * Constructs a new {@link DelayedIterator} instance with a {@link Plugin} as the owner, a * {@link Supplier}, and 1 as the interval delay, iterating every tick. * * @param plugin plugin to handle this iterator * @param supplier suuplier to supply the collection to iterate over */ public DelayedIterator(@Nonnull Plugin plugin, @Nonnull Supplier<Collection<T>> supplier) { this(plugin, supplier, 1); } /** * Constructs a new {@link DelayedIterator} instance with a {@link Plugin} as the owner, a * {@link Supplier}, and a set interval (in ticks) delay per iteration. * * @param plugin plugin to handle this iterator * @param supplier suuplier to supply the collection to iterate over * @param interval interval (in ticks) between each iteration */ public DelayedIterator(@Nonnull Plugin plugin, @Nonnull Supplier<Collection<T>> supplier, long interval) { super(plugin, 0, interval); this.supplier = Preconditions.checkNotNull(supplier, "supplier cannot be null."); } /** * This method is called per iteration of an object. * * @param t current element in the iterator */ public abstract void onRun(T t); /** * This method is called when the whole iteration is finished. */ public void onDone() {} @Override public final void run() { if (this.iterator == null) { this.iterator = this.supplier.get().iterator(); } if (this.iterator.hasNext()) { onRun(this.iterator.next()); } if (!this.iterator.hasNext()) { // We're done. stop(); onDone(); } } @Override public boolean stop() { boolean b = super.stop(); this.iterator = null; return b; } /** * Returns true if the iteration has more elements. (In other words, returns true if * {@link #next} would return an element rather than throwing an exception.) * * @return whether the iteration has more elements * * @see {@link Iterator#hasNext()} */ public boolean hasNext() { Iterator<T> it = this.iterator; return it != null && it.hasNext(); } /** * Returns the next element in the iteration. * <p /> * <b>NOTE: This method triggers {@link #onRun(Object)} assuming no exception is thrown, * please use with caution.</b> * * @return the next element in the iteration * * @throws NoSuchElementException if the iteration has no more elements */ public T next() throws NoSuchElementException { T next = this.iterator.next(); onRun(next); return next; } /** * Gets the collection {@link Supplier} of this delayed iterator. * * @return supplier of a collection */ public Supplier<Collection<T>> getSupplier() { return supplier; } }