/* 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/. */

const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;

const UNKNOWN_FAIL = ["geolocation", "desktop-notification"];

Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://webapprt/modules/WebappRT.jsm");

function ContentPermission() {}

ContentPermission.prototype = {
  classID: Components.ID("{07ef5b2e-88fb-47bd-8cec-d3b0bef11ac4}"),
  QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt]),

  _getChromeWindow: function(aWindow) { 
    return aWindow
      .QueryInterface(Ci.nsIInterfaceRequestor)
      .getInterface(Ci.nsIWebNavigation)
      .QueryInterface(Ci.nsIDocShellTreeItem)
      .rootTreeItem
      .QueryInterface(Ci.nsIInterfaceRequestor)
      .getInterface(Ci.nsIDOMWindow)
      .QueryInterface(Ci.nsIDOMChromeWindow);
  },

  prompt: function(request) {
    // Only allow exactly one permission request here.
    let types = request.types.QueryInterface(Ci.nsIArray);
    if (types.length != 1) {
      request.cancel();
      return;
    }
    let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);

    // Reuse any remembered permission preferences
    let result =
      Services.perms.testExactPermissionFromPrincipal(request.principal,
                                                      perm.type);

    // We used to use the name "geo" for the geolocation permission, now we're
    // using "geolocation".  We need to check both to support existing
    // installations.
    if ((result == Ci.nsIPermissionManager.UNKNOWN_ACTION ||
         result == Ci.nsIPermissionManager.PROMPT_ACTION) &&
        perm.type == "geolocation") {
      let geoResult = Services.perms.testExactPermission(request.principal.URI,
                                                         "geo");
      // We override the result only if the "geo" permission was allowed or
      // denied.
      if (geoResult == Ci.nsIPermissionManager.ALLOW_ACTION ||
          geoResult == Ci.nsIPermissionManager.DENY_ACTION) {
        result = geoResult;
      }
    }

    if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
      request.allow();
      return;
    } else if (result == Ci.nsIPermissionManager.DENY_ACTION ||
               (result == Ci.nsIPermissionManager.UNKNOWN_ACTION &&
                UNKNOWN_FAIL.indexOf(perm.type) >= 0)) {
      request.cancel();
      return;
    }

    // Display a prompt at the top level
    let {name} = WebappRT.localeManifest;
    let requestingWindow = request.window.top;
    let chromeWin = this._getChromeWindow(requestingWindow);
    let bundle = Services.strings.createBundle("chrome://webapprt/locale/webapp.properties");

    // Construct a prompt with share/don't and remember checkbox
    let remember = {value: false};
    let choice = Services.prompt.confirmEx(
      chromeWin,
      bundle.formatStringFromName(perm.type + ".title", [name], 1),
      bundle.GetStringFromName(perm.type + ".description"),
      // Set both buttons to strings with the cancel button being default
      Ci.nsIPromptService.BUTTON_POS_1_DEFAULT |
        Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_0 |
        Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_1,
      bundle.GetStringFromName(perm.type + ".allow"),
      bundle.GetStringFromName(perm.type + ".deny"),
      null,
      bundle.GetStringFromName(perm.type + ".remember"),
      remember);

    let action = Ci.nsIPermissionManager.ALLOW_ACTION;
    if (choice != 0) {
      action = Ci.nsIPermissionManager.DENY_ACTION;
    }

    if (remember.value) {
      // Persist the choice if the user wants to remember
      Services.perms.addFromPrincipal(request.principal, perm.type, action);
    } else {
      // Otherwise allow the permission for the current session
      Services.perms.addFromPrincipal(request.principal, perm.type, action,
                                      Ci.nsIPermissionManager.EXPIRE_SESSION);
    }

    // Trigger the selected choice
    if (choice == 0) {
      request.allow();
    }
    else {
      request.cancel();
    }
  }
};

this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentPermission]);
