/*
* This file is part of NucleusFramework for Bukkit, licensed under the MIT License (MIT).
*
* Copyright (c) JCThePants (www.jcwhatever.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.jcwhatever.nucleus.utils.performance.queued;
import com.jcwhatever.nucleus.managed.scheduler.Scheduler;
import com.jcwhatever.nucleus.managed.scheduler.IScheduledTask;
import com.jcwhatever.nucleus.managed.scheduler.TaskHandler;
import org.bukkit.plugin.Plugin;
/**
* Abstract implementation of a {@link QueueTask} designed to make it easier to
* perform iterative tasks.
*
* <p>Iterative tasks can be broken up into segments which are performed like individual
* tasks; run in consecutive order with a delay between each segment run.</p>
*/
public abstract class IterationTask extends QueueTask {
private int _start, _end, _increment, _segmentSize;
private int _current, _segmentsCompleted, _iterations;
private boolean _lessThan;
private final Object _sync = new Object();
private IScheduledTask _task;
/**
* Constructor. Initializes iteration variables.
*
* @param plugin The owning plugin
* @param segmentSize The number of times to iterate before pausing
* @param start The number to start iteration at
* @param end The number+1 to end iteration at
* @param increment The increment per iteration. Use negative numbers if start is larger than end value
*/
public IterationTask(Plugin plugin, TaskConcurrency concurrency,
int segmentSize, int start, int end, int increment) {
super(plugin, concurrency);
_current = _start;
_start = start;
_end = end;
_increment = increment;
_segmentSize = segmentSize;
_lessThan = _start < _end || _start == _end && _increment > 0;
}
/**
* Get the start index
*/
public final int getStart() {
return _start;
}
/**
* Get the index that will be stopped at.
*/
public final int getEnd() {
return _end - 1;
}
/**
* Get the increment per iteration
*/
public final int getIncrement() {
return _increment;
}
/**
* Get the number of iteration segments completed.
*/
public final int getSegmentsCompleted() {
return _segmentsCompleted;
}
/**
* Get the number of iterations completed.
*/
public final int getIterations() {
return _iterations;
}
@Override
protected final void onRun() {
onIterateBegin();
if (_task != null)
_task.cancel();
_task = Scheduler.runTaskRepeat(getPlugin(), 1, 1, new Worker());
}
/**
* Invoked at each iteration.
*
* @param index The current iteration index
*/
protected abstract void onIterateItem(int index);
/**
* Invoked when the task begins.
*/
protected void onIterateBegin() {}
/**
* Invoked before the first iteration of a segment.
*
* <p>Intended for optional override.</p>
*
* @param index The current iteration index.
*/
protected void onSegmentStart(int index) {}
/**
* Invoked after the last iteration of a segment.
*
* <p>Intended for optional override.</p>
*
* @param index The current iteration index.
*/
protected void onSegmentEnd(int index) {}
/**
* Invoked just before the task finishes.
*
* <p>Intended for optional override.</p>
*/
protected void onPreComplete() {}
// the worker responsible for iterating
private class Worker extends TaskHandler {
@Override
public void run() {
if (isEnded()) {
cancelTask();
return;
}
synchronized (_sync) {
boolean isStart = true;
int completed = 0;
for (int i = _current; _lessThan ? i < _end : i > _end; i += _increment) {
// determine if this is the start of the segment
if (isStart) {
onSegmentStart(i);
}
// determine if this is the end of the segment
if (_segmentSize > 0 && completed >= _segmentSize) {
_segmentsCompleted ++;
_current = i;
onSegmentEnd(i);
// end segment
return;
}
isStart = false;
onIterateItem(i);
if (!isRunning()) {
cancelTask();
return;
}
_iterations++;
completed++;
}
}
onPreComplete();
cancelTask();
}
}
@Override
protected void onCancel() {
complete();
}
}