/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.util.ui;
import com.intellij.concurrency.JobScheduler;
import com.intellij.openapi.Disposable;
import org.jetbrains.annotations.NonNls;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* @deprecated use {@link JobScheduler#getScheduler()} instead
*/
public abstract class Timer implements Disposable, Runnable {
private final int mySpan;
private final String myName;
private volatile boolean myTakeInitialDelay = true;
private Exception myInterruptedException;
private final Object LOCK = new Object();
private ScheduledFuture<?> myFuture;
private enum TimerState {startup, initialSleep, running, suspended, restarting, pausing, disposed}
private TimerState myState = TimerState.startup;
private int myPauseTime;
public Timer(@NonNls String name, int span) {
myName = name;
mySpan = span;
}
public void setTakeInitialDelay(final boolean take) {
myTakeInitialDelay = take;
}
public final int getSpan() {
return mySpan;
}
public final void start() {
synchronized (LOCK) {
if (isRunning() || isDisposed()) return;
myState = TimerState.startup;
queue(this, 0);
}
}
@Override
public void run() {
synchronized (LOCK) {
switch (myState) {
case startup:
startup();
break;
case restarting:
startup();
break;
case initialSleep:
myState = TimerState.running;
fireAndReschedule();
break;
case running:
fireAndReschedule();
break;
case suspended:
break;
case pausing:
myState = TimerState.running;
queue(this, myPauseTime);
break;
case disposed:
break;
}
}
}
private void startup() {
myState = TimerState.initialSleep;
if (myTakeInitialDelay) {
queue(this, mySpan);
} else {
fireAndReschedule();
}
}
private void fireAndReschedule() {
try {
onTimer();
}
catch (InterruptedException e) {
myInterruptedException = e;
suspend();
return;
}
queue(this, getSpan());
}
protected abstract void onTimer() throws InterruptedException;
public final void suspend() {
synchronized (LOCK) {
if (isDisposed() || !isRunning()) return;
myState = TimerState.suspended;
}
}
public final void delay(int length) {
synchronized (LOCK) {
if (isDisposed() || !isRunning()) return;
myState = TimerState.pausing;
queue(this, length);
}
}
public final void resume() {
synchronized (LOCK) {
if (isDisposed() || isRunning()) return;
myState = TimerState.running;
queue(this, 0);
}
}
@Override
public final void dispose() {
synchronized (LOCK) {
myState = TimerState.disposed;
}
}
public void restart() {
synchronized (LOCK) {
myState = TimerState.restarting;
queue(this, 0);
}
}
public boolean isRunning() {
synchronized (LOCK) {
return myState == TimerState.running || myState == TimerState.initialSleep || myState == TimerState.restarting;
}
}
public boolean isDisposed() {
synchronized (LOCK) {
return myState == TimerState.disposed;
}
}
@SuppressWarnings({"HardCodedStringLiteral"})
public String toString() {
return "Timer=" + myName;
}
private void setFuture(ScheduledFuture<?> schedule) {
myFuture = schedule;
}
public ScheduledFuture<?> getFuture() {
return myFuture;
}
private static void queue(Timer timer, int span) {
final ScheduledFuture<?> future = timer.getFuture();
if (future != null) {
future.cancel(true);
}
timer.setFuture(JobScheduler.getScheduler().schedule(timer, span, TimeUnit.MILLISECONDS));
}
}