trigger method

Future<StateOfMind> trigger(
  1. Graph graph,
  2. StateOfMind stateOfMind,
  3. TransitionNotification<E> transition, {
  4. required bool applySideEffects,
})

Applies transition to the current statemachine and returns the resulting StateOfMind.

As the statemachine can be in multiple states the stateOfMind argument indicates what stateOfMind the transition is to be processed against. /

Implementation

Future<StateOfMind> trigger(Graph graph, StateOfMind stateOfMind,
    TransitionNotification<E> transition,
    {required bool applySideEffects}) async {
  final exitPaths = <PartialStatePath>[];
  final enterPaths = <PartialStatePath>[];

  final fromPath = StatePath.fromLeaf(graph, transition.from!.stateType);
  final toPath = StatePath.fromLeaf(graph, transition.to!.stateType);

  final commonAncestor = findCommonAncestor(graph, fromPath, toPath);

  if (!transition.skipExit) {
    exitPaths.addAll(_getExitPaths(stateOfMind, fromPath, commonAncestor));
  }

  if (!transition.skipEnter) {
    enterPaths.add(_getEnterPaths(toPath, commonAncestor));
  }

  final exitStates = dedupPaths(exitPaths);
  final enterStates = dedupPaths(enterPaths);

  final fromStateDefinition =
      graph.stateDefinitions[transition.from.runtimeType];

  if (applySideEffects) {
    await _callOnExits(fromStateDefinition, transition.event, exitStates);
    await _callSideEffect(transition);
  }

  // when entering we must start from the root and work
  // towards the leaf.
  await _callOnEnters(enterStates.reversed.toList(), transition.event);

  for (final statePath in exitPaths.toSet()) {
    /// check that a transition occured
    if (statePath.isNotEmpty) {
      removePath(stateOfMind, statePath.fullPath(graph));
    }
  }

  for (final statePath in enterPaths.toSet()) {
    /// check that a transition occured
    if (statePath.isNotEmpty) {
      addPath(stateOfMind, statePath.fullPath(graph));
    }
  }

  // If we transitioned up to a parent [toPath]
  // then we will have removed the child (and all its parents) so
  // we need re-add the parent [toPath].
  // No need to call onEnter as we were already in the parent state.
  if (toPath.leaf == commonAncestor) {
    addPath(stateOfMind, toPath);
  }

  /// If we transition from a child to a parent then we need to
  ///  remove the parent
  /// No need to run onExit as we are still in the parent state
  ///  due to the child.
  stateOfMind.stripRedundantParents();

  log('Updated stateOfMind: $stateOfMind');

  return stateOfMind;
}