package eu.hgross.blaubot.core.statemachine.states;
import eu.hgross.blaubot.core.ConnectionStateMachineConfig;
import eu.hgross.blaubot.core.IBlaubotConnection;
import eu.hgross.blaubot.core.IBlaubotDevice;
import eu.hgross.blaubot.core.BlaubotConnectionManager;
import eu.hgross.blaubot.core.statemachine.BlaubotAdapterHelper;
import eu.hgross.blaubot.core.statemachine.StateMachineSession;
import eu.hgross.blaubot.core.statemachine.events.AbstractBlaubotDeviceDiscoveryEvent;
import eu.hgross.blaubot.core.statemachine.events.AbstractTimeoutStateMachineEvent;
import eu.hgross.blaubot.core.statemachine.events.DiscoveredFreeEvent;
import eu.hgross.blaubot.core.statemachine.events.DiscoveredKingEvent;
import eu.hgross.blaubot.core.statemachine.states.PeasantState.ConnectionAccomplishmentType;
import eu.hgross.blaubot.admin.AbstractAdminMessage;
import eu.hgross.blaubot.util.Log;
public class FreeState implements IBlaubotState {
private static final String LOG_TAG = "FreeState";
private StateMachineSession session;
@Override
public void handleState(StateMachineSession session) {
this.session = session;
session.getServerConnectionManager().setMaster(false);
BlaubotAdapterHelper.startBeacons(session.getBeaconService());
BlaubotAdapterHelper.stopAcceptors(session.getConnectionStateMachine().getConnectionAcceptors());
BlaubotAdapterHelper.setDiscoveryActivated(session.getConnectionStateMachine().getBeaconService(), true);
if(Log.logDebugMessages()) {
Log.d(LOG_TAG, "Waiting for discovery events.");
}
}
@Override
public IBlaubotState onConnectionEstablished(IBlaubotConnection connection) {
// connections should be rejected in free state!
if(Log.logWarningMessages()) {
Log.w(LOG_TAG, "Got a connection in FreeState - disconnecting.");
}
connection.disconnect();
return this;
}
@Override
public IBlaubotState onConnectionClosed(IBlaubotConnection connection) {
return this;
}
@Override
public IBlaubotState onDeviceDiscoveryEvent(AbstractBlaubotDeviceDiscoveryEvent discoveryEvent) {
IBlaubotDevice device = discoveryEvent.getRemoteDevice();
if(session.isOwnDevice(device.getUniqueDeviceID())) {
if(Log.logErrorMessages()) {
Log.e(LOG_TAG, "We discovered ourselves");
}
throw new RuntimeException();
};
if (discoveryEvent instanceof DiscoveredKingEvent) {
if(Log.logDebugMessages()) {
Log.d(LOG_TAG, "Found a king. Trying to connect to the king " + device.getUniqueDeviceID() + " (" + device.getReadableName() + ")");
}
ConnectionStateMachineConfig conf = session.getConnectionStateMachineConfigForDevice(discoveryEvent.getRemoteDevice());
final int crowningTimeout = conf.getCrowningPreparationTimeout();
// -> found a king
// connect to the king; first let the king time to crown himself
try {
Thread.sleep(crowningTimeout);
} catch (InterruptedException e) {
}
IBlaubotConnection conn = session.getConnectionManager().connectToBlaubotDevice(device, BlaubotConnectionManager.AUTO_MAX_RETRIES);
boolean connect = conn != null;
if (connect) {
if(Log.logDebugMessages()) {
Log.d(LOG_TAG, "Successfully connected to King.");
}
// change to peasant state
return new PeasantState(conn, ConnectionAccomplishmentType.VOLUNTARILY);
} else {
if(Log.logDebugMessages()) {
Log.d(LOG_TAG, "Failed to connect to King - remaining in FreeState.");
}
// do nothing ... we wait for another king
// TODO: maybe retry every x ms?
}
} else if (discoveryEvent instanceof DiscoveredFreeEvent) {
if(Log.logDebugMessages()) {
Log.d(LOG_TAG, "Discovered another free blaubot instance: " + discoveryEvent.getRemoteDevice().getUniqueDeviceID());
}
// -> we found another free blaubot instance
// check mac address (or whatever)
if (session.isGreaterThanOurDevice(device)) {
if(Log.logDebugMessages()) {
Log.d(LOG_TAG, "Other Free is greater than we are - trying to connect.");
}
// the other device should get crowned soon
// connect to the greater device
IBlaubotConnection conn = session.getConnectionManager().connectToBlaubotDevice(device, BlaubotConnectionManager.AUTO_MAX_RETRIES);
boolean connect = conn != null;
if (connect) {
if(Log.logDebugMessages()) {
Log.d(LOG_TAG, "Connection to free succeeded.");
}
// change to peasant state
return new PeasantState(conn, ConnectionAccomplishmentType.VOLUNTARILY);
} else {
if(Log.logDebugMessages()) {
Log.d(LOG_TAG, "Connection to free failed, remaining in FreeState.");
}
// TODO: maybe retry some times and then decide to be king?
}
} else {
if(Log.logDebugMessages()) {
Log.d(LOG_TAG, "We are greater or equal than the other Free - we claim the throne ... (" + session.getOwnDevice() + " >= " + device + ")");
}
// -- we are the greater device
// we crown ourselves
return new KingState();
}
} else {
// yes, no, election ...
// wee keep our state
}
return this;
}
@Override
public IBlaubotState onTimeoutEvent(AbstractTimeoutStateMachineEvent timeoutEvent) {
return this; // no timeout events
}
@Override
public IBlaubotState onAdminMessage(AbstractAdminMessage adminMessage) {
// not relevant
return this;
}
@Override
public String toString() {
return "FreeState";
}
}