text: // Copyright 2020 The Google Research Authors.
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  goog.module('eeg_modelling.eeg_viewer.WindowLocation');
  
  const Dispatcher = goog.require('eeg_modelling.eeg_viewer.Dispatcher');
  const Store = goog.require('eeg_modelling.eeg_viewer.Store');
  
  class WindowLocation {
  
    constructor() {
      const store = Store.getInstance();
      // This listener callback will update the request parameters in the URL
      // hash and update the web history state accordingly.
      store.registerListener(
          Store.RequestProperties, 'WindowLocation',
          (store, changedProperties) =>
              this.handleRequestParams(store, changedProperties));
    }
  
    /**
     * Parses the URL fragment into a QueryData object.
     * @return {!Dispatcher.FragmentData} Dictionary of query data fields to
     * update store with.
     */
    parseFragment() {
      const fragmentData = {};
      const hash = location.hash.substring(1);
      if (hash) {
        const assignments = hash.split('&');
        assignments.forEach((assignment) => {
          const elements = assignment.split('=');
          if (elements.length < 2) {
            Dispatcher.getInstance().sendAction({
              actionType: Dispatcher.ActionType.ERROR,
              data: {
                message: 'Bad Fragment',
              },
            });
          }
          fragmentData[elements[0]] = decodeURIComponent(
              elements.slice(1).join('='));
        });
      }
  
      const actionData = {};
      Store.RequestProperties.forEach((storeParam) => {
        const param = storeParam.toLowerCase();
        const valid = (param in fragmentData &&
            (fragmentData[param] == 0 || fragmentData[param]));
        actionData[param] = valid ? fragmentData[param] : null;
      });
      return /** @type {!Dispatcher.FragmentData} */ (actionData);
    }
  
    /**
     * Creates a URL event that makes a data request.
     */
    makeDataRequest() {
      const fragmentData = this.parseFragment();
      Dispatcher.getInstance().sendAction({
        actionType: Dispatcher.ActionType.WINDOW_LOCATION_PENDING_REQUEST,
        data: fragmentData,
      });
    }
  
    /**
     * Converts store chunk data into a fragment string and sets the fragment.
     * Also handles browser history state based on whether the file parameters in
     * the request have changed.
     * @param {!Store.StoreData} store Store chunk data to use to update fragment.
     * @param {!Array<!Store.Property>} changedProperties List of the properties
     *     that changed because of the last action.
     */
    handleRequestParams(store, changedProperties) {
      if (!store.chunkGraphData) {
        return;
      }
  
      const fileParamDirty = Store.FileRequestProperties.some(
          (param) => changedProperties.includes(param));
      const assignments = Store.RequestProperties.map((param) => {
        const key = param.toLowerCase();
        let value = store[param];
        if (Store.FileRequestProperties.includes(param)) {
          value = value ? value : '';
        } else if (Store.ListRequestProperties.includes(param)) {
          value = value ? value.join(',') : '';
        }
        return `${key}=${value}`;
      });
      const url = '#' + assignments.join('&');
      if (fileParamDirty) {
        history.pushState({}, '', url);
      } else {
        history.replaceState({}, '', url);
      }
    }
  }
  
  goog.addSingletonGetter(WindowLocation);
  
  exports = WindowLocation;
  