/
codebase/
codebase/area/
codebase/doc/
codebase/etc/
codebase/src/net/sourceforge/pain/data/trigger/
codebase/src/net/sourceforge/pain/logic/
codebase/src/net/sourceforge/pain/logic/affect/
codebase/src/net/sourceforge/pain/logic/event/
codebase/src/net/sourceforge/pain/logic/event/deploy/
codebase/src/net/sourceforge/pain/logic/event/guitool/
codebase/src/net/sourceforge/pain/logic/event/guitool/event/
codebase/src/net/sourceforge/pain/logic/fn/util/
codebase/src/net/sourceforge/pain/logic/trigger/
codebase/src/net/sourceforge/pain/logic/trigger/impl/
codebase/src/net/sourceforge/pain/network/console/
codebase/src/net/sourceforge/pain/network/console/telnet/
codebase/src/net/sourceforge/pain/network/guitool/
codebase/src/net/sourceforge/pain/plugin/
codebase/src/net/sourceforge/pain/plugin/command/
codebase/src/net/sourceforge/pain/plugin/reset/
codebase/src/net/sourceforge/pain/plugin/shutdown/
codebase/src/net/sourceforge/pain/plugin/social/
codebase/src/net/sourceforge/pain/util/
db/doc/javadoc/resources/
db/src/net/sourceforge/pain/util/
gui/
gui/lib/
gui/src/net/sourceforge/pain/tools/guitool/dbbrowse/
gui/src/net/sourceforge/pain/tools/guitool/dialog/
gui/src/net/sourceforge/pain/tools/guitool/menu/
gui/src/net/sourceforge/pain/tools/guitool/resources/
gui/src/net/sourceforge/pain/tools/guitool/resources/images/
gui/src/net/sourceforge/pain/tools/guitool/resources/images/explorer/
tests/
tests/src/
tests/src/net/sourceforge/pain/db/data/
package net.sourceforge.pain;

import net.sourceforge.pain.data.*;
import net.sourceforge.pain.util.*;


public final class Time 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 WorldTime worldTime = null;
	private int time = 0;


	protected Time() {
	}

	public void addListener(TimeListener l) {
		Log.debug("adding listener:" + l);
		active.add(l);
	}

	public void removeListener(TimeListener l) {
		Log.debug("adding to remove listener:" + l);
		toRemove.add(l);
	}

	public void run() {
		worldTime = Core.getWorld().getWorldTime();
		time = worldTime.getTime();
		Log.debug("World Time Start:" + time);
		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();
				}

				time++;
				worldTime.setTime(time);
				final TimeListener[] data = active.data;
				final int size = active.size;
				for (int i = 0; i < size; i++) {
					try {
						data[i].pulse(time);
					} 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;
			}
		}
		Core.timeStopped();
	}

	private synchronized void processRemoved() {
		for (int i = 0; i < toRemove.size; i++) {
			active.remove(toRemove.data[i]);
		}
		toRemove.clear();
	}

	public int getTime() {
		return time;
	}

	public void stopTimer() {
		started = false;
	}

	static final class Listeners {
		TimeListener[] data = new TimeListener[10];
		int size = 0;

		synchronized void add(TimeListener l) {
			if (size == data.length) {
				TimeListener[] newData = new TimeListener[size * 2];
				System.arraycopy(data, 0, newData, 0, size);
				data = newData;
			}
			data[size] = l;
			size++;
		}

		synchronized void remove(TimeListener 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;
		}
	}
}