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

const LIST_UPDATED_TOPIC     = "plugins-list-updated";

var { MockRegistrar } = ChromeUtils.import("resource://testing-common/MockRegistrar.jsm", {});

function PluginTag(name, description) {
  this.name = name;
  this.description = description;
}

PluginTag.prototype = {
  name: null,
  description: null,
  version: "1.0",
  filename: null,
  fullpath: null,
  disabled: false,
  blocklisted: false,
  clicktoplay: false,

  mimeTypes: [],

  getMimeTypes(count) {
    count.value = this.mimeTypes.length;
    return this.mimeTypes;
  }
};

const PLUGINS = [
  // A standalone plugin
  new PluginTag("Java", "A mock Java plugin"),

  // A plugin made up of two plugin files
  new PluginTag("Flash", "A mock Flash plugin"),
  new PluginTag("Flash", "A mock Flash plugin")
];

const gPluginHost = {
  // nsIPluginHost
  getPluginTags(count) {
    count.value = PLUGINS.length;
    return PLUGINS;
  },

  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPluginHost])
};

MockRegistrar.register("@mozilla.org/plugin/host;1", gPluginHost);

// This verifies that when the list of plugins changes the add-ons manager
// correctly updates
function run_test() {
  do_test_pending();
  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");

  Services.prefs.setBoolPref("media.gmp-provider.enabled", false);

  startupManager();
  AddonManager.addAddonListener(AddonListener);
  AddonManager.addInstallListener(InstallListener);

  run_test_1();
}

function end_test() {
  executeSoon(do_test_finished);
}

function sortAddons(addons) {
  addons.sort(function(a, b) {
    return a.name.localeCompare(b.name);
  });
}

// Basic check that the mock object works
async function run_test_1() {
  let addons = await AddonManager.getAddonsByTypes(["plugin"]);
  sortAddons(addons);

  Assert.equal(addons.length, 2);

  Assert.equal(addons[0].name, "Flash");
  Assert.ok(!addons[0].userDisabled);
  Assert.equal(addons[1].name, "Java");
  Assert.ok(!addons[1].userDisabled);

  run_test_2();
}

// No change to the list should not trigger any events or changes in the API
async function run_test_2() {
  // Reorder the list a bit
  let tag = PLUGINS[0];
  PLUGINS[0] = PLUGINS[2];
  PLUGINS[2] = PLUGINS[1];
  PLUGINS[1] = tag;

  Services.obs.notifyObservers(null, LIST_UPDATED_TOPIC);

  let addons = await AddonManager.getAddonsByTypes(["plugin"]);
  sortAddons(addons);

  Assert.equal(addons.length, 2);

  Assert.equal(addons[0].name, "Flash");
  Assert.ok(!addons[0].userDisabled);
  Assert.equal(addons[1].name, "Java");
  Assert.ok(!addons[1].userDisabled);

  run_test_3();
}

// Tests that a newly detected plugin shows up in the API and sends out events
async function run_test_3() {
  let tag = new PluginTag("Quicktime", "A mock Quicktime plugin");
  PLUGINS.push(tag);
  let id = tag.name + tag.description;

  let test_params = {};
  test_params[id] = [
    ["onInstalling", false],
    "onInstalled"
  ];

  prepare_test(test_params, [
    "onExternalInstall"
  ]);

  Services.obs.notifyObservers(null, LIST_UPDATED_TOPIC);

  ensure_test_completed();

  let addons = await AddonManager.getAddonsByTypes(["plugin"]);
  sortAddons(addons);

  Assert.equal(addons.length, 3);

  Assert.equal(addons[0].name, "Flash");
  Assert.ok(!addons[0].userDisabled);
  Assert.equal(addons[1].name, "Java");
  Assert.ok(!addons[1].userDisabled);
  Assert.equal(addons[2].name, "Quicktime");
  Assert.ok(!addons[2].userDisabled);

  run_test_4();
}

// Tests that a removed plugin disappears from in the API and sends out events
async function run_test_4() {
  let tag = PLUGINS.splice(1, 1)[0];
  let id = tag.name + tag.description;

  let test_params = {};
  test_params[id] = [
    ["onUninstalling", false],
    "onUninstalled"
  ];

  prepare_test(test_params);

  Services.obs.notifyObservers(null, LIST_UPDATED_TOPIC);

  ensure_test_completed();

  let addons = await AddonManager.getAddonsByTypes(["plugin"]);
  sortAddons(addons);

  Assert.equal(addons.length, 2);

  Assert.equal(addons[0].name, "Flash");
  Assert.ok(!addons[0].userDisabled);
  Assert.equal(addons[1].name, "Quicktime");
  Assert.ok(!addons[1].userDisabled);

  run_test_5();
}

// Removing part of the flash plugin should have no effect
async function run_test_5() {
  PLUGINS.splice(0, 1);

  Services.obs.notifyObservers(null, LIST_UPDATED_TOPIC);

  ensure_test_completed();

  let addons = await AddonManager.getAddonsByTypes(["plugin"]);
  sortAddons(addons);

  Assert.equal(addons.length, 2);

  Assert.equal(addons[0].name, "Flash");
  Assert.ok(!addons[0].userDisabled);
  Assert.equal(addons[1].name, "Quicktime");
  Assert.ok(!addons[1].userDisabled);

  run_test_6();
}

// Replacing flash should be detected
async function run_test_6() {
  let oldTag = PLUGINS.splice(0, 1)[0];
  let newTag = new PluginTag("Flash 2", "A new crash-free Flash!");
  newTag.disabled = true;
  PLUGINS.push(newTag);

  let test_params = {};
  test_params[oldTag.name + oldTag.description] = [
    ["onUninstalling", false],
    "onUninstalled"
  ];
  test_params[newTag.name + newTag.description] = [
    ["onInstalling", false],
    "onInstalled"
  ];

  prepare_test(test_params, [
    "onExternalInstall"
  ]);

  Services.obs.notifyObservers(null, LIST_UPDATED_TOPIC);

  ensure_test_completed();

  let addons = await AddonManager.getAddonsByTypes(["plugin"]);
  sortAddons(addons);

  Assert.equal(addons.length, 2);

  Assert.equal(addons[0].name, "Flash 2");
  Assert.ok(addons[0].userDisabled);
  Assert.equal(addons[1].name, "Quicktime");
  Assert.ok(!addons[1].userDisabled);

  run_test_7();
}

// If new tags are detected and the disabled state changes then we should send
// out appropriate notifications
async function run_test_7() {
  PLUGINS[0] = new PluginTag("Quicktime", "A mock Quicktime plugin");
  PLUGINS[0].disabled = true;
  PLUGINS[1] = new PluginTag("Flash 2", "A new crash-free Flash!");

  let test_params = {};
  test_params[PLUGINS[0].name + PLUGINS[0].description] = [
    ["onDisabling", false],
    "onDisabled"
  ];
  test_params[PLUGINS[1].name + PLUGINS[1].description] = [
    ["onEnabling", false],
    "onEnabled"
  ];

  prepare_test(test_params);

  Services.obs.notifyObservers(null, LIST_UPDATED_TOPIC);

  ensure_test_completed();

  let addons = await AddonManager.getAddonsByTypes(["plugin"]);
  sortAddons(addons);

  Assert.equal(addons.length, 2);

  Assert.equal(addons[0].name, "Flash 2");
  Assert.ok(!addons[0].userDisabled);
  Assert.equal(addons[1].name, "Quicktime");
  Assert.ok(addons[1].userDisabled);

  end_test();
}
