const TEST_URL = "http://www.example.com/browser/dom/tests/browser/dummy.html";

function pageScript() {
  window.addEventListener("beforeunload", function (event) {
    var str = "Leaving?";
    event.returnValue = str;
    return str;
  }, true);
}

function frameScript() {
  content.window.addEventListener("beforeunload", function (event) {
    sendAsyncMessage("Test:OnBeforeUnloadReceived");
    var str = "Leaving?";
    event.returnValue = str;
    return str;
  }, true);
}

// Wait for onbeforeunload dialog, and dismiss it immediately.
function awaitAndCloseBeforeUnloadDialog(doStayOnPage) {
  return new Promise(resolve => {
    function onDialogShown(node) {
      Services.obs.removeObserver(onDialogShown, "tabmodal-dialog-loaded");
      let button = doStayOnPage ? node.ui.button1 : node.ui.button0;
      button.click();
      resolve();
    }

    Services.obs.addObserver(onDialogShown, "tabmodal-dialog-loaded");
  });
}

SpecialPowers.pushPrefEnv(
  {"set": [["dom.require_user_interaction_for_beforeunload", false]]});

/**
 * Test navigation from a content page to a chrome page. Also check that only
 * one beforeunload event is fired.
 */
add_task(function* () {
  let beforeUnloadCount = 0;
  messageManager.addMessageListener("Test:OnBeforeUnloadReceived", function() {
    beforeUnloadCount++;
  });

  // Open a content page.
  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
  let browser = tab.linkedBrowser;

  ok(browser.isRemoteBrowser, "Browser should be remote.");
  browser.messageManager.loadFrameScript(
    "data:,(" + frameScript.toString() + ")();", true);

  // Navigate to a chrome page.
  let dialogShown1 = awaitAndCloseBeforeUnloadDialog(false);
  yield BrowserTestUtils.loadURI(browser, "about:support");
  yield Promise.all([
    dialogShown1,
    BrowserTestUtils.browserLoaded(browser)
  ]);
  is(beforeUnloadCount, 1, "Should have received one beforeunload event.");
  ok(!browser.isRemoteBrowser, "Browser should not be remote.");

  // Go back to content page.
  ok(gBrowser.webNavigation.canGoBack, "Should be able to go back.");
  gBrowser.goBack();
  yield BrowserTestUtils.browserLoaded(browser);
  browser.messageManager.loadFrameScript(
    "data:,(" + frameScript.toString() + ")();", true);

  // Test that going forward triggers beforeunload prompt as well.
  ok(gBrowser.webNavigation.canGoForward, "Should be able to go forward.");
  let dialogShown2 = awaitAndCloseBeforeUnloadDialog(false);
  gBrowser.goForward();
  yield Promise.all([
    dialogShown2,
    BrowserTestUtils.browserLoaded(browser)
  ]);
  is(beforeUnloadCount, 2, "Should have received two beforeunload events.");

  yield BrowserTestUtils.removeTab(tab);
});

/**
 * Test navigation from a chrome page to a content page. Also check that only
 * one beforeunload event is fired.
 */
add_task(function* () {
  let beforeUnloadCount = 0;
  messageManager.addMessageListener("Test:OnBeforeUnloadReceived", function() {
    beforeUnloadCount++;
  });

  // Open a chrome page.
  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser,
                                                        "about:support");
  let browser = tab.linkedBrowser;

  ok(!browser.isRemoteBrowser, "Browser should not be remote.");
  yield ContentTask.spawn(browser, null, function* () {
    content.window.addEventListener("beforeunload", function (event) {
      sendAsyncMessage("Test:OnBeforeUnloadReceived");
      var str = "Leaving?";
      event.returnValue = str;
      return str;
    }, true);
  });

  // Navigate to a content page.
  let dialogShown1 = awaitAndCloseBeforeUnloadDialog(false);
  yield BrowserTestUtils.loadURI(browser, TEST_URL);
  yield Promise.all([
    dialogShown1,
    BrowserTestUtils.browserLoaded(browser)
  ]);
  is(beforeUnloadCount, 1, "Should have received one beforeunload event.");
  ok(browser.isRemoteBrowser, "Browser should be remote.");

  // Go back to chrome page.
  ok(gBrowser.webNavigation.canGoBack, "Should be able to go back.");
  gBrowser.goBack();
  yield BrowserTestUtils.browserLoaded(browser);
  yield ContentTask.spawn(browser, null, function* () {
    content.window.addEventListener("beforeunload", function (event) {
      sendAsyncMessage("Test:OnBeforeUnloadReceived");
      var str = "Leaving?";
      event.returnValue = str;
      return str;
    }, true);
  });

  // Test that going forward triggers beforeunload prompt as well.
  ok(gBrowser.webNavigation.canGoForward, "Should be able to go forward.");
  let dialogShown2 = awaitAndCloseBeforeUnloadDialog(false);
  gBrowser.goForward();
  yield Promise.all([
    dialogShown2,
    BrowserTestUtils.browserLoaded(browser)
  ]);
  is(beforeUnloadCount, 2, "Should have received two beforeunload events.");

  yield BrowserTestUtils.removeTab(tab);
});