/*
* This file is part of BukkitBridge.
*
* Copyright (c) 2012 Spout LLC <http://www.spout.org/>
* BukkitBridge is licensed under the GNU General Public License.
*
* BukkitBridge is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* BukkitBridge is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.spout.bridge.bukkit.scheduler;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.scheduler.BukkitWorker;
import org.spout.api.scheduler.TaskPriority;
import org.spout.bridge.BukkitBridgePlugin;
public class BridgeScheduler implements BukkitScheduler {
private final BukkitBridgePlugin plugin;
public BridgeScheduler(BukkitBridgePlugin plugin) {
this.plugin = plugin;
}
@Override
public <T> Future<T> callSyncMethod(Plugin plugin, Callable<T> task) {
FutureRunnable<T> futureRun = new FutureRunnable<T>(task);
this.plugin.getEngine().getScheduler().scheduleSyncDelayedTask(plugin, futureRun);
return futureRun;
}
@Override
public void cancelAllTasks() {
plugin.getEngine().getScheduler().cancelAllTasks();
}
@Override
public void cancelTask(int taskId) {
plugin.getEngine().getScheduler().cancelTask(taskId);
}
@Override
public void cancelTasks(Plugin plugin) {
this.plugin.getEngine().getScheduler().cancelTasks(plugin);
}
@Override
public List<BukkitWorker> getActiveWorkers() {
throw new UnsupportedOperationException();
}
@Override
public List<BukkitTask> getPendingTasks() {
throw new UnsupportedOperationException();
}
@Override
public boolean isCurrentlyRunning(int taskId) {
throw new UnsupportedOperationException();
}
@Override
public boolean isQueued(int taskId) {
return plugin.getEngine().getScheduler().isQueued(taskId);
}
@Override
public int scheduleAsyncDelayedTask(Plugin plugin, Runnable task) {
return this.plugin.getEngine().getScheduler().scheduleAsyncTask(plugin, task).getTaskId();
}
@Override
public int scheduleAsyncDelayedTask(Plugin plugin, Runnable task, long delay) {
return this.plugin.getEngine().getScheduler().scheduleAsyncDelayedTask(plugin, task, delay * 50L, TaskPriority.NORMAL).getTaskId();
}
@Override
public int scheduleAsyncRepeatingTask(Plugin plugin, Runnable task, long delay, long period) {
if (period > 0) {
return scheduleAsyncDelayedTask(plugin, new RepeatingRunnable(plugin, task, period), delay);
} else {
return scheduleAsyncDelayedTask(plugin, task, delay);
}
}
@Override
public int scheduleSyncDelayedTask(Plugin plugin, Runnable task) {
return scheduleSyncDelayedTask(plugin, task, 0);
}
@Override
public int scheduleSyncDelayedTask(Plugin plugin, Runnable task, long delay) {
return scheduleSyncRepeatingTask(plugin, task, delay, -1L);
}
@Override
public int scheduleSyncRepeatingTask(Plugin plugin, Runnable task, long delay, long period) {
return this.plugin.getEngine().getScheduler().scheduleSyncRepeatingTask(plugin, task, delay * 50L, (period > 0 ? period * 50L : period), TaskPriority.NORMAL).getTaskId();
}
private static class FutureRunnable<T> implements Runnable, Future<T> {
private final Callable<T> future;
private volatile T result;
private volatile ExecutionException ex;
private volatile boolean cancelled = false;
private final AtomicBoolean done = new AtomicBoolean(false);
FutureRunnable(Callable<T> future) {
this.future = future;
}
@Override
public void run() {
if (cancelled) {
return;
}
try {
result = future.call();
} catch (Exception e) {
ex = new ExecutionException(e);
}
done.set(true);
done.notify();
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
if (!cancelled) {
cancelled = true;
return !done.get();
}
return false;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public boolean isDone() {
return done.get();
}
@Override
public T get() throws InterruptedException, ExecutionException {
if (!done.get()) {
done.wait();
}
if (ex != null) {
throw ex;
} else {
return result;
}
}
@Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
if (!done.get()) {
done.wait(unit.toMillis(timeout));
}
if (done.get()) {
return get();
}
throw new TimeoutException();
}
}
@Override
public BukkitTask runTask(Plugin arg0, Runnable arg1) throws IllegalArgumentException {
throw new UnsupportedOperationException();
}
@Override
public BukkitTask runTaskAsynchronously(Plugin arg0, Runnable arg1) throws IllegalArgumentException {
throw new UnsupportedOperationException();
}
@Override
public BukkitTask runTaskLater(Plugin arg0, Runnable arg1, long arg2) throws IllegalArgumentException {
throw new UnsupportedOperationException();
}
@Override
public BukkitTask runTaskLaterAsynchronously(Plugin arg0, Runnable arg1, long arg2) throws IllegalArgumentException {
throw new UnsupportedOperationException();
}
@Override
public BukkitTask runTaskTimer(Plugin arg0, Runnable arg1, long arg2, long arg3) throws IllegalArgumentException {
throw new UnsupportedOperationException();
}
@Override
public BukkitTask runTaskTimerAsynchronously(Plugin arg0, Runnable arg1, long arg2, long arg3) throws IllegalArgumentException {
throw new UnsupportedOperationException();
}
private static class RepeatingRunnable implements Runnable {
final Runnable r;
final Plugin p;
final long period;
RepeatingRunnable(Plugin p, Runnable r, long period) {
this.r = r;
this.p = p;
this.period = period;
}
@Override
public void run() {
try {
r.run();
} finally {
Bukkit.getServer().getScheduler().scheduleAsyncRepeatingTask(p, r, 1, period - 1);
}
}
}
}