package eu.hgross.blaubot.core; import java.lang.reflect.Constructor; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import eu.hgross.blaubot.core.acceptor.ConnectionMetaDataDTO; import eu.hgross.blaubot.core.statemachine.events.AbstractBlaubotDeviceDiscoveryEvent; import eu.hgross.blaubot.core.statemachine.events.DiscoveredFreeEvent; import eu.hgross.blaubot.core.statemachine.events.DiscoveredKingEvent; import eu.hgross.blaubot.core.statemachine.events.DiscoveredPeasantEvent; import eu.hgross.blaubot.core.statemachine.events.DiscoveredPrinceEvent; import eu.hgross.blaubot.core.statemachine.events.DiscoveredStoppedEvent; import eu.hgross.blaubot.core.statemachine.states.FreeState; import eu.hgross.blaubot.core.statemachine.states.IBlaubotState; import eu.hgross.blaubot.core.statemachine.states.KingState; import eu.hgross.blaubot.core.statemachine.states.PeasantState; import eu.hgross.blaubot.core.statemachine.states.PrinceState; import eu.hgross.blaubot.core.statemachine.states.StoppedState; /** * Enum constants wiring together some classes related to device states. * * @author Henning Gross {@literal (mail.to@henning-gross.de)} * */ public enum State { Free (FreeState.class, DiscoveredFreeEvent.class), Peasant (PeasantState.class, DiscoveredPeasantEvent.class), Prince (PrinceState.class, DiscoveredPrinceEvent.class), King (KingState.class, DiscoveredKingEvent.class), Stopped (StoppedState.class, DiscoveredStoppedEvent.class); /** * Maps all allowed state changes */ private static Map<State, Set<State>> ALLOWED_STATE_CHANGES = new HashMap<State, Set<State>>(); static { for(State s : State.values()) { ALLOWED_STATE_CHANGES.put(s, new HashSet<State>()); } ALLOWED_STATE_CHANGES.get(Free).addAll(Arrays.asList(Stopped, Peasant, King)); ALLOWED_STATE_CHANGES.get(Peasant).addAll(Arrays.asList(Stopped, Peasant, Free, Prince)); ALLOWED_STATE_CHANGES.get(Prince).addAll(Arrays.asList(Stopped, Peasant, Free, King)); ALLOWED_STATE_CHANGES.get(King).addAll(Arrays.asList(Stopped, Free, Peasant)); ALLOWED_STATE_CHANGES.get(Stopped).addAll(Arrays.asList(Stopped, Free)); } private Class<? extends IBlaubotState> stateClass; private Class<? extends AbstractBlaubotDeviceDiscoveryEvent> discoveryEventClass; State(Class<? extends IBlaubotState> stateClass, Class<? extends AbstractBlaubotDeviceDiscoveryEvent> discoveryEventClass) { this.stateClass = stateClass; this.discoveryEventClass = discoveryEventClass; } public Class<? extends IBlaubotState> getStateClass() { return stateClass; } private Class<? extends AbstractBlaubotDeviceDiscoveryEvent> getDiscoveryEventClass() { return discoveryEventClass; } /** * @param stateClass a class that is used by sthe state machine * @return state enum or null, if no state is mapped to this stateClass */ public static State getStateByStatemachineClass(Class<? extends IBlaubotState> stateClass) { for(State s : State.values()) { if (s.stateClass == stateClass) return s; } return null; } /** * Creates the appropriate discovery event from the given State * * @param device the device associated with this state * @param connectionMetaDataList the meta data for the acceptors of `device` * @return the discovery event for the given device */ public AbstractBlaubotDeviceDiscoveryEvent createDiscoveryEventForDevice (IBlaubotDevice device, List<ConnectionMetaDataDTO> connectionMetaDataList) { Constructor<? extends AbstractBlaubotDeviceDiscoveryEvent> constructor; try { constructor = getDiscoveryEventClass().getConstructor(IBlaubotDevice.class, List.class); AbstractBlaubotDeviceDiscoveryEvent event = constructor.newInstance(device, connectionMetaDataList); return event; } catch(Exception e) { throw new RuntimeException("Could not create AbstractBlaubotDeviceDiscoveryEvent from State " + this, e); } } /** * Checks if a transition to "toState" is allowed from "this" state. * * @param toState the state to check * @return true iff a state change from 'this' state to 'toState' is allowed. */ public boolean isStateChangeAllowed(State toState) { return ALLOWED_STATE_CHANGES.get(this).contains(toState); } }