/
area/
classes/net/sourceforge/pain/logic/
classes/net/sourceforge/pain/logic/event/
classes/net/sourceforge/pain/logic/fn/util/
classes/net/sourceforge/pain/network/console/
classes/net/sourceforge/pain/plugin/
classes/net/sourceforge/pain/plugin/reset/
classes/net/sourceforge/pain/plugin/shutdown/
classes/net/sourceforge/pain/plugin/social/
classest/net/sourceforge/pain/db/data/
doc/
doc/paindb/resources/
src/net/sourceforge/pain/logic/
src/net/sourceforge/pain/logic/event/
src/net/sourceforge/pain/logic/fn/util/
src/net/sourceforge/pain/network/console/
src/net/sourceforge/pain/network/console/telnet/
src/net/sourceforge/pain/plugin/
src/net/sourceforge/pain/plugin/command/
src/net/sourceforge/pain/plugin/reset/
src/net/sourceforge/pain/plugin/shutdown/
src/net/sourceforge/pain/plugin/social/
src/net/sourceforge/pain/util/
tests/
tests/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;
		}
	}
}