/**
 * In this test, we check that the content can't open more than one popup at a
 * time (depending on "dom.allow_mulitple_popups" preference value).
 */

const TEST_DOMAIN = "http://example.net";
const TEST_PATH = "/browser/dom/base/test/";
const CHROME_DOMAIN = "chrome://mochitests/content";

requestLongerTimeout(2);

function WindowObserver(count) {
  return new Promise(resolve => {
    let windowObserver = function(aSubject, aTopic, aData) {
      if (aTopic != "domwindowopened") {
        return;
      }

      if (--count == 0) {
        Services.ww.unregisterNotification(windowObserver);
        resolve();
      }
    }
    Services.ww.registerNotification(windowObserver);
  });
}

add_task(async _ => {
  info("All opened if the pref is off");

  await SpecialPowers.pushPrefEnv({"set": [
    ["dom.block_multiple_popups", false],
    ["dom.disable_open_during_load", true],
  ]});

  let tab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html")
  gBrowser.selectedTab = tab;

  let browser = gBrowser.getBrowserForTab(tab);
  await BrowserTestUtils.browserLoaded(browser);

  let obs = new WindowObserver(2);

  await BrowserTestUtils.synthesizeMouseAtCenter("#openPopups", {}, tab.linkedBrowser);

  await obs;
  ok(true, "We had 2 windows.");

  await BrowserTestUtils.synthesizeMouseAtCenter("#closeAllWindows", {}, tab.linkedBrowser);

  BrowserTestUtils.removeTab(tab);
});

add_task(async _ => {
  info("2 window.open()s in a click event allowed because whitelisted domain.");

  await SpecialPowers.pushPrefEnv({"set": [
    ["dom.block_multiple_popups", true],
    ["dom.disable_open_during_load", true],
  ]});

  const uri = Services.io.newURI(TEST_DOMAIN);
  const principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});

  Services.perms.addFromPrincipal(principal, "popup", Services.perms.ALLOW_ACTION);

  let tab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html")
  gBrowser.selectedTab = tab;

  let browser = gBrowser.getBrowserForTab(tab);
  await BrowserTestUtils.browserLoaded(browser);

  let obs = new WindowObserver(2);

  await BrowserTestUtils.synthesizeMouseAtCenter("#openPopups", {}, tab.linkedBrowser);

  await obs;
  ok(true, "We had 2 windows.");

  await BrowserTestUtils.synthesizeMouseAtCenter("#closeAllWindows", {}, tab.linkedBrowser);

  BrowserTestUtils.removeTab(tab);

  await new Promise(aResolve => {
    Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_PERMISSIONS, value => {
      Assert.equal(value, 0);
      aResolve();
    });
  });
});

add_task(async _ => {
  info("2 window.open()s in a mouseup event allowed because whitelisted domain.");

  await SpecialPowers.pushPrefEnv({"set": [
    ["dom.block_multiple_popups", true],
    ["dom.disable_open_during_load", true],
  ]});

  const uri = Services.io.newURI(TEST_DOMAIN);
  const principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});

  Services.perms.addFromPrincipal(principal, "popup", Services.perms.ALLOW_ACTION);

  let tab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html")
  gBrowser.selectedTab = tab;

  let browser = gBrowser.getBrowserForTab(tab);
  await BrowserTestUtils.browserLoaded(browser);

  let obs = new WindowObserver(2);

  await BrowserTestUtils.synthesizeMouseAtCenter("#input", { type: "mouseup" }, tab.linkedBrowser);

  await obs;
  ok(true, "We had 2 windows.");

  await BrowserTestUtils.synthesizeMouseAtCenter("#closeAllWindows", {}, tab.linkedBrowser);

  BrowserTestUtils.removeTab(tab);

  await new Promise(aResolve => {
    Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_PERMISSIONS, value => {
      Assert.equal(value, 0);
      aResolve();
    });
  });
});

add_task(async _ => {
  info("2 window.open()s in a single click event: only the first one is allowed.");

  await SpecialPowers.pushPrefEnv({"set": [
    ["dom.block_multiple_popups", true],
    ["dom.disable_open_during_load", true],
  ]});

  let tab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html")
  gBrowser.selectedTab = tab;

  let browser = gBrowser.getBrowserForTab(tab);
  await BrowserTestUtils.browserLoaded(browser);

  let p = ContentTask.spawn(browser, null, () => {
    return new content.Promise(resolve => {
      content.addEventListener("DOMPopupBlocked", () => {
        ok(true, "The popup has been blocked");
        resolve();
      }, {once:true});
    });
  });

  let obs = new WindowObserver(1);

  await BrowserTestUtils.synthesizeMouseAtCenter("#openPopups", {}, tab.linkedBrowser);

  await p;
  await obs;
  ok(true, "We had only 1 window.");

  await BrowserTestUtils.synthesizeMouseAtCenter("#closeAllWindows", {}, tab.linkedBrowser);

  BrowserTestUtils.removeTab(tab);
});

add_task(async _ => {
  info("2 window.open()s in a single mouseup event: only the first one is allowed.");

  await SpecialPowers.pushPrefEnv({"set": [
    ["dom.block_multiple_popups", true],
    ["dom.disable_open_during_load", true],
  ]});

  let tab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html")
  gBrowser.selectedTab = tab;

  let browser = gBrowser.getBrowserForTab(tab);
  await BrowserTestUtils.browserLoaded(browser);

  let p = ContentTask.spawn(browser, null, () => {
    return new content.Promise(resolve => {
      content.addEventListener("DOMPopupBlocked", () => {
        ok(true, "The popup has been blocked");
        resolve();
      }, {once:true});
    });
  });

  let obs = new WindowObserver(1);

  await BrowserTestUtils.synthesizeMouseAtCenter("#input", { type: "mouseup" }, tab.linkedBrowser);

  await p;
  await obs;
  ok(true, "We had only 1 window.");

  await BrowserTestUtils.synthesizeMouseAtCenter("#closeAllWindows", {}, tab.linkedBrowser);

  BrowserTestUtils.removeTab(tab);
});

add_task(async _ => {
  info("2 window.open()s by non-event code: no windows allowed.");

  await SpecialPowers.pushPrefEnv({"set": [
    ["dom.block_multiple_popups", true],
    ["dom.disable_open_during_load", true],
  ]});

  let tab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html?openPopups")
  gBrowser.selectedTab = tab;

  let browser = gBrowser.getBrowserForTab(tab);
  await BrowserTestUtils.browserLoaded(browser);

  await ContentTask.spawn(browser, null, () => {
    return new content.Promise(resolve => {
      let count = 0;
      content.addEventListener("DOMPopupBlocked", function cb() {
        if (++count == 2) {
          content.removeEventListener("DOMPopupBlocked", cb);
          ok(true, "The popup has been blocked");
          resolve();
        }
      });

      let p = content.document.createElement("p");
      p.setAttribute('id', 'start');
      content.document.body.appendChild(p);
    });
  });

  ok(true, "We had 0 windows.");

  await BrowserTestUtils.synthesizeMouseAtCenter("#closeAllWindows", {}, tab.linkedBrowser);

  BrowserTestUtils.removeTab(tab);
});

add_task(async _ => {
  info("2 window.open()s by non-event code allowed by permission");

  await SpecialPowers.pushPrefEnv({"set": [
    ["dom.block_multiple_popups", true],
    ["dom.disable_open_during_load", true],
  ]});

  const uri = Services.io.newURI(TEST_DOMAIN);
  const principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});

  Services.perms.addFromPrincipal(principal, "popup", Services.perms.ALLOW_ACTION);

  let obs = new WindowObserver(2);

  let tab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html?openPopups")
  gBrowser.selectedTab = tab;

  let browser = gBrowser.getBrowserForTab(tab);
  await BrowserTestUtils.browserLoaded(browser);

  ok(true, "We had 2 windows.");

  await BrowserTestUtils.synthesizeMouseAtCenter("#closeAllWindows", {}, tab.linkedBrowser);

  BrowserTestUtils.removeTab(tab);

  await new Promise(aResolve => {
    Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_PERMISSIONS, value => {
      Assert.equal(value, 0);
      aResolve();
    });
  });
});

add_task(async _ => {
  info("1 window.open() executing another window.open(): only the first one is allowed.");

  await SpecialPowers.pushPrefEnv({"set": [
    ["dom.block_multiple_popups", true],
    ["dom.disable_open_during_load", true],
  ]});

  let tab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html")
  gBrowser.selectedTab = tab;

  let browser = gBrowser.getBrowserForTab(tab);
  await BrowserTestUtils.browserLoaded(browser);

  // We don't receive DOMPopupBlocked for nested windows. Let's use just the observer.
  let obs = new WindowObserver(1);

  await BrowserTestUtils.synthesizeMouseAtCenter("#openNestedPopups", {}, tab.linkedBrowser);

  await obs;
  ok(true, "We had 1 window.");

  await BrowserTestUtils.synthesizeMouseAtCenter("#closeAllWindows", {}, tab.linkedBrowser);

  BrowserTestUtils.removeTab(tab);
});

add_task(async _ => {
  info("window.open() and .click() on the element opening the window.");

  await SpecialPowers.pushPrefEnv({"set": [
    ["dom.block_multiple_popups", true],
    ["dom.disable_open_during_load", true],
  ]});

  let tab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html")
  gBrowser.selectedTab = tab;

  let browser = gBrowser.getBrowserForTab(tab);
  await BrowserTestUtils.browserLoaded(browser);

  let p = ContentTask.spawn(browser, null, () => {
    return new content.Promise(resolve => {
      content.addEventListener("DOMPopupBlocked", () => {
        ok(true, "The popup has been blocked");
        resolve();
      }, {once:true});
    });
  });

  let obs = new WindowObserver(1);

  await BrowserTestUtils.synthesizeMouseAtCenter("#openPopupAndClick", {}, tab.linkedBrowser);

  await p;
  await obs;
  ok(true, "We had only 1 window.");

  await BrowserTestUtils.synthesizeMouseAtCenter("#closeAllWindows", {}, tab.linkedBrowser);

  BrowserTestUtils.removeTab(tab);
});

add_task(async _ => {
  info("All opened from chrome.");

  await SpecialPowers.pushPrefEnv({"set": [
    ["dom.block_multiple_popups", true],
    ["dom.disable_open_during_load", true],
  ]});

  let tab = BrowserTestUtils.addTab(gBrowser, CHROME_DOMAIN + TEST_PATH + "browser_multiple_popups.html")
  gBrowser.selectedTab = tab;

  let browser = gBrowser.getBrowserForTab(tab);
  await BrowserTestUtils.browserLoaded(browser);

  let obs = new WindowObserver(2);

  await BrowserTestUtils.synthesizeMouseAtCenter("#openPopups", {}, tab.linkedBrowser);

  await obs;
  ok(true, "We had 2 windows.");

  await BrowserTestUtils.synthesizeMouseAtCenter("#closeAllWindows", {}, tab.linkedBrowser);

  BrowserTestUtils.removeTab(tab);
});
