text: /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
  /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
  /* 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/. */
  
  // This JS shim contains the callbacks to fire DOMRequest events for
  // navigator.pay API within the payment processor's scope.
  
  "use strict";
  
  dump("======================= payment.js ======================= \n");
  
  let { classes: Cc, interfaces: Ci, utils: Cu }  = Components;
  Cu.import("resource://gre/modules/XPCOMUtils.jsm");
  
  XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                     "@mozilla.org/childprocessmessagemanager;1",
                                     "nsIMessageSender");
  
  XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
                                     "@mozilla.org/uuid-generator;1",
                                     "nsIUUIDGenerator");
  
  #ifdef MOZ_B2G_RIL
  XPCOMUtils.defineLazyServiceGetter(this, "mobileConnection",
                                     "@mozilla.org/ril/content-helper;1",
                                     "nsIMobileConnectionProvider");
  #endif
  
  
  const kClosePaymentFlowEvent = "close-payment-flow-dialog";
  
  let _requestId;
  
  let PaymentProvider = {
  
  #ifdef MOZ_B2G_RIL
    __exposedProps__: {
      paymentSuccess: 'r',
      paymentFailed: 'r',
      iccIds: 'r',
      mcc: 'r',
      mnc: 'r'
    },
  #else
    __exposedProps__: {
      paymentSuccess: 'r',
      paymentFailed: 'r'
    },
  #endif
  
    _closePaymentFlowDialog: function _closePaymentFlowDialog(aCallback) {
      // After receiving the payment provider confirmation about the
      // successful or failed payment flow, we notify the UI to close the
      // payment flow dialog and return to the caller application.
      let id = kClosePaymentFlowEvent + "-" + uuidgen.generateUUID().toString();
  
      let browser = Services.wm.getMostRecentWindow("navigator:browser");
      let content = browser.getContentWindow();
      if (!content) {
        return;
      }
  
      let detail = {
        type: kClosePaymentFlowEvent,
        id: id,
        requestId: _requestId
      };
  
      // In order to avoid race conditions, we wait for the UI to notify that
      // it has successfully closed the payment flow and has recovered the
      // caller app, before notifying the parent process to fire the success
      // or error event over the DOMRequest.
      content.addEventListener("mozContentEvent",
                               function closePaymentFlowReturn(evt) {
        if (evt.detail.id == id && aCallback) {
          aCallback();
        }
  
        content.removeEventListener("mozContentEvent",
                                    closePaymentFlowReturn);
  
        let glue = Cc["@mozilla.org/payment/ui-glue;1"]
                     .createInstance(Ci.nsIPaymentUIGlue);
        glue.cleanup();
      });
  
      browser.shell.sendChromeEvent(detail);
    },
  
    paymentSuccess: function paymentSuccess(aResult) {
      PaymentProvider._closePaymentFlowDialog(function notifySuccess() {
        if (!_requestId) {
          return;
        }
        cpmm.sendAsyncMessage("Payment:Success", { result: aResult,
                                                   requestId: _requestId });
      });
    },
  
    paymentFailed: function paymentFailed(aErrorMsg) {
      PaymentProvider._closePaymentFlowDialog(function notifyError() {
        if (!_requestId) {
          return;
        }
        cpmm.sendAsyncMessage("Payment:Failed", { errorMsg: aErrorMsg,
                                                  requestId: _requestId });
      });
    },
  
  #ifdef MOZ_B2G_RIL
    // Until bug 814629 is done, we only have support for a single SIM, so we
    // can only provide information for a single ICC. However, we return arrays
    // for any ICC related getter so the payment provider facing API won't need
    // to change once we support multiple SIMs.
    get iccIds() {
      return [mobileConnection.iccInfo.iccid];
    },
  
    get mcc() {
      return [mobileConnection.iccInfo.mcc];
    },
  
    get mnc() {
      return [mobileConnection.iccInfo.mnc];
    }
  #endif
  };
  
  // We save the identifier of the DOM request, so we can dispatch the results
  // of the payment flow to the appropriate content process.
  addMessageListener("Payment:LoadShim", function receiveMessage(aMessage) {
    _requestId = aMessage.json.requestId;
  });
  
  addEventListener("DOMWindowCreated", function(e) {
    content.wrappedJSObject.mozPaymentProvider = PaymentProvider;
  });
  