package controller;
import controller.action.ActionType;
import controller.action.GCAction;
import controller.net.Sender;
import controller.ui.GCGUI;
import data.AdvancedData;
import java.awt.EventQueue;
/**
* @author Michel Bartsch
*
* If the actionPerformed method of an action is called, it executes the register
* method of this class. Later the action`s perform method will be called
* in the GUI`s thread. This is to avoid resource conflicts caused by multiple
* threads without massive use of synchronized get- and set-methods.
*
* This class is a sigleton!
*/
public class EventHandler
{
/** The instance of the singleton. */
private static EventHandler instance;
/** This GUI`s update method will be called. */
private GCGUI gui;
/** The sender has a send method to update the data to send */
private Sender sender = Sender.getInstance();
/**
* This is the current data. You should write into data only in actions
* and than use the data giving as parameters. The data is not private,
* only because the Log may change it to a later version.
*/
public AdvancedData data;
/** The last actions as the name says. */
public GCAction lastNonClockEvent = null;
public GCAction lastUIEvent = null;
public GCAction lastNetEvent = null;
/**
* This may be set only in actions. If true, lastUIEvent will be set to
* null, even if the current action is an UIEvent.
*/
public boolean noLastUIEvent = false;
/**
* Creates a new EventHandler.
*/
private EventHandler() {}
/**
* To get the singleton instance for public attribute access.
*
* @return The singleton`s instance.
*/
public synchronized static EventHandler getInstance()
{
if (instance == null) {
instance = new EventHandler();
}
return instance;
}
/**
* Sets the GUI.
*
* @param gui The GUI to be updated when the changes.
*/
public void setGUI(GCGUI gui)
{
this.gui = gui;
}
/**
* Very important method called automatically by every action in it`s
* actionPerformed method to later call it`s perform method in the
* GUI-Thread.
*
* @param event The action calling.
*/
public void register(final GCAction event)
{
if (EventQueue.isDispatchThread()) {
// current thread is dispatcher, no need to use EventQueue
if (event.isLegal(data)) {
event.perform(data);
update(event);
}
} else {
// force all threads to perform action in GUI-thread, using
// invokeLater to avoid deadlocks...
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
if (event.isLegal(data)) {
event.perform(data);
update(event);
}
}
});
}
}
/**
* After the perform method this updates some attributes, calls the GUI`s
* update method and changes the data to be send.
*
* @param event The action that has been called.
*/
private void update(GCAction event)
{
if (event.type != ActionType.CLOCK) {
lastNonClockEvent = event;
if (event.type == ActionType.UI) {
lastUIEvent = event;
} else if (event.type == ActionType.NET) {
lastNetEvent = event;
}
}
if (noLastUIEvent) {
noLastUIEvent = false;
lastUIEvent = null;
}
sender.send(data);
gui.update(data);
}
}