"use strict";

import isArray from 'lodash/isArray';
import { UniqueIdProvider } from "./adapters/UniqueIdProvider.js";
import { Store } from "./components/Store.js";
import { OptionProcessorsStore } from "./processors/OptionProcessorsStore.js";
import { ComponentRegistry } from "./components/ComponentRegistry.js";
import { Commands } from "./commands/Commands.js";
import { LayoutTreeParser } from "./commands/LayoutTreeParser.js";
import { LayoutTreeCrawler } from "./commands/LayoutTreeCrawler.js";
import { EventsRegistry } from "./events/EventsRegistry.js";
import { CommandsObserver } from "./events/CommandsObserver.js";
import { Constants } from "./adapters/Constants.js";
import { ComponentEventsObserver } from "./events/ComponentEventsObserver.js";
import { TouchablePreview } from "./adapters/TouchablePreview.js";
import { ComponentWrapper } from "./components/ComponentWrapper.js";
import { OptionsProcessor } from "./commands/OptionsProcessor.js";
import { ColorService } from "./adapters/ColorService.js";
import { AssetService } from "./adapters/AssetResolver.js";
import { Deprecations } from "./commands/Deprecations.js";
import { LayoutProcessor } from "./processors/LayoutProcessor.js";
import { LayoutProcessorsStore } from "./processors/LayoutProcessorsStore.js";
import { OptionsCrawler } from "./commands/OptionsCrawler.js";
import { LinkingHandler } from "./linking/LinkingHandler.js";
export class NavigationRoot {
  TouchablePreview = TouchablePreview;
  constructor(nativeCommandsSender, nativeEventsReceiver, appRegistryService) {
    this.nativeCommandsSender = nativeCommandsSender;
    this.nativeEventsReceiver = nativeEventsReceiver;
    this.appRegistryService = appRegistryService;
    this.componentWrapper = new ComponentWrapper();
    this.store = new Store();
    this.optionProcessorsStore = new OptionProcessorsStore();
    this.layoutProcessorsStore = new LayoutProcessorsStore();
    this.uniqueIdProvider = new UniqueIdProvider();
    this.componentEventsObserver = new ComponentEventsObserver(this.nativeEventsReceiver, this.store);
    this.componentRegistry = new ComponentRegistry(this.store, this.componentEventsObserver, this.componentWrapper, this.appRegistryService);
    this.layoutTreeParser = new LayoutTreeParser(this.uniqueIdProvider);
    const optionsProcessor = new OptionsProcessor(this.store, this.uniqueIdProvider, this.optionProcessorsStore, new ColorService(), new AssetService(), new Deprecations());
    const layoutProcessor = new LayoutProcessor(this.layoutProcessorsStore);
    this.layoutTreeCrawler = new LayoutTreeCrawler(this.store, optionsProcessor);
    this.commandsObserver = new CommandsObserver(this.uniqueIdProvider);
    this.optionsCrawler = new OptionsCrawler(this.store, this.uniqueIdProvider);
    this.commands = new Commands(this.store, this.nativeCommandsSender, this.layoutTreeParser, this.layoutTreeCrawler, this.commandsObserver, this.uniqueIdProvider, optionsProcessor, layoutProcessor, this.optionsCrawler);
    this.eventsRegistry = new EventsRegistry(this.nativeEventsReceiver, this.commandsObserver, this.componentEventsObserver);
    this.linkingHandler = new LinkingHandler(layout => this.commands.showModal(layout));
    this.componentEventsObserver.registerOnceForAllComponentEvents();
  }

  /**
   * Every navigation component in your app must be registered with a unique name.
   * The component itself is a traditional React component extending React.Component.
   */
  registerComponent(componentName, componentProvider, concreteComponentProvider) {
    return this.componentRegistry.registerComponent(componentName, componentProvider, concreteComponentProvider);
  }

  /**
   * Adds an option processor which allows option interpolation by optionPath.
   */
  addOptionProcessor(optionPath, processor) {
    return this.optionProcessorsStore.addProcessor(optionPath, processor);
  }

  /**
   * Method to be invoked when a layout is processed and is about to be created. This can be used to change layout options or even inject props to components.
   */
  addLayoutProcessor(processor) {
    return this.layoutProcessorsStore.addProcessor(processor);
  }
  setLazyComponentRegistrator(lazyRegistratorFn) {
    this.store.setLazyComponentRegistrator(lazyRegistratorFn);
  }

  /**
   * Utility helper function like registerComponent,
   * wraps the provided component with a react-redux Provider with the passed redux store
   * @deprecated
   */
  registerComponentWithRedux(componentName, getComponentClassFunc, ReduxProvider, reduxStore) {
    console.warn('registerComponentWithRedux is deprecated and will be removed in the next version! Please use Navigation.registerComponent instead. Visit the docs for more information https://wix.github.io/react-native-navigation/api/component#registering-a-component-wrapped-with-providers');
    return this.componentRegistry.registerComponent(componentName, getComponentClassFunc, undefined, ReduxProvider, reduxStore);
  }

  /**
   * Reset the app to a new layout
   */
  setRoot(layout) {
    const result = this.commands.setRoot(layout);
    result.then(() => this.linkingHandler.setRootReady()).catch(() => {});
    return result;
  }

  /**
   * Set default options to all screens. Useful for declaring a consistent style across the app.
   */
  setDefaultOptions(options) {
    this.commands.setDefaultOptions(options);
  }

  /**
   * Change a component's navigation options
   */
  mergeOptions(componentId, options) {
    this.commands.mergeOptions(componentId, options);
  }

  /**
   * Update a mounted component's props
   */
  updateProps(componentId, props, callback) {
    this.commands.updateProps(componentId, props, callback);
  }

  /**
   * Show a screen as a modal.
   */
  showModal(layout) {
    return this.commands.showModal(layout);
  }

  /**
   * Dismiss a modal by componentId. The dismissed modal can be anywhere in the stack.
   */
  dismissModal(componentId, mergeOptions) {
    return this.commands.dismissModal(componentId, mergeOptions);
  }

  /**
   * Dismiss all Modals
   */
  dismissAllModals(mergeOptions) {
    return this.commands.dismissAllModals(mergeOptions);
  }

  /**
   * Push a new layout into this screen's navigation stack.
   */
  push(componentId, layout) {
    return this.commands.push(componentId, layout);
  }

  /**
   * Pop a component from the stack, regardless of it's position.
   */
  pop(componentId, mergeOptions) {
    return this.commands.pop(componentId, mergeOptions);
  }

  /**
   * Pop the stack to a given component
   */
  popTo(componentId, mergeOptions) {
    return this.commands.popTo(componentId, mergeOptions);
  }

  /**
   * Pop the component's stack to root.
   */
  popToRoot(componentId, mergeOptions) {
    return this.commands.popToRoot(componentId, mergeOptions);
  }

  /**
   * Sets new root component to stack.
   */
  setStackRoot(componentId, layout) {
    const children = isArray(layout) ? layout : [layout];
    return this.commands.setStackRoot(componentId, children);
  }

  /**
   * Show overlay on top of the entire app
   */
  showOverlay(layout) {
    return this.commands.showOverlay(layout);
  }

  /**
   * dismiss overlay by componentId
   */
  dismissOverlay(componentId) {
    return this.commands.dismissOverlay(componentId);
  }

  /**
   * dismiss all overlays
   */
  dismissAllOverlays() {
    return this.commands.dismissAllOverlays();
  }

  /**
   * Resolves arguments passed on launch
   */
  getLaunchArgs() {
    return this.commands.getLaunchArgs();
  }

  /**
   * Configure deep link handling. Maps URL prefixes and path patterns to
   * RNN components. By default each matched link is presented as a modal
   * (wrapped in a stack so a topBar close button can be configured); supply
   * `getModal` to customize the modal layout or `onLink` to bypass the
   * default behavior entirely.
   */
  setLinking(config) {
    this.linkingHandler.configure(config);
  }

  /**
   * Manually run a URL through the deep link pipeline as if it had been
   * delivered by the OS. Useful for URLs received from push notifications
   * or other non-`Linking` sources.
   */
  handleDeepLink(url) {
    this.linkingHandler.handleURL(url);
  }

  /**
   * Signal that the app is ready to process deep links (e.g. after the
   * user has authenticated). When set to `true`, any links that were
   * queued while not ready are replayed in order.
   */
  setLinkingReady(ready) {
    this.linkingHandler.setLinkingReady(ready);
  }

  /**
   * Obtain the events registry instance
   */
  events() {
    return this.eventsRegistry;
  }

  /**
   * Constants coming from native
   */
  async constants() {
    return await Constants.get(this.nativeCommandsSender);
  }

  /**
   * Constants coming from native (synchronized call)
   */
  constantsSync() {
    return Constants.getSync(this.nativeCommandsSender);
  }
}
//# sourceMappingURL=Navigation.js.map