# `Finitomata.Flow`
[🔗](https://github.com/am-kantox/finitomata/blob/v0.35.0/lib/finitomata/flow.ex#L1)

The basic “brick” to build forks in top-level `Finitomata` instances.

## Definition Syntax

To construct the `Flow`, one should use the declarative map with events and states, as a string.

```elixir
%{
  "start" => %{valid_states: [:new], handler: &Foo.Bar.recipient_flow_name/3, initial: "✓"},
  "submit_name" => %{valid_states: [:started, :phone_number_submitted], handler: &submit_name/3},
  "submit_phone_number" => %{valid_states: [:started, :name_submitted], handler: &sumbit_phone/3},
  "commit" => %{valid_states: [:submit_name, :submit_phone_number], handler: &commit/3, final: "✓"}
}
```

and pass it to the `use Finitomata.Flow` as shown below. The declaration might be loaded from a file,
  or passed directly as a string.

```elixir
defmodule OnboardingFlow do
  @moduledoc false
  use Finitomata.Flow, flow: "priv/flows/onboarding.flow"
end
```

## Using with _FSM_

The FSM wanting to use the flow, must use `forks: [state: [event: FlowImplModule, …]]` option in a call to
  `use Finitomata`

```elixir
  use Finitomata, fsm: @fsm, …, forks: [started: [to_onboarded: OnboardingFlow]]
```

The compilation checks for both validity and consistency would be performed for `OnboardingFlow`.

Once the main FSM enters the state marked as `forks:` (`:started` in this particular example,)
the FSM with the name `{:fork, :started, MainFsmName}` will be launched and the main FSM would
wait for it to be finished. Upon termination, the flow FSM would send `:to_onboarded` event to
the main FSM, enforcing it to move to the next state.

One might specify several `Flow`s for the same event and state. In that case, `c:Finitomata.on_fork/2`
event must be implemented to decide what `Flow` to start in runtime.

```elixir
  use Finitomata, fsm: @fsm, …, forks: [s1: [evt: Flow1, evt: Flow2]]

  […]

  @impl Finitomata
  def on_fork(:s1, %{} = state) do
    if state.simple_flow?,
      do: {:ok, Flow1},
      else: {:ok, Flow2}
  end
```

## `Flow` management

`Flow`’s API is dedicated to the `event/4` function. To start a transition
  for the `FLow`, one should call somewhat along the following lines.

```elixir
Finitomata.Flow.event({:fork, :s1, "MainFSM"}, :submit_name, :commit)
```

The above will transition the `Flow` to the final state, terminating the `Flow`
  and sending `:to_onboarded` event to the main _FSM_.

# `event_option`

```elixir
@type event_option() :: {:skip_handlers?, boolean()}
```

The option to be passed to control the event behaviour

# `event_options`

```elixir
@type event_options() :: [event_option()]
```

The options to be passed to control the event behaviour

# `event_resolution`

```elixir
@type event_resolution() ::
  {:ok, term()} | :fsm_gone | {:error, Finitomata.State.payload()}
```

The result of event processing

# `flow_map`

```elixir
@type flow_map() :: %{optional(binary()) =&gt; flow_step()}
```

The expected map to configure `Finitomata.Flow`

# `flow_step`

```elixir
@type flow_step() :: %{
  initial: boolean() | binary(),
  final: boolean() | binary(),
  valid_states: [Finitomata.Transition.state()],
  target_states: [Finitomata.Transition.state()],
  handler: (... -&gt; term())
}
```

The expected flow step to configure `Finitomata.Flow`

# `event`

```elixir
@spec event(
  {Finitomata.id(), Finitomata.fsm_name()} | Finitomata.fsm_name(),
  Finitomata.Transition.event(),
  term()
) :: event_resolution()
```

Performs the transition to the predefined state, awaits for a result

# `event`

```elixir
@spec event(
  {Finitomata.id(), Finitomata.fsm_name()} | Finitomata.fsm_name(),
  Finitomata.Transition.event(),
  Finitomata.Transition.state(),
  term(),
  event_options()
) :: event_resolution()
```

Performs the transition to the desired state, awaits for a result

# `fast_forward`

```elixir
@spec fast_forward(
  {Finitomata.id(), Finitomata.fsm_name()} | Finitomata.fsm_name(),
  target ::
    Finitomata.Transition.state()
    | [Finitomata.Transition.state()]
    | Finitomata.Transition.Path.t(),
  options :: event_options()
) ::
  {:ok, [event_resolution()]}
  | {:fsm_gone, [event_resolution()]}
  | {:error, term()}
```

Fast-forwards the flow into one of the reachable states.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
