package mightypork.util.control.eventbus;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import mightypork.util.control.Destroyable;
import mightypork.util.control.eventbus.clients.DelegatingClient;
import mightypork.util.control.eventbus.events.Event;
import mightypork.util.control.eventbus.events.flags.DelayedEvent;
import mightypork.util.control.eventbus.events.flags.ImmediateEvent;
import mightypork.util.control.eventbus.events.flags.SingleReceiverEvent;
import mightypork.util.control.eventbus.events.flags.UnloggedEvent;
import mightypork.util.logging.Log;
/**
* An event bus, accommodating multiple EventChannels.
* Channel will be created when an event of type is first encountered.
*
* @author MightyPork
*/
final public class EventBus implements Destroyable {
/**
* Queued event holder
*/
private class DelayQueueEntry implements Delayed {
private final long due;
private final Event> evt;
public DelayQueueEntry(double seconds, Event> event) {
super();
this.due = System.currentTimeMillis() + (long) (seconds * 1000);
this.evt = event;
}
@Override
public int compareTo(Delayed o)
{
return Long.valueOf(getDelay(TimeUnit.MILLISECONDS)).compareTo(o.getDelay(TimeUnit.MILLISECONDS));
}
@Override
public long getDelay(TimeUnit unit)
{
return unit.convert(due - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
public Event> getEvent()
{
return evt;
}
}
/**
* Thread handling queued events
*/
private class QueuePollingThread extends Thread {
public volatile boolean stopped = false;
public QueuePollingThread() {
super("Queue Polling Thread");
}
@Override
public void run()
{
DelayQueueEntry evt;
while (!stopped) {
evt = null;
try {
evt = sendQueue.take();
} catch (final InterruptedException ignored) {
//
}
if (evt != null) {
dispatch(evt.getEvent());
}
}
}
}
static final String logMark = " ";
private static Class> getEventListenerClass(Event> event)
{
// BEHOLD, MAGIC!
final Type[] interfaces = event.getClass().getGenericInterfaces();
for (final Type interf : interfaces) {
if (interf instanceof ParameterizedType) {
if (((ParameterizedType) interf).getRawType() == Event.class) {
final Type[] types = ((ParameterizedType) interf).getActualTypeArguments();
for (final Type genericType : types) {
return (Class>) genericType;
}
}
}
}
throw new RuntimeException("Could not detect event listener type.");
}
/** Log detailed messages (debug) */
public boolean detailedLogging = false;
/** Queue polling thread */
private final QueuePollingThread busThread;
/** Registered clients */
private final BufferedHashSet