"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const core_1 = require("@bluebase/core");
const components_1 = require("@bluebase/components");
const lib_1 = require("../../lib");
const InternalNavigator_1 = require("../../components/InternalNavigator");
const react_1 = tslib_1.__importDefault(require("react"));
const historyToActionObject_1 = require("../../helpers/historyToActionObject");
/**
 * Base Navigator
 *
 * Contain functionality common to all Navigators
 */
class BaseNavigator extends react_1.default.Component {
    constructor(props) {
        super(props);
        this.state = {
            routes: this.props.routes || [],
        };
        // This binding is necessary to make `this` work in the callback
        this.getNavigationOptions = this.getNavigationOptions.bind(this);
        this.renderInitialRoute = this.renderInitialRoute.bind(this);
        this.renderRoute = this.renderRoute.bind(this);
    }
    /**
     * We resolve all screen components here
     * @param props
     */
    componentWillMount() {
        const BB = this.context;
        const routes = (this.props.routes || []).map(route => {
            // If there is no screen component, render nothing
            if (!route.screen) {
                return route;
            }
            // If screen prop is a string resolve that component from BlueBase, otherwisen use as is
            const screen = (typeof route.screen === 'string')
                ? BB.Components.resolve(route.screen)
                : route.screen;
            return Object.assign({}, route, { screen });
        });
        this.setState({ routes });
    }
    render() {
        // const BB: BlueBase = this.context;
        const _a = this.props, { type, initialRouteName: _initialRouteName } = _a, rest = tslib_1.__rest(_a, ["type", "initialRouteName"]);
        const { routes } = this.state;
        if (routes.length === 0) {
            return null;
        }
        return (react_1.default.createElement(lib_1.Switch, Object.assign({}, rest),
            routes.map(this.renderRoute),
            this.renderInitialRoute()));
    }
    /**
     * Render each indivitual route
     * @param route
     * @param BB
     */
    renderRoute(route) {
        const BB = this.context;
        const { exact, name, navigator: subNavigator, path, screen } = route;
        const { routes } = this.state;
        const RouteView = this.props.RouteView || screen || components_1.Noop;
        return (react_1.default.createElement(lib_1.Route, { key: name, exact: exact, path: path }, (routerProps) => {
            const navigation = historyToActionObject_1.historyToActionObject(routerProps, BB);
            // Sub Routes
            // We do this to resolve navigationOptions
            const navigator = Object.assign({}, this.props, { routes: routes.map(r => (Object.assign({}, r, { navigationOptions: this.getNavigationOptions(r, navigation) }))) });
            //
            return (react_1.default.createElement(RouteView, { screen: screen, navigation: navigation, navigationOptions: this.getNavigationOptions(route, navigation), navigator: navigator }, subNavigator ? react_1.default.createElement(InternalNavigator_1.InternalNavigator, { navigator: subNavigator }) : null));
        }));
    }
    /**
     * Redirects to the initial route, if non is given redirects to the
     * first route in the routes array.
     * @param BB
     */
    renderInitialRoute() {
        const BB = this.context;
        const { initialRouteName: _initialRouteName } = this.props;
        const { routes } = this.state;
        if (routes.length === 0) {
            return null;
        }
        const initialRouteName = _initialRouteName || routes[0].name;
        return (react_1.default.createElement(lib_1.Route, null, (routerProps) => {
            const navigation = historyToActionObject_1.historyToActionObject(routerProps, BB);
            return (react_1.default.createElement(components_1.Redirect, { routeName: initialRouteName, params: navigation.state.params }));
        }));
    }
    getNavigationOptions(route, navigation) {
        const BB = this.context;
        const { screenProps } = this.props;
        // Save the resolved tree in configs to use later
        const mainNavigationConfigs = BB.Configs.getValue('plugin.react-router.navigationConfigs');
        // // Extract screenProps
        // const screenProps: ScreenProps = {
        // 	...mainNavigationConfigs.screenProps,
        // 	...params.screenProps
        // };
        // Create navigationOptions from main navigation configs
        let navigationOptions = core_1.resolveThunk(mainNavigationConfigs.defaultNavigationOptions || {}, { navigation, screenProps, navigationOptions: {} });
        // Create navigationOptions from navigatior defaultNavigationOptions
        navigationOptions = core_1.resolveThunk(this.props.defaultNavigationOptions || navigationOptions, { navigation, screenProps, navigationOptions });
        // Now, create navigationOptions from route's navigationOptions object
        navigationOptions = core_1.resolveThunk(route.navigationOptions || navigationOptions, { navigation, screenProps, navigationOptions });
        // And finally, create navigationOptions from route.screen NavigationOptions
        navigationOptions = core_1.resolveThunk((route.screen && route.screen.navigationOptions) || navigationOptions, { navigation, screenProps, navigationOptions });
        // Phew...
        return navigationOptions;
    }
}
BaseNavigator.contextType = core_1.BlueBaseContext;
exports.BaseNavigator = BaseNavigator;
