/* 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 Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;

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

const MAX_CACHE_SIZE      = 250;
const PREF_UPDATE         = "general.useragent.updates.";
const PREF_OVERRIDE       = "general.useragent.override.";
const XPCOM_SHUTDOWN      = "xpcom-shutdown";
const HTTP_PROTO_HANDLER = Cc["@mozilla.org/network/protocol;1?name=http"]
                             .getService(Ci.nsIHttpProtocolHandler);

XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
  "@mozilla.org/childprocessmessagemanager;1",
  "nsISyncMessageSender");

function SiteSpecificUserAgent() {
  this.inParent = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
    .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;

  if (this.inParent) {
    Cu.import("resource://gre/modules/UserAgentOverrides.jsm");
  } else {
    Cu.import("resource://gre/modules/Services.jsm");
    Services.prefs.addObserver(PREF_OVERRIDE, this, false);
    Services.prefs.addObserver(PREF_UPDATE, this, false);
    Services.obs.addObserver(this, XPCOM_SHUTDOWN, false);
    this.userAgentCache = new Map;
  }
}

SiteSpecificUserAgent.prototype = {
  getUserAgentForURIAndWindow: function ssua_getUserAgentForURIAndWindow(aURI, aWindow) {
    if (this.inParent) {
      return UserAgentOverrides.getOverrideForURI(aURI) || HTTP_PROTO_HANDLER.userAgent;
    }

    let host = aURI.asciiHost;
    let cachedResult = this.userAgentCache.get(host);
    if (cachedResult) {
      return cachedResult;
    }

    let data = { uri: aURI };
    let result = cpmm.sendRpcMessage("Useragent:GetOverride", data)[0] || HTTP_PROTO_HANDLER.userAgent;

    if (this.userAgentCache.size >= MAX_CACHE_SIZE) {
      this.userAgentCache.clear();
    }

    this.userAgentCache.set(host, result);
    return result;
  },

  invalidateCache: function() {
    this.userAgentCache.clear();
  },

  clean: function() {
    this.userAgentCache.clear();
    if (!this.inParent) {
      Services.obs.removeObserver(this, XPCOM_SHUTDOWN);
      Services.prefs.removeObserver(PREF_OVERRIDE, this);
      Services.prefs.removeObserver(PREF_UPDATE, this);
    }
  },

  observe: function(subject, topic, data) {
    switch (topic) {
      case "nsPref:changed":
        this.invalidateCache();
        break;
      case XPCOM_SHUTDOWN:
        this.clean();
        break;
    }
  },

  classID: Components.ID("{506c680f-3d1c-4954-b351-2c80afbc37d3}"),
  QueryInterface: XPCOMUtils.generateQI([Ci.nsISiteSpecificUserAgent])
};

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