001package fr.aumgn.bukkitutils.timer;
002
003import java.util.concurrent.TimeUnit;
004
005import org.bukkit.Bukkit;
006import org.bukkit.ChatColor;
007import org.bukkit.plugin.Plugin;
008
009import com.google.common.base.Stopwatch;
010
011/**
012 * A timer class which display time according
013 * to the delays specified in the {@link TimerConfig}
014 * using the abstract method {@link #sendTimeMessage(String)}.
015 */
016public abstract class Timer implements Runnable {
017
018    private static final int TICKS_PER_SECONDS = 20;
019
020    private final Plugin plugin;
021    private final int majorDelay;
022    private final int minorDelay;
023    private final String format;
024    private final String endMessage;
025    private Runnable runnable;
026
027    private int remainingTime;
028
029    private int taskId;
030    private Stopwatch watch;
031    private int currentDelay;
032    private int pauseDelay;
033
034    private Timer(boolean dummy, Plugin plugin, TimerConfig config, int seconds) {
035        this.plugin = plugin;
036        this.majorDelay = config.getMajorDuration();
037        this.minorDelay = config.getMinorDuration();
038        this.format = config.getFormat();
039        this.endMessage = config.getEndMessage();
040
041        this.taskId = -1;
042        this.remainingTime = seconds;
043
044        this.currentDelay = 0;
045    }
046
047    public Timer(Plugin plugin, TimerConfig config, int seconds, Runnable runnable) {
048        this(true, plugin, config, seconds);
049        this.runnable = runnable;
050    }
051
052    public Timer(Plugin plugin, TimerConfig config, int seconds) {
053        this(false, plugin, config, seconds);
054        this.runnable = new Runnable() {
055            public void run() {
056                onFinish();
057            }
058        };
059    }
060
061    private void scheduleAndPrintTime(int delay) {
062        long minutes = TimeUnit.SECONDS.toMinutes(remainingTime);
063        String msg = String.format(format, minutes, remainingTime % 60);
064        sendTimeMessage(getCurrentColor() + msg);
065        schedule(delay);
066    }
067
068    private void schedule(int delay) {
069        currentDelay = delay;
070        watch = new Stopwatch();
071        watch.start();
072        taskId = Bukkit.getScheduler().scheduleSyncDelayedTask(
073                plugin, this, (long) delay * TICKS_PER_SECONDS);
074    }
075
076    private ChatColor getCurrentColor() {
077        if (remainingTime >= majorDelay) {
078            return ChatColor.YELLOW;
079        } else if (remainingTime >= minorDelay){
080            return ChatColor.GOLD;
081        } else {
082            return ChatColor.RED;
083        }
084    }
085
086    public int getRemainingTime() {
087        return remainingTime;
088    }
089
090    public void start() {
091        remainingTime -= currentDelay;
092        if (remainingTime > majorDelay) {
093            schedule(majorDelay);
094        } else if (remainingTime > minorDelay) {
095            schedule(minorDelay);
096        } else if (remainingTime > 0) {
097            schedule(1);
098        } else {
099            runnable.run();
100        }
101    }
102
103    @Override
104    public void run() {
105        remainingTime -= currentDelay;
106        if (remainingTime > majorDelay) {
107            scheduleAndPrintTime(majorDelay);
108        } else if (remainingTime > minorDelay) {
109            scheduleAndPrintTime(minorDelay);
110        } else if (remainingTime > 0) {
111            scheduleAndPrintTime(1);
112        } else {
113            runnable.run();
114        }
115    }
116
117    public void cancel() {
118        if (taskId != -1) {
119            Bukkit.getScheduler().cancelTask(taskId);
120            taskId = -1;
121        }
122    }
123
124    public void pause() {
125        cancel();
126        watch.stop();
127        pauseDelay = (int) watch.elapsedTime(TimeUnit.SECONDS);
128        remainingTime -= pauseDelay;
129    }
130
131    public void resume() {
132        int delay = currentDelay - pauseDelay;
133        if (delay > 0) {
134            scheduleAndPrintTime(delay);
135        } else {
136            runnable.run();
137        }
138    }
139
140    public void onFinish() {
141        sendTimeMessage(endMessage);
142    }
143
144    public abstract void sendTimeMessage(String string);
145}