package net.sourceforge.pain;
import net.sourceforge.pain.data.*;
import net.sourceforge.pain.util.*;
/**
* Codebase internal clocks (pulse) impl.
*/
public final class Pulse implements Runnable {
public static final int PULSE_PER_SCD = 10;
public static final int PULSE_PER_MIN = PULSE_PER_SCD * 60;
private final Object monitor = new Object();
private final int msec_in_pulse = 1000 / PULSE_PER_SCD;
private final Listeners active = new Listeners();
private final Listeners toRemove = new Listeners();
private boolean started = false;
private CodebasePulse codebasePulse = null;
private int pulse = 0;
Pulse() {
}
public void addListener(PulseListener l) {
Log.debug("adding listener:" + l);
active.add(l);
}
public void removeListener(PulseListener l) {
Log.debug("adding to remove listener:" + l);
toRemove.add(l);
}
public void run() {
codebasePulse = Codebase.getCodebaseData().getCodebasePulse();
pulse = codebasePulse.getPulse();
Log.debug("CodebasePulser start:" + pulse);
started = true;
long nextPulseTime = System.currentTimeMillis() + msec_in_pulse;
long timeToWait;
while (started) {
try {
timeToWait = nextPulseTime - System.currentTimeMillis();
if (timeToWait > 10) {
synchronized (monitor) {
monitor.wait(timeToWait);
}
}
nextPulseTime = System.currentTimeMillis() + msec_in_pulse;
if (toRemove.size > 0) {
processRemoved();
}
pulse++;
codebasePulse.setPulse(pulse);
final PulseListener[] data = active.data;
final int size = active.size;
for (int i = 0; i < size; i++) {
try {
data[i].pulse(pulse);
} catch (Exception e) {
Log.error(e);
}
}
} catch (Exception e) {
Log.error(e);
} catch (Error e) {
Log.error("CRITICAL BUG! ERROR THROWN!", e);
// new Thread(this).start();
// break;
}
}
Codebase.shutdown();
}
private synchronized void processRemoved() {
for (int i = 0; i < toRemove.size; i++) {
active.remove(toRemove.data[i]);
}
toRemove.clear();
}
/**
* @return current time in pulse
*/
public int currentTime() {
return pulse;
}
/**
* the way to stop codebase.
*/
public void stopPulse() {
started = false;
}
static final class Listeners {
PulseListener[] data = new PulseListener[10];
int size = 0;
synchronized void add(PulseListener l) {
if (size == data.length) {
PulseListener[] newData = new PulseListener[size * 2];
System.arraycopy(data, 0, newData, 0, size);
data = newData;
}
data[size] = l;
size++;
}
synchronized void remove(PulseListener l) {
for (int i = 0; i < size; i++) {
if (data[i] == l) {
int numMoved = size - i - 1;
if (numMoved > 0) {
System.arraycopy(data, i + 1, data, i, numMoved);
}
data[size] = null;
size--;
}
}
}
synchronized void clear() {
for (int i = 0; i < size; i++) {
data[i] = null;
}
size = 0;
}
}
}