text: // Copyright (c) 2019 Uber Technologies, Inc.
  //
  // Permission is hereby granted, free of charge, to any person obtaining a copy
  // of this software and associated documentation files (the "Software"), to deal
  // in the Software without restriction, including without limitation the rights
  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  // copies of the Software, and to permit persons to whom the Software is
  // furnished to do so, subject to the following conditions:
  //
  // The above copyright notice and this permission notice shall be included in
  // all copies or substantial portions of the Software.
  //
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  // THE SOFTWARE.
  
  import {
    DELETE_DATA_ID,
    ADD_DATA_ID,
    EXPORT_DATA_TYPE,
    RATIOS,
    RESOLUTIONS
  } from 'constants/default-settings';
  import {createNotification} from 'utils/notifications-utils';
  
  export const DEFAULT_ACTIVE_SIDE_PANEL = 'layer';
  export const DEFAULT_MODAL = ADD_DATA_ID;
  
  /**
   * Updaters for `uiState` reducer. Can be used in your root reducer to directly modify kepler.gl's state.
   * Read more about [Using updaters](../advanced-usage/using-updaters.md)
   *
   * @public
   * @example
   *
   * import keplerGlReducer, {uiStateUpdaters} from 'kepler.gl/reducers';
   * // Root Reducer
   * const reducers = combineReducers({
   *  keplerGl: keplerGlReducer,
   *  app: appReducer
   * });
   *
   * const composedReducer = (state, action) => {
   *  switch (action.type) {
   *    // click button to close side panel
   *    case 'CLICK_BUTTON':
   *      return {
   *        ...state,
   *        keplerGl: {
   *          ...state.keplerGl,
   *          foo: {
   *             ...state.keplerGl.foo,
   *             uiState: uiStateUpdaters.toggleSidePanelUpdater(
   *               uiState, {payload: null}
   *             )
   *          }
   *        }
   *      };
   *  }
   *  return reducers(state, action);
   * };
   *
   * export default composedReducer;
   */
  /* eslint-disable no-unused-vars */
   const uiStateUpdaters = null;
  /* eslint-enable no-unused-vars */
  
  /**
   * A list of map control visibility and whether is it active.
   * @memberof uiStateUpdaters
   * @constant
   * @type {Object}
   * @property {Object} visibleLayers Default: `{show: true, active: false}`
   * @property {Object} mapLegend Default: `{show: true, active: false}`
   * @property {Object} toggle3d Default: `{show: true}`
   * @property {Object} splitMap Default: `{show: true}`
   * @public
   */
  export const DEFAULT_MAP_CONTROLS = {
    visibleLayers: {
      show: true,
      active: false
    },
    mapLegend: {
      show: true,
      active: false
    },
    toggle3d: {
      show: true
    },
    splitMap: {
      show: true
    }
  };
  
  /**
   * Default image export config
   * @memberof uiStateUpdaters
   * @constant
   * @type {Object}
   * @property {string} ratio Default: `'SCREEN'`,
   * @property {string} resolution Default: `'ONE_X'`,
   * @property {boolean} legend Default: `false`,
   * @property {string} imageDataUri Default: `''`,
   * @property {boolean} exporting Default: `false`
   * @public
   */
  export const DEFAULT_EXPORT_IMAGE = {
    // user options
    ratio: RATIOS.SCREEN,
    resolution: RESOLUTIONS.ONE_X,
    legend: false,
    // exporting state
    imageDataUri: '',
    exporting: false
  };
  
  /**
   * Default initial `exportData` settings
   * @memberof uiStateUpdaters
   * @constant
   * @type {Object}
   * @property {string} selectedDataset Default: `''`,
   * @property {string} dataType Default: `'csv'`,
   * @property {boolean} filtered Default: `true`,
   * @property {boolean} config deprecated
   * @property {boolean} data used in modal config export. Default: `false`
   * @public
   */
  export const DEFAULT_EXPORT_DATA = {
    selectedDataset: '',
    dataType: EXPORT_DATA_TYPE.CSV,
    filtered: true,
    config: false, // no longer used, since we removed the option to export config from modal data export
    data: false // this is used in modal config export
  };
  
  export const DEFAULT_NOTIFICATIONS = [];
  
  /**
   * Default initial `uiState`
   * @memberof uiStateUpdaters
   * @constant
   * @type {Object}
   * @property {boolean} readOnly Default: `false`
   * @property {string} activeSidePanel Default: `'layer'`
   * @property {string|null} currentModal Default: `'addData'`
   * @property {string|null} datasetKeyToRemove Default: `null`
   * @property {string|null} visibleDropdown Default: `null`
   * @property {Object} exportImage Default: [`DEFAULT_EXPORT_IMAGE`](#default_export_image)
   * @property {Object} exportData Default: [`DEFAULT_EXPORT_DATA`](#default_export_data)
   * @property {Object} mapControls Default: [`DEFAULT_MAP_CONTROLS`](#default_map_controls)
   * @public
   */
  export const INITIAL_UI_STATE = {
    readOnly: false,
    activeSidePanel: DEFAULT_ACTIVE_SIDE_PANEL,
    currentModal: DEFAULT_MODAL,
    datasetKeyToRemove: null,
    visibleDropdown: null,
    // export image modal ui
    exportImage: DEFAULT_EXPORT_IMAGE,
    // export data modal ui
    exportData: DEFAULT_EXPORT_DATA,
    // map control panels
    mapControls: DEFAULT_MAP_CONTROLS,
    // ui notifications
    notifications: DEFAULT_NOTIFICATIONS
  };
  
  /* Updaters */
  /**
   * Toggle active side panel
   * @memberof uiStateUpdaters
   * @param {Object} state `uiState`
   * @param {Object} action
   * @param {string|null} action.payload id of side panel to be shown, one of `layer`, `filter`, `interaction`, `map`. close side panel if `null`
   * @returns {Object} nextState
   * @public
   */
  export const toggleSidePanelUpdater = (state, {payload: id}) => {
    if (id === state.activeSidePanel) {
      return state;
    }
  
    return {
      ...state,
      activeSidePanel: id
    };
  };
  
  /**
   * Show and hide modal dialog
   * @memberof uiStateUpdaters
   * @param {Object} state `uiState`
   * @param {Object} action
   * @param {string|null} action.payload id of modal to be shown, null to hide modals. One of:
   *
   *  - [`DATA_TABLE_ID`](../constants/default-settings.md#data_table_id)
   *  - [`DELETE_DATA_ID`](../constants/default-settings.md#delete_data_id)
   *  - [`ADD_DATA_ID`](../constants/default-settings.md#add_data_id)
   *  - [`EXPORT_IMAGE_ID`](../constants/default-settings.md#export_image_id)
   *  - [`EXPORT_DATA_ID`](../constants/default-settings.md#export_data_id)
   *  - [`EXPORT_CONFIG_ID`](../constants/default-settings.md#export_config_id)
   *  - [`ADD_MAP_STYLE_ID`](../constants/default-settings.md#add_map_style_id)
   * @returns {Object} nextState
   * @public
   */
  export const toggleModalUpdater = (state, {payload: id}) => ({
    ...state,
    currentModal: id
  });
  
  /**
   * Hide and show side panel header dropdown, activated by clicking the share link on top of the side panel
   * @memberof uiStateUpdaters
   * @param {Object} state `uiState`
   * @param {Object} action
   * @param {string} action.payload id of the dropdown
   * @returns {Object} nextState
   * @public
   */
  export const showExportDropdownUpdater = (state, {payload: id}) => ({
    ...state,
    visibleDropdown: id
  });
  
  /**
   * Hide side panel header dropdown, activated by clicking the share link on top of the side panel
   * @memberof uiStateUpdaters
   * @param {Object} state `uiState`
   * @returns {Object} nextState
   * @public
   */
  export const hideExportDropdownUpdater = (state) => ({
    ...state,
    visibleDropdown: null
  });
  
  /**
   * Toggle active map control panel
   * @memberof uiStateUpdaters
   * @param {Object} state `uiState`
   * @param {Object} action action
   * @param {string} action.payload map control panel id, one of the keys of: [`DEFAULT_MAP_CONTROLS`](#default_map_controls)
   * @returns {Object} nextState
   * @public
   */
  export const toggleMapControlUpdater = (state, {payload: panelId}) => ({
    ...state,
    mapControls: {
      ...state.mapControls,
      [panelId]: {
        ...state.mapControls[panelId],
        active: !state.mapControls[panelId].active
      }
    }
  });
  
  /**
   * Toggle active map control panel
   * @memberof uiStateUpdaters
   * @param {Object} state `uiState`
   * @param {Object} action
   * @param {string} action.payload dataset id
   * @returns {Object} nextState
   * @public
   */
  export const openDeleteModalUpdater = (
    state,
    {payload: datasetKeyToRemove}
  ) => ({
    ...state,
    currentModal: DELETE_DATA_ID,
    datasetKeyToRemove
  });
  
  /**
   * Set `exportImage.legend` to `true` or `false`
   * @memberof uiStateUpdaters
   * @param {Object} state `uiState`
   * @returns {Object} nextState
   * @public
   */
  export const toggleLegendUpdater = state => ({
    ...state,
    exportImage: {
      ...state.exportImage,
      legend: !state.exportImage.legend
    }
  });
  
  /**
   * Set `exportImage.ratio`
   * @memberof uiStateUpdaters
   * @param {Object} state `uiState`
   * @param {Object} action
   * @param {string} action.payload one of `'SCREEN'`, `'FOUR_BY_THREE'` and `'SIXTEEN_BY_NINE'`
   * @returns {Object} nextState
   * @public
   */
  export const setRatioUpdater = (state, {payload}) => ({
    ...state,
    exportImage: {
      ...state.exportImage,
      ratio: payload.ratio
    }
  });
  
  /**
   * Set `exportImage.resolution`
   * @memberof uiStateUpdaters
   * @param {Object} state `uiState`
   * @param {Object} action
   * @param {string} action.payload one of `'ONE_X'`, `'TWO_X'`
   * @returns {Object} nextState
   * @public
   */
  export const setResolutionUpdater = (state, {payload}) => ({
    ...state,
    exportImage: {
      ...state.exportImage,
      resolution: payload.resolution
    }
  });
  
  /**
   * Set `exportImage.exporting` to `true`
   * @memberof uiStateUpdaters
   * @param {Object} state `uiState`
   * @returns {Object} nextState
   * @public
   */
  export const startExportingImage = state => ({
    ...state,
    exportImage: {
      ...state.exportImage,
      exporting: true,
      imageDataUri: ''
    }
  });
  
  /**
   * Set `exportImage.setExportImageDataUri` to a image dataUri
   * @memberof uiStateUpdaters
   * @param {Object} state `uiState`
   * @param {Object} action
   * @param {string} action.payload export image data uri
   * @returns {Object} nextState
   * @public
   */
  export const setExportImageDataUri = (state, {payload: dataUri}) => ({
    ...state,
    exportImage: {
      ...state.exportImage,
      exporting: false,
      imageDataUri: dataUri
    }
  });
  
  /**
   * Delete cached export image
   * @memberof uiStateUpdaters
   * @param {Object} state `uiState`
   * @returns {Object} nextState
   * @public
   */
  export const cleanupExportImage = state => ({
    ...state,
    exportImage: {
      ...state.exportImage,
      exporting: false,
      imageDataUri: ''
    }
  });
  
  /**
   * Set selected dataset for export
   * @memberof uiStateUpdaters
   * @param {Object} state `uiState`
   * @param {Object} action
   * @param {string} action.payload dataset id
   * @returns {Object} nextState
   * @public
   */
  export const setExportSelectedDatasetUpdater = (state, {payload: dataset}) => ({
    ...state,
    exportData: {
      ...state.exportData,
      selectedDataset: dataset
    }
  });
  
  /**
   * Set data format for exporting data
   * @memberof uiStateUpdaters
   * @param {Object} state `uiState`
   * @param {Object} action
   * @param {string} action.payload one of `'text/csv'`
   * @returns {Object} nextState
   * @public
   */
  export const setExportDataTypeUpdater = (state, {payload: dataType}) => ({
    ...state,
    exportData: {
      ...state.exportData,
      dataType
    }
  });
  
  /**
   * Whether to export filtered data, `true` or `false`
   * @memberof uiStateUpdaters
   * @param {Object} state `uiState`
   * @param {Object} action
   * @param {boolean} action.payload
   * @returns {Object} nextState
   * @public
   */
  export const setExportFilteredUpdater = (state, {payload: filtered}) => ({
    ...state,
    exportData: {
      ...state.exportData,
      filtered
    }
  });
  
  /**
   * Whether to including data in map config, toggle between `true` or `false`
   * @memberof uiStateUpdaters
   * @param {Object} state `uiState`
   * @returns {Object} nextState
   * @public
   */
  export const setExportDataUpdater = (state, action) => ({
    ...state,
    exportData: {
      ...state.exportData,
      data: !state.exportData.data
    }
  });
  
  /**
   * Add a notification to be displayed
   * @memberof uiStateUpdaters
   * @param {Object} state `uiState`
   * @param {Object} action
   * @param {Object} action.payload
   * @returns {Object} nextState
   * @public
   */
  export const addNotificationUpdater = (state, {payload}) => ({
    ...state,
    notifications: [
      ...(state.notifications || []),
      createNotification(payload)
    ]
  });
  
  /**
   * Remove a notification
   * @memberof uiStateUpdaters
   * @param {Object} state `uiState`
   * @param {Object} action
   * @param {String} action.payload id of the notification to be removed
   * @returns {Object} nextState
   */
  export const removeNotificationUpdater = (state, {payload: id}) => ({
    ...state,
    notifications: state.notifications.filter(n => n.id !== id)
  });
  