"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.initialSourcesContentState = initialSourcesContentState;
exports.default = void 0;
loader.lazyRequireGetter(this, "_asyncValue", "devtools/client/debugger/src/utils/async-value");

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */

/**
 * Sources content reducer.
 *
 * This store the textual content for each source.
 */
function initialSourcesContentState() {
  return {
    /**
     * Text content of all the original sources.
     * This is large data, so this is only fetched on-demand for a subset of sources.
     * This state attribute is mutable in order to avoid cloning this possibly large map
     * on each new source. But selectors are never based on the map. Instead they only
     * query elements of the map.
     *
     * Map(source id => AsyncValue<String>)
     */
    mutableOriginalSourceTextContentMapBySourceId: new Map(),

    /**
     * Text content of all the generated sources.
     *
     * Map(source actor is => AsyncValue<String>)
     */
    mutableGeneratedSourceTextContentMapBySourceActorId: new Map(),

    /**
     * Incremental number that is bumped each time we navigate to a new page.
     *
     * This is used to better handle async race condition where we mix previous page data
     * with the new page. As sources are keyed by URL we may easily conflate the two page loads data.
     */
    epoch: 1
  };
}

function update(state = initialSourcesContentState(), action) {
  switch (action.type) {
    case "LOAD_ORIGINAL_SOURCE_TEXT":
      if (!action.source) {
        throw new Error("Missing source");
      }

      return updateSourceTextContent(state, action);

    case "LOAD_GENERATED_SOURCE_TEXT":
      if (!action.sourceActor) {
        throw new Error("Missing source actor.");
      }

      return updateSourceTextContent(state, action);

    case "REMOVE_SOURCES":
      return removeAllSourceTextContentForSourcesAndActors(state, action);
  }

  return state;
}
/*
 * Update a source's loaded text content.
 */


function updateSourceTextContent(state, action) {
  // If there was a navigation between the time the action was started and
  // completed, we don't want to update the store.
  if (action.epoch !== state.epoch) {
    return state;
  }

  let content;

  if (action.status === "start") {
    content = (0, _asyncValue.pending)();
  } else if (action.status === "error") {
    content = (0, _asyncValue.rejected)(action.error);
  } else if (typeof action.value.text === "string") {
    content = (0, _asyncValue.fulfilled)({
      type: "text",
      value: action.value.text,
      contentType: action.value.contentType
    });
  } else {
    content = (0, _asyncValue.fulfilled)({
      type: "wasm",
      value: action.value.text
    });
  }

  if (action.source && action.sourceActor) {
    throw new Error("Both the source and the source actor should not exist at the same time");
  }

  if (action.source) {
    state.mutableOriginalSourceTextContentMapBySourceId.set(action.source.id, content);
  }

  if (action.sourceActor) {
    state.mutableGeneratedSourceTextContentMapBySourceActorId.set(action.sourceActor.id, content);
  }

  return { ...state
  };
}

function removeAllSourceTextContentForSourcesAndActors(state, action) {
  if (!action.sources.length && !action.actors.length) {
    return state;
  }

  const originalSizeBefore = state.mutableOriginalSourceTextContentMapBySourceId.size;

  for (const source of action.sources) {
    state.mutableOriginalSourceTextContentMapBySourceId.delete(source.id);
  }

  const generatedSizeBefore = state.mutableGeneratedSourceTextContentMapBySourceActorId.size;

  for (const actor of action.actors) {
    state.mutableGeneratedSourceTextContentMapBySourceActorId.delete(actor.id);
  }

  if (originalSizeBefore != state.mutableOriginalSourceTextContentMapBySourceId.size || generatedSizeBefore != state.mutableGeneratedSourceTextContentMapBySourceActorId.size) {
    return { ...state
    };
  }

  return state;
}

var _default = update;
exports.default = _default;