"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.resetForm = resetForm;
exports.setQueryParam = setQueryParam;
exports.parseUrlQueryString = parseUrlQueryString;
exports.formChanged = formChanged;
exports.checkShouldReplanTrip = checkShouldReplanTrip;
exports.storeDefaultSettings = exports.clearDefaultSettings = exports.setActiveSearch = exports.clearActiveSearch = exports.settingQueryParam = void 0;

require("core-js/modules/web.dom.iterable");

var _coreUtils = _interopRequireDefault(require("@opentripplanner/core-utils"));

var _lodash = _interopRequireDefault(require("lodash.debounce"));

var _lodash2 = _interopRequireDefault(require("lodash.isequal"));

var _moment = _interopRequireDefault(require("moment"));

var _qs = _interopRequireDefault(require("qs"));

var _reduxActions = require("redux-actions");

var _state = require("../util/state");

var _api = require("./api");

var _map = require("./map");

var _ui = require("./ui");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

const {
  getDefaultQuery,
  getTripOptionsFromQuery,
  getUrlParams,
  planParamsToQueryAsync
} = _coreUtils.default.query;
const settingQueryParam = (0, _reduxActions.createAction)('SET_QUERY_PARAM');
exports.settingQueryParam = settingQueryParam;
const clearActiveSearch = (0, _reduxActions.createAction)('CLEAR_ACTIVE_SEARCH');
exports.clearActiveSearch = clearActiveSearch;
const setActiveSearch = (0, _reduxActions.createAction)('SET_ACTIVE_SEARCH');
exports.setActiveSearch = setActiveSearch;
const clearDefaultSettings = (0, _reduxActions.createAction)('CLEAR_DEFAULT_SETTINGS');
exports.clearDefaultSettings = clearDefaultSettings;
const storeDefaultSettings = (0, _reduxActions.createAction)('STORE_DEFAULT_SETTINGS');
/**
 * Reset the trip form parameters to their default values.
 * @param {Boolean} [full=false] if set to true, the from/to locations and URL
 *  query parameters will also be reset.
 */

exports.storeDefaultSettings = storeDefaultSettings;

function resetForm(full = false) {
  return function (dispatch, getState) {
    const state = getState();
    const {
      transitModes
    } = state.otp.config.modes;

    if (state.otp.user.defaults) {
      dispatch(settingQueryParam(state.otp.user.defaults));
    } else {
      // Get user overrides and apply to default query
      const userOverrides = _coreUtils.default.storage.getItem('defaultQuery', {});

      const defaultQuery = Object.assign(getDefaultQuery(state.otp.config), userOverrides); // Filter out non-options (i.e., date, places).

      const options = getTripOptionsFromQuery(defaultQuery); // Default mode is currently WALK,TRANSIT. We need to update this value
      // here to match the list of modes, otherwise the form will break.

      options.mode = ['WALK', ...transitModes.map(m => m.mode)].join(',');
      dispatch(settingQueryParam(options));
    }

    if (full) {
      // If fully resetting form, also clear the active search, from/to
      // locations, and query params.
      dispatch(clearActiveSearch());
      dispatch((0, _map.setLocation)({
        location: null,
        locationType: 'from'
      }));
      dispatch((0, _map.setLocation)({
        location: null,
        locationType: 'to'
      })); // Get query params. Delete everything except sessionId.

      const params = getUrlParams();

      for (const key in params) {
        if (key !== 'sessionId') delete params[key];
      }

      dispatch((0, _ui.routeTo)('/', _qs.default.stringify(params, {
        addQueryPrefix: true
      })));
    }
  };
}
/**
 * Action to update any specified query parameter. Replaces previous series of
 * parameter-specific actions. If a search ID is provided, a routing query (OTP
 * search) will be kicked off immediately.
 */


function setQueryParam(payload, searchId) {
  return function (dispatch, getState) {
    dispatch(settingQueryParam(payload));
    if (searchId) dispatch((0, _api.routingQuery)(searchId));
  };
}
/**
 * An action that parses the active URL's query params (or whatever is passed in)
 * and updates the state with the OTP plan query params. A new search will be
 * performed according to the behavior of setQueryParam (i.e., if the passed
 * searchId is not null).
 * @param  {Object} params an object containing URL query params
 * @param  {string} source optionally contains the source of the query params
 *                         (e.g., _CALL indicates that the source is from a past
 *                         query made during a call taker session, to prevent
 *                         a search from being added to the current call)
 */


function parseUrlQueryString(params = getUrlParams(), source) {
  return function (dispatch, getState) {
    // Filter out the OTP (i.e. non-UI) params and set the initial query
    const planParams = {};
    Object.keys(params).forEach(key => {
      if (!key.startsWith('ui_')) planParams[key] = params[key];
    });

    let searchId = params.ui_activeSearch || _coreUtils.default.storage.randId();

    if (source) searchId += source; // Convert strings to numbers/objects and dispatch

    planParamsToQueryAsync(planParams, getState().otp.config).then(query => dispatch(setQueryParam(query, searchId)));
  };
}

let debouncedPlanTrip; // store as variable here, so it can be reused.

let lastDebouncePlanTimeMs;
/**
 * This action is dispatched when a change between the old query and new query
 * is detected. It handles checks for whether the trip should be replanned
 * (based on autoPlan strategies) as well as updating the UI state (esp. for
 * mobile).
 */

function formChanged(oldQuery, newQuery) {
  return function (dispatch, getState) {
    const state = getState();
    const {
      config,
      currentQuery,
      ui
    } = state.otp;
    const {
      autoPlan,
      debouncePlanTimeMs
    } = config;

    const isMobile = _coreUtils.default.ui.isMobile();

    const {
      fromChanged,
      oneLocationChanged,
      shouldReplanTrip,
      toChanged
    } = checkShouldReplanTrip(autoPlan, isMobile, oldQuery, newQuery); // If departArrive is set to 'NOW', update the query time to current

    if (currentQuery.departArrive === 'NOW') {
      const now = (0, _moment.default)().format(_coreUtils.default.time.OTP_API_TIME_FORMAT);
      dispatch(settingQueryParam({
        time: now
      }));
    } // Only clear the main panel if a single location changed. This prevents
    // clearing the panel on load if the app is focused on a stop viewer but a
    // search query should also be visible.


    if (oneLocationChanged) {
      dispatch((0, _ui.setMainPanelContent)(null));
    }

    if (!shouldReplanTrip) {
      // If not replanning the trip, clear the current search when either
      // location changes.
      if (fromChanged || toChanged) {
        dispatch(clearActiveSearch()); // Return to search screen on mobile only if not currently on welcome
        // screen (otherwise when the current position is auto-set the screen
        // will change unexpectedly).

        if (ui.mobileScreen !== _ui.MobileScreens.WELCOME_SCREEN) {
          dispatch((0, _ui.setMobileScreen)(_ui.MobileScreens.SEARCH_FORM));
        }
      }
    } else if ((0, _state.queryIsValid)(state)) {
      // If replanning trip and query is valid,
      // check if debouncing function needs to be (re)created.
      if (!debouncedPlanTrip || lastDebouncePlanTimeMs !== debouncePlanTimeMs) {
        debouncedPlanTrip = (0, _lodash.default)(() => dispatch((0, _api.routingQuery)()), debouncePlanTimeMs);
        lastDebouncePlanTimeMs = debouncePlanTimeMs;
      }

      debouncedPlanTrip();
    }
  };
}
/**
 * Check if the trip should be replanned based on the auto plan strategy,
 * whether the mobile view is active, and the old/new queries. Response type is
 * an object containing various booleans.
 */


function checkShouldReplanTrip(autoPlan, isMobile, oldQuery, newQuery) {
  // Determine if either from/to location has changed
  const fromChanged = !(0, _lodash2.default)(oldQuery.from, newQuery.from);
  const toChanged = !(0, _lodash2.default)(oldQuery.to, newQuery.to);
  const oneLocationChanged = fromChanged && !toChanged || !fromChanged && toChanged; // Check whether a trip should be auto-replanned

  const strategy = isMobile && (autoPlan === null || autoPlan === void 0 ? void 0 : autoPlan.mobile) ? autoPlan === null || autoPlan === void 0 ? void 0 : autoPlan.mobile : autoPlan === null || autoPlan === void 0 ? void 0 : autoPlan.default;
  const shouldReplanTrip = evaluateAutoPlanStrategy(strategy, fromChanged, toChanged, oneLocationChanged);
  return {
    fromChanged,
    oneLocationChanged,
    shouldReplanTrip,
    toChanged
  };
}
/**
 * Shorthand method to evaluate auto plan strategy. It is assumed that this is
 * being called within the context of the `formChanged` action, so presumably
 * some query param has already changed. If further checking of query params is
 * needed, additional strategies should be added.
 */


const evaluateAutoPlanStrategy = (strategy, fromChanged, toChanged, oneLocationChanged) => {
  switch (strategy) {
    case 'ONE_LOCATION_CHANGED':
      if (oneLocationChanged) return true;
      break;

    case 'BOTH_LOCATIONS_CHANGED':
      if (fromChanged && toChanged) return true;
      break;

    case 'ANY':
      return true;

    default:
      return false;
  }
};

//# sourceMappingURL=form.js