/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

/* import-globals-from head.js */

/**
 * Temporarily flip all the preferences necessary for service worker testing.
 */
async function enableServiceWorkerDebugging() {
  // Enable service workers.
  await pushPref("dom.serviceWorkers.enabled", true);

  // Accept workers from mochitest's http (normally only available in https).
  await pushPref("dom.serviceWorkers.testing.enabled", true);

  // Force single content process. Necessary until sw e10s refactor is done (Bug 1231208).
  await pushPref("dom.ipc.processCount", 1);
  Services.ppmm.releaseCachedProcesses();
}
/* exported enableServiceWorkerDebugging */

/**
 * Helper to listen once on a message sent using postMessage from the provided tab.
 *
 * @param {Tab} tab
 *        The tab on which the message will be received.
 * @param {String} message
 *        The name of the expected message.
 */
function onTabMessage(tab, message) {
  const mm = tab.linkedBrowser.messageManager;
  return new Promise(resolve => {
    mm.addMessageListener(message, function listener() {
      mm.removeMessageListener(message, listener);
      resolve();
    });
  });
}
/* exported onTabMessage */

async function _waitForServiceWorkerStatus(workerText, status, document) {
  await waitUntil(() => {
    const target = findDebugTargetByText(workerText, document);
    const statusElement = target && target.querySelector(".qa-worker-status");
    return statusElement && statusElement.textContent === status;
  });

  return findDebugTargetByText(workerText, document);
}
/* exported waitForServiceWorkerRunning */

async function waitForServiceWorkerStopped(workerText, document) {
  return _waitForServiceWorkerStatus(workerText, "Stopped", document);
}
/* exported waitForServiceWorkerStopped */

async function waitForServiceWorkerRunning(workerText, document) {
  return _waitForServiceWorkerStatus(workerText, "Running", document);
}
/* exported waitForServiceWorkerRunning */

async function waitForServiceWorkerRegistering(workerText, document) {
  return _waitForServiceWorkerStatus(workerText, "Registering", document);
}
/* exported waitForServiceWorkerRegistering */

async function waitForRegistration(tab) {
  info("Wait until the registration appears on the window");
  const swBrowser = tab.linkedBrowser;
  await asyncWaitUntil(async () =>
    SpecialPowers.spawn(swBrowser, [], async function() {
      return !!(await content.wrappedJSObject.getRegistration());
    })
  );
}
/* exported waitForRegistration */

/**
 * Helper to listen once on a message sent using postMessage from the provided tab.
 *
 * @param {Tab} tab
 *        The tab on which the message will be received.
 * @param {String} message
 *        The name of the expected message.
 */
function forwardServiceWorkerMessage(tab) {
  info("Make the test page notify us when the service worker sends a message.");
  return ContentTask.spawn(tab.linkedBrowser, {}, function() {
    const win = content.wrappedJSObject;
    win.navigator.serviceWorker.addEventListener("message", function(event) {
      sendAsyncMessage(event.data);
    });
  });
}
/* exported forwardServiceWorkerMessage */

/**
 * Unregister the service worker from the content page. The content page should define
 * `getRegistration` to allow this helper to retrieve the service worker registration that
 * should be unregistered.
 *
 * @param {Tab} tab
 *        The tab on which the service worker should be removed.
 */
async function unregisterServiceWorker(tab) {
  return SpecialPowers.spawn(tab.linkedBrowser, [], function() {
    const win = content.wrappedJSObject;
    // Check that the content page defines getRegistration.
    is(
      typeof win.getRegistration,
      "function",
      "getRegistration is a valid function"
    );
    win.getRegistration().unregister();
  });
}
/* exported unregisterServiceWorker */
