package rmblworx.tools.timey;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import rmblworx.tools.timey.event.CountdownExpiredEvent;
import rmblworx.tools.timey.event.TimeyEvent;
import rmblworx.tools.timey.event.TimeyEventDispatcher;
import rmblworx.tools.timey.event.TimeyEventListener;
import rmblworx.tools.timey.exception.NullArgumentException;
import rmblworx.tools.timey.exception.ValueMinimumArgumentException;
import rmblworx.tools.timey.vo.TimeDescriptor;
/*
* Copyright 2014-2015 Christian Raue
* MIT License http://opensource.org/licenses/mit-license.php
*/
/**
* Implementierung eines einfachen Timer's zum ausführen einer Zeitmessung.
*
* @author mmatthies
*/
class SimpleCountdown implements ICountdownTimer, TimeyEventListener, ApplicationContextAware {
/**
* Maßzahl für die Ausfuehrungsverzögerung des Threads.
*/
private static final int DELAY = 1;
/**
* Beschreibt die Größe des vom Scheduler verwalteten Threadpools.
*/
private static final int THREAD_POOL_SIZE = 1;
/**
* Referenz auf das Future-Objekt der aktuellen Zeitmessung.
*/
private ScheduledFuture<?> countdownFuture;
/**
* Scheduler wird verwendet um die Threads zu verwalten und wiederholt
* ausführen zu lassen.
*/
private ScheduledExecutorService scheduler;
/**
* Spring-Kontext.
*/
private ApplicationContext springContext;
/**
* Wertobjekt das die Zeit für die GUI kapselt und liefert.
*/
private TimeDescriptor timeDescriptor;
/**
* Die bereits vergangene Zeit in Millisekunden.
*/
private long timePassed = 0;
/**
* Erweiterter Konstruktor.
*
* @param timeyEventDispatcher
* Referenz auf den Event-Dispatcher
*/
public SimpleCountdown(final TimeyEventDispatcher timeyEventDispatcher) {
timeyEventDispatcher.addEventListener(this);
}
@Override
public void handleEvent(final TimeyEvent timeyEvent) {
if (timeyEvent instanceof CountdownExpiredEvent) {
this.stopCountdown();
}
}
/**
* Gibt Auskunft darüber ob der Timer läuft.
*
* @return true wenn er läuft sonst false
*/
Boolean isRunning() {
return !this.countdownFuture.isDone();
}
@Override
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
this.springContext = applicationContext;
}
@Override
public Boolean setCountdownTime(final TimeDescriptor descriptor) {
if (null == descriptor) {
throw new NullArgumentException();
}
this.timeDescriptor = descriptor;
return Boolean.TRUE;
}
@Override
public TimeDescriptor startCountdown(final int delayPerThread, final TimeUnit timeUnit) {
if (delayPerThread < 1) {
throw new ValueMinimumArgumentException();
} else if (timeUnit == null) {
throw new NullArgumentException();
}
this.scheduler = Executors.newScheduledThreadPool(THREAD_POOL_SIZE);
final CountdownRunnable countdown = (CountdownRunnable) this.springContext.getBean("countdownRunnable",
this.timeDescriptor, Long.valueOf(this.timePassed));
this.countdownFuture = this.scheduler.scheduleAtFixedRate(countdown, 0, delayPerThread, timeUnit);
return this.timeDescriptor;
}
@Override
public Boolean stopCountdown() {
if (this.scheduler != null && !this.scheduler.isTerminated()) {
final TaskStopper stopRunnable = new TaskStopper(this.scheduler, this.countdownFuture);
this.scheduler.schedule(stopRunnable, DELAY, TimeUnit.MILLISECONDS);
}
this.timePassed = this.timeDescriptor.getMilliSeconds();
return Boolean.TRUE;
}
}