/** Execute several navigation event on the current stack */
  public void chain(NavigationChain chain, ViewTransitionDirection direction) {
    check();
    Preconditions.checkArgument(
        chain != null && !chain.chains.isEmpty(), "Navigation chain cannot be null nor empty");

    ViewTransitionDirection defaultDirection = null;
    List<History.Entry> entries = new ArrayList<>(chain.chains.size());
    for (int i = 0; i < chain.chains.size(); i++) {
      NavigationChain.Chain c = chain.chains.get(i);
      if (c.path == null) {
        defaultDirection = ViewTransitionDirection.BACKWARD;
        if (history.canKill()) {
          if (c.type == NavigationChain.Chain.TYPE_BACK) {
            entries.add(history.kill());
          } else {
            entries.addAll(history.killAll(false));
          }
        }
      } else {
        defaultDirection = ViewTransitionDirection.FORWARD;
        if (c.type == NavigationChain.Chain.TYPE_REPLACE) {
          History.Entry e = history.kill();
          if (history.indexOf(e) != 0) {
            entries.add(e);
          }
        }

        // push type for push and replace, modal for show
        int type =
            c.type == NavigationChain.Chain.TYPE_PUSH
                    || c.type == NavigationChain.Chain.TYPE_REPLACE
                ? History.NAV_TYPE_PUSH
                : History.NAV_TYPE_MODAL;
        entries.add(history.add(c.path, type));
      }
    }

    entries.get(entries.size() - 1).direction = direction != null ? direction : defaultDirection;
    entries.get(0).returnsResult = chain.result;
    dispatcher.dispatch(entries);
  }