text: import $ from 'dom7';
  import Utils from '../../utils/utils';
  import History from '../../utils/history';
  import redirect from './redirect';
  
  function refreshPage() {
    const router = this;
    return router.navigate(router.currentRoute.url, {
      ignoreCache: true,
      reloadCurrent: true,
    });
  }
  
  function forward(el, forwardOptions = {}) {
    const router = this;
    const app = router.app;
    const view = router.view;
  
    const options = Utils.extend({
      animate: router.params.animate,
      pushState: true,
      history: true,
      reloadCurrent: router.params.reloadPages,
      reloadPrevious: false,
      reloadAll: false,
      on: {},
    }, forwardOptions);
  
    const dynamicNavbar = router.dynamicNavbar;
    const separateNavbar = router.separateNavbar;
  
    const $viewEl = router.$el;
    const $newPage = $(el);
    const reload = options.reloadPrevious || options.reloadCurrent || options.reloadAll;
    let $oldPage;
  
    let $navbarEl;
    let $newNavbarInner;
    let $oldNavbarInner;
  
    if ($newPage.length) {
      // Remove theme elements
      router.removeThemeElements($newPage);
    }
  
    if (dynamicNavbar) {
      $newNavbarInner = $newPage.children('.navbar').children('.navbar-inner');
      if (separateNavbar) {
        $navbarEl = router.$navbarEl;
        if ($newNavbarInner.length > 0) {
          $newPage.children('.navbar').remove();
        }
        if ($newNavbarInner.length === 0 && $newPage[0].f7Page) {
          // Try from pageData
          $newNavbarInner = $newPage[0].f7Page.$navbarEl;
        }
      }
    }
  
    router.allowPageChange = false;
    if ($newPage.length === 0) {
      router.allowPageChange = true;
      return router;
    }
  
    // Pages In View
    const $pagesInView = $viewEl
      .children('.page:not(.stacked)')
      .filter((index, pageInView) => pageInView !== $newPage[0]);
  
    // Navbars In View
    let $navbarsInView;
    if (separateNavbar) {
      $navbarsInView = $navbarEl
        .children('.navbar-inner:not(.stacked)')
        .filter((index, navbarInView) => navbarInView !== $newNavbarInner[0]);
    }
  
    // Exit when reload previous and only 1 page in view so nothing ro reload
    if (options.reloadPrevious && $pagesInView.length < 2) {
      router.allowPageChange = true;
      return router;
    }
  
    // New Page
    let newPagePosition = 'next';
    if (options.reloadCurrent || options.reloadAll) {
      newPagePosition = 'current';
    } else if (options.reloadPrevious) {
      newPagePosition = 'previous';
    }
    $newPage
      .addClass(`page-${newPagePosition}`)
      .removeClass('stacked');
  
    if (dynamicNavbar && $newNavbarInner.length) {
      $newNavbarInner
        .addClass(`navbar-${newPagePosition}`)
        .removeClass('stacked');
    }
  
    // Find Old Page
    if (options.reloadCurrent) {
      $oldPage = $pagesInView.eq($pagesInView.length - 1);
      if (separateNavbar) {
        // $oldNavbarInner = $navbarsInView.eq($pagesInView.length - 1);
        $oldNavbarInner = $(app.navbar.getElByPage($oldPage));
      }
    } else if (options.reloadPrevious) {
      $oldPage = $pagesInView.eq($pagesInView.length - 2);
      if (separateNavbar) {
        // $oldNavbarInner = $navbarsInView.eq($pagesInView.length - 2);
        $oldNavbarInner = $(app.navbar.getElByPage($oldPage));
      }
    } else if (options.reloadAll) {
      $oldPage = $pagesInView.filter((index, pageEl) => pageEl !== $newPage[0]);
      if (separateNavbar) {
        $oldNavbarInner = $navbarsInView.filter((index, navbarEl) => navbarEl !== $newNavbarInner[0]);
      }
    } else {
      if ($pagesInView.length > 1) {
        let i = 0;
        for (i = 0; i < $pagesInView.length - 1; i += 1) {
          const oldNavbarInnerEl = app.navbar.getElByPage($pagesInView.eq(i));
          if (router.params.stackPages) {
            $pagesInView.eq(i).addClass('stacked');
            if (separateNavbar) {
              // $navbarsInView.eq(i).addClass('stacked');
              $(oldNavbarInnerEl).addClass('stacked');
            }
          } else {
            // Page remove event
            router.pageCallback('beforeRemove', $pagesInView[i], $navbarsInView && $navbarsInView[i], 'previous', undefined, options);
            router.removePage($pagesInView[i]);
            if (separateNavbar && oldNavbarInnerEl) {
              router.removeNavbar(oldNavbarInnerEl);
            }
          }
        }
      }
      $oldPage = $viewEl
        .children('.page:not(.stacked)')
        .filter((index, page) => page !== $newPage[0]);
      if (separateNavbar) {
        $oldNavbarInner = $navbarEl
          .children('.navbar-inner:not(.stacked)')
          .filter((index, navbarInner) => navbarInner !== $newNavbarInner[0]);
      }
    }
    if (dynamicNavbar && !separateNavbar) {
      $oldNavbarInner = $oldPage.children('.navbar').children('.navbar-inner');
    }
  
    // Push State
    if (router.params.pushState && options.pushState && !options.reloadPrevious) {
      const pushStateRoot = router.params.pushStateRoot || '';
      History[options.reloadCurrent || options.reloadAll ? 'replace' : 'push'](
        view.id,
        {
          url: options.route.url,
        },
        pushStateRoot + router.params.pushStateSeparator + options.route.url
      );
    }
  
    // Current Page & Navbar
    router.currentPageEl = $newPage[0];
    if (dynamicNavbar && $newNavbarInner.length) {
      router.currentNavbarEl = $newNavbarInner[0];
    } else {
      delete router.currentNavbarEl;
    }
  
    // Current Route
    router.currentRoute = options.route;
  
    // Update router history
    const url = options.route.url;
    if (options.history) {
      if (options.reloadCurrent && router.history.length > 0) {
        router.history[router.history.length - (options.reloadPrevious ? 2 : 1)] = url;
      } else if (options.reloadAll) {
        router.history = [url];
      } else {
        router.history.push(url);
      }
    }
    router.saveHistory();
  
    // Insert new page and navbar
    const newPageInDom = $newPage.parents(document).length > 0;
    const f7Component = $newPage[0].f7Component;
    if (options.reloadPrevious) {
      if (f7Component && !newPageInDom) {
        f7Component.$mount((componentEl) => {
          $(componentEl).insertBefore($oldPage);
        });
      } else {
        $newPage.insertBefore($oldPage);
      }
      if (separateNavbar && $newNavbarInner.length) {
        if ($oldNavbarInner.length) {
          $newNavbarInner.insertBefore($oldNavbarInner);
        } else {
          if (!router.$navbarEl.parents(document).length) {
            router.$el.prepend(router.$navbarEl);
          }
          $navbarEl.append($newNavbarInner);
        }
      }
    } else {
      if ($oldPage.next('.page')[0] !== $newPage[0]) {
        if (f7Component && !newPageInDom) {
          f7Component.$mount((componentEl) => {
            $viewEl.append(componentEl);
          });
        } else {
          $viewEl.append($newPage[0]);
        }
      }
      if (separateNavbar && $newNavbarInner.length) {
        if (!router.$navbarEl.parents(document).length) {
          router.$el.prepend(router.$navbarEl);
        }
        $navbarEl.append($newNavbarInner[0]);
      }
    }
    if (!newPageInDom) {
      router.pageCallback('mounted', $newPage, $newNavbarInner, newPagePosition, reload ? newPagePosition : 'current', options, $oldPage);
    }
  
    // Remove old page
    if (options.reloadCurrent && $oldPage.length > 0) {
      if (router.params.stackPages && router.initialPages.indexOf($oldPage[0]) >= 0) {
        $oldPage.addClass('stacked');
        if (separateNavbar) {
          $oldNavbarInner.addClass('stacked');
        }
      } else {
        // Page remove event
        router.pageCallback('beforeRemove', $oldPage, $oldNavbarInner, 'previous', undefined, options);
        router.removePage($oldPage);
        if (separateNavbar && $oldNavbarInner && $oldNavbarInner.length) {
          router.removeNavbar($oldNavbarInner);
        }
      }
    } else if (options.reloadAll) {
      $oldPage.each((index, pageEl) => {
        const $oldPageEl = $(pageEl);
        const $oldNavbarInnerEl = $(app.navbar.getElByPage($oldPageEl));
        if (router.params.stackPages && router.initialPages.indexOf($oldPageEl[0]) >= 0) {
          $oldPageEl.addClass('stacked');
          if (separateNavbar) {
            $oldNavbarInnerEl.addClass('stacked');
          }
        } else {
          // Page remove event
          router.pageCallback('beforeRemove', $oldPageEl, $oldNavbarInner && $oldNavbarInner.eq(index), 'previous', undefined, options);
          router.removePage($oldPageEl);
          if (separateNavbar && $oldNavbarInnerEl.length) {
            router.removeNavbar($oldNavbarInnerEl);
          }
        }
      });
    }
  
    // Load Tab
    if (options.route.route.tab) {
      router.tabLoad(options.route.route.tab, Utils.extend({}, options, {
        history: false,
        pushState: false,
      }));
    }
  
    // Page init and before init events
    router.pageCallback('init', $newPage, $newNavbarInner, newPagePosition, reload ? newPagePosition : 'current', options, $oldPage);
  
    if (options.reloadCurrent || options.reloadAll) {
      router.allowPageChange = true;
      router.pageCallback('beforeIn', $newPage, $newNavbarInner, newPagePosition, 'current', options);
      router.pageCallback('afterIn', $newPage, $newNavbarInner, newPagePosition, 'current', options);
      return router;
    }
  
    // Before animation event
    router.pageCallback('beforeIn', $newPage, $newNavbarInner, 'next', 'current', options);
    router.pageCallback('beforeOut', $oldPage, $oldNavbarInner, 'current', 'previous', options);
  
    // Animation
    function afterAnimation() {
      const pageClasses = 'page-previous page-current page-next';
      const navbarClasses = 'navbar-previous navbar-current navbar-next';
      $newPage.removeClass(pageClasses).addClass('page-current').removeAttr('aria-hidden');
      $oldPage.removeClass(pageClasses).addClass('page-previous').attr('aria-hidden', 'true');
      if (dynamicNavbar) {
        $newNavbarInner.removeClass(navbarClasses).addClass('navbar-current').removeAttr('aria-hidden');
        $oldNavbarInner.removeClass(navbarClasses).addClass('navbar-previous').attr('aria-hidden', 'true');
      }
      // After animation event
      router.allowPageChange = true;
      router.pageCallback('afterIn', $newPage, $newNavbarInner, 'next', 'current', options);
      router.pageCallback('afterOut', $oldPage, $oldNavbarInner, 'current', 'previous', options);
  
      let keepOldPage = app.theme === 'ios' ? (router.params.preloadPreviousPage || router.params.iosSwipeBack) : router.params.preloadPreviousPage;
      if (!keepOldPage) {
        if ($newPage.hasClass('smart-select-page') || $newPage.hasClass('photo-browser-page') || $newPage.hasClass('autocomplete-page')) {
          keepOldPage = true;
        }
      }
      if (!keepOldPage) {
        if (router.params.stackPages) {
          $oldPage.addClass('stacked');
          if (separateNavbar) {
            $oldNavbarInner.addClass('stacked');
          }
        } else if (!($newPage.attr('data-name') && $newPage.attr('data-name') === 'smart-select-page')) {
          // Remove event
          router.pageCallback('beforeRemove', $oldPage, $oldNavbarInner, 'previous', undefined, options);
          router.removePage($oldPage);
          if (separateNavbar && $oldNavbarInner.length) {
            router.removeNavbar($oldNavbarInner);
          }
        }
      }
      router.emit('routeChanged', router.currentRoute, router.previousRoute, router);
  
      if (router.params.pushState) {
        History.clearRouterQueue();
      }
    }
    function setPositionClasses() {
      const pageClasses = 'page-previous page-current page-next';
      const navbarClasses = 'navbar-previous navbar-current navbar-next';
      $oldPage.removeClass(pageClasses).addClass('page-current').removeAttr('aria-hidden');
      $newPage.removeClass(pageClasses).addClass('page-next').removeAttr('aria-hidden');
      if (dynamicNavbar) {
        $oldNavbarInner.removeClass(navbarClasses).addClass('navbar-current').removeAttr('aria-hidden');
        $newNavbarInner.removeClass(navbarClasses).addClass('navbar-next').removeAttr('aria-hidden');
      }
    }
    if (options.animate) {
      const delay = router.app.theme === 'md' ? router.params.materialPageLoadDelay : router.params.iosPageLoadDelay;
      if (delay) {
        setTimeout(() => {
          setPositionClasses();
          router.animate($oldPage, $newPage, $oldNavbarInner, $newNavbarInner, 'forward', () => {
            afterAnimation();
          });
        }, delay);
      } else {
        setPositionClasses();
        router.animate($oldPage, $newPage, $oldNavbarInner, $newNavbarInner, 'forward', () => {
          afterAnimation();
        });
      }
    } else {
      afterAnimation();
    }
    return router;
  }
  function load(loadParams = {}, loadOptions = {}, ignorePageChange) {
    const router = this;
    if (!router.allowPageChange && !ignorePageChange) return router;
    const params = loadParams;
    const options = loadOptions;
    const { url, content, el, pageName, template, templateUrl, component, componentUrl } = params;
  
    if (!options.reloadCurrent &&
      options.route &&
      options.route.route &&
      options.route.route.parentPath &&
      router.currentRoute.route &&
      router.currentRoute.route.parentPath === options.route.route.parentPath) {
      // Do something nested
      if (options.route.url === router.url) {
        return false;
      }
      // Check for same params
      let sameParams = Object.keys(options.route.params).length === Object.keys(router.currentRoute.params).length;
      if (sameParams) {
        // Check for equal params name
        Object.keys(options.route.params).forEach((paramName) => {
          if (
            !(paramName in router.currentRoute.params) ||
            (router.currentRoute.params[paramName] !== options.route.params[paramName])
          ) {
            sameParams = false;
          }
        });
      }
      if (sameParams) {
        if (options.route.route.tab) {
          return router.tabLoad(options.route.route.tab, options);
        }
        return false;
      }
    }
  
    if (
      options.route &&
      options.route.url &&
      router.url === options.route.url &&
      !(options.reloadCurrent || options.reloadPrevious) &&
      !router.params.allowDuplicateUrls
    ) {
      return false;
    }
  
    if (!options.route && url) {
      options.route = router.parseRouteUrl(url);
      Utils.extend(options.route, { route: { url, path: url } });
    }
  
    // Component Callbacks
    function resolve(pageEl, newOptions) {
      return router.forward(pageEl, Utils.extend(options, newOptions));
    }
    function reject() {
      router.allowPageChange = true;
      return router;
    }
  
    if (url || templateUrl || componentUrl) {
      router.allowPageChange = false;
    }
  
    // Proceed
    if (content) {
      router.forward(router.getPageEl(content), options);
    } else if (template || templateUrl) {
      // Parse template and send page element
      try {
        router.pageTemplateLoader(template, templateUrl, options, resolve, reject);
      } catch (err) {
        router.allowPageChange = true;
        throw err;
      }
    } else if (el) {
      // Load page from specified HTMLElement or by page name in pages container
      router.forward(router.getPageEl(el), options);
    } else if (pageName) {
      // Load page by page name in pages container
      router.forward(router.$el.children(`.page[data-name="${pageName}"]`).eq(0), options);
    } else if (component || componentUrl) {
      // Load from component (F7/Vue/React/...)
      try {
        router.pageComponentLoader(router.el, component, componentUrl, options, resolve, reject);
      } catch (err) {
        router.allowPageChange = true;
        throw err;
      }
    } else if (url) {
      // Load using XHR
      if (router.xhr) {
        router.xhr.abort();
        router.xhr = false;
      }
      router.xhrRequest(url, options)
        .then((pageContent) => {
          router.forward(router.getPageEl(pageContent), options);
        })
        .catch(() => {
          router.allowPageChange = true;
        });
    }
    return router;
  }
  function navigate(navigateParams, navigateOptions = {}) {
    const router = this;
    let url;
    let createRoute;
    if (typeof navigateParams === 'string') {
      url = navigateParams;
    } else {
      url = navigateParams.url;
      createRoute = navigateParams.route;
    }
    const app = router.app;
    if (!router.view) {
      if (app.views.main) {
        app.views.main.router.navigate(url, navigateOptions);
      }
      return router;
    }
    if (url === '#' || url === '') {
      return router;
    }
  
    let navigateUrl = url.replace('./', '');
    if (navigateUrl[0] !== '/' && navigateUrl.indexOf('#') !== 0) {
      const currentPath = router.currentRoute.parentPath || router.currentRoute.path;
      navigateUrl = ((currentPath ? `${currentPath}/` : '/') + navigateUrl)
        .replace('///', '/')
        .replace('//', '/');
    }
    let route;
    if (createRoute) {
      route = Utils.extend(router.parseRouteUrl(navigateUrl), {
        route: Utils.extend({}, createRoute),
      });
    } else {
      route = router.findMatchingRoute(navigateUrl);
    }
  
    if (!route) {
      return router;
    }
  
    if (route.route.redirect) {
      return redirect.call(router, 'navigate', route, navigateOptions);
    }
  
    const options = {};
    if (route.route.options) {
      Utils.extend(options, route.route.options, navigateOptions, { route });
    } else {
      Utils.extend(options, navigateOptions, { route });
    }
    if (options && options.context) {
      route.context = options.context;
      options.route.context = options.context;
    }
    ('popup popover sheet loginScreen actions customModal').split(' ').forEach((modalLoadProp) => {
      if (route.route[modalLoadProp]) {
        router.modalLoad(modalLoadProp, route, options);
      }
    });
    ('url content component pageName el componentUrl template templateUrl').split(' ').forEach((pageLoadProp) => {
      if (route.route[pageLoadProp]) {
        router.load({ [pageLoadProp]: route.route[pageLoadProp] }, options);
      }
    });
    // Async
    function asyncResolve(resolveParams, resolveOptions) {
      router.allowPageChange = false;
      let resolvedAsModal = false;
      ('popup popover sheet loginScreen actions customModal').split(' ').forEach((modalLoadProp) => {
        if (resolveParams[modalLoadProp]) {
          resolvedAsModal = true;
          const modalRoute = Utils.extend({}, route, { route: resolveParams });
          router.allowPageChange = true;
          router.modalLoad(modalLoadProp, modalRoute, Utils.extend(options, resolveOptions));
        }
      });
      if (resolvedAsModal) return;
      router.load(resolveParams, Utils.extend(options, resolveOptions), true);
    }
    function asyncReject() {
      router.allowPageChange = true;
    }
    if (route.route.async) {
      router.allowPageChange = false;
  
      route.route.async.call(router, route, router.currentRoute, asyncResolve, asyncReject);
    }
    // Return Router
    return router;
  }
  export { refreshPage, forward, load, navigate };
  