All Downloads are FREE. Search and download functionalities are using the official Maven repository.

eu.lestard.redux_javafx_devtool.updater.Updater Maven / Gradle / Ivy

package eu.lestard.redux_javafx_devtool.updater;

import eu.lestard.redux_javafx_devtool.actions.ClientActionDispatchedAction;
import eu.lestard.redux_javafx_devtool.actions.ClientActionSelectedAction;
import eu.lestard.redux_javafx_devtool.actions.SwitchIgnoreNewActionsAction;
import eu.lestard.redux_javafx_devtool.actions.TimeTravelToClientAction;
import eu.lestard.redux_javafx_devtool.actions.TimeTravelToNextActionAction;
import eu.lestard.redux_javafx_devtool.actions.TimeTravelToPreviousActionAction;
import eu.lestard.redux_javafx_devtool.state.AppState;
import eu.lestard.redux_javafx_devtool.state.ClientAction;
import eu.lestard.redux_javafx_devtool.state.StateHistoryEntry;
import eu.lestard.redux_javafx_devtool.state.StateNode;
import eu.lestard.redux_javafx_devtool.state.selectors.Selectors;
import eu.lestard.redux_javafx_devtool.util.IdGenerator;
import io.vavr.collection.Seq;
import io.vavr.control.Option;

import static io.vavr.API.$;
import static io.vavr.API.Case;
import static io.vavr.API.Match;
import static io.vavr.Predicates.instanceOf;

public class Updater {
	private static final IdGenerator idGenerator = IdGenerator.create(0);

	private Updater() {
	}

	public static AppState update(AppState state, Object action) {
		return Match(action).of(
			Case($(instanceOf(ClientActionDispatchedAction.class)),
				clientActionDispatchedAction -> {
					final Object clientAction = clientActionDispatchedAction.getClientAction();
					final Object clientState = clientActionDispatchedAction.getClientState();

					/*
						If time traveling is active at the moment (i.e. the currently selected and active
						action is not the last action is the state history) we may not accept new client actions.
						Of course this only applies if whe have at least a single action recorded yet.
					 */
					if(Selectors.isTimeTravelActive(state) && !state.getStateHistory().isEmpty()) {
						return state;
					} else {
						return state.withNewAction(
							ClientAction.create(idGenerator.getId(), clientAction),
							clientState
						);
					}
				}
			),

			Case($(instanceOf(ClientActionSelectedAction.class)),
				clientActionSelectedAction -> state.withSelectedAction(clientActionSelectedAction.getClientAction())
			),

			Case($(instanceOf(TimeTravelToClientAction.class)),
				timeTravelToClientAction -> {
					// the action that we jump to
					final ClientAction targetAction = timeTravelToClientAction.getClientAction();

					final Option targetStateOption = state.getStateHistory()
						.find(historyEntry -> historyEntry.getAction().getId().equals(targetAction.getId()))
						.map(StateHistoryEntry::getState);

					if(targetStateOption.isEmpty()) {
						return state;
					}

					final Seq historyWithDeactivatedActions = state.getStateHistory()
						.map(historyEntry -> {
							final ClientAction historyEntryAction = historyEntry.getAction();

							if(historyEntryAction.getDispatchTime().isAfter(targetAction.getDispatchTime())) {
								return historyEntry.withAction(historyEntryAction.withActiveFlag(false));
							} else {
								if(historyEntryAction.isActive()) {
									return historyEntry;
								} else {
									return historyEntry.withAction(historyEntryAction.withActiveFlag(true));
								}
							}
						});

					return state
						.withStateHistory(historyWithDeactivatedActions);
				}
			),

			Case($(instanceOf(TimeTravelToNextActionAction.class)),
				timeTravelToNextActionAction -> {
					final Option currentHistoryEntryOption = state.getStateHistory()
						.filter(entry -> entry.getAction().isActive())
						.lastOption();

					return currentHistoryEntryOption.map(currentHistoryEntry -> {
						final int indexOfCurrent = state.getStateHistory().indexOf(currentHistoryEntry);


						if((state.getStateHistory().size() -1) == indexOfCurrent) {
							// if the last entry is already active, there is no 'next' action.
							return state;
						}

						final StateHistoryEntry nextHistoryEntry = state.getStateHistory().get(indexOfCurrent + 1);

						final Seq newHistory = state.getStateHistory()
							.replace(nextHistoryEntry,
								nextHistoryEntry.withAction(nextHistoryEntry.getAction().withActiveFlag(true)));
						return state.withStateHistory(newHistory);
					}).getOrElse(state);
				}
			),


			Case($(instanceOf(TimeTravelToPreviousActionAction.class)),
				timeTravelToPreviousActionAction -> {
					final Option currentHistoryEntryOption = state.getStateHistory()
						.filter(entry -> entry.getAction().isActive())
						.lastOption();

					return currentHistoryEntryOption.map(currentHistoryEntry -> {
						final int indexOfCurrent = state.getStateHistory().indexOf(currentHistoryEntry);

						if(indexOfCurrent < 1) {
							// if the current entry is the first we can't move to previous
							return state;
						}

						final Seq newHistory = state.getStateHistory()
							.replace(currentHistoryEntry,
								currentHistoryEntry.withAction(currentHistoryEntry.getAction().withActiveFlag(false)));
						return state.withStateHistory(newHistory);
					}).getOrElse(state);
				}
			),

			Case($(instanceOf(SwitchIgnoreNewActionsAction.class)),
				switchIgnoreNewActionsAction -> state.withIgnoreNewActions(!state.isIgnoreNewActions())),


			Case($(), state)
		);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy