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

"use strict";

/**
 * A ReflowObserver that listens for reflow events from the page.
 * Implements nsIReflowObserver.
 */
class ConsoleReflowListener {
  /**
   * @param {object} window
   *        The window for which we need to track reflow.
   * @param {object} listener
   *        The listener owner which needs to implement `onReflowActivity(reflowInfo)`
   */
  constructor(window, listener) {
    this.docshell = window.docShell;
    this.listener = listener;
    this.docshell.addWeakReflowObserver(this);
  }

  QueryInterface = ChromeUtils.generateQI([
    "nsIReflowObserver",
    "nsISupportsWeakReference",
  ]);
  docshell = null;
  listener = null;

  /**
   * Forward reflow event to listener.
   *
   * @param {DOMHighResTimeStamp} start
   * @param {DOMHighResTimeStamp} end
   * @param {boolean} interruptible
   */
  sendReflow(start, end, interruptible) {
    const frame = Components.stack.caller.caller;

    let filename = frame ? frame.filename : null;

    if (filename) {
      // Because filename could be of the form "xxx.js -> xxx.js -> xxx.js",
      // we only take the last part.
      filename = filename.split(" ").pop();
    }

    this.listener.onReflowActivity({
      interruptible,
      start,
      end,
      sourceURL: filename,
      sourceLine: frame ? frame.lineNumber : null,
      functionName: frame ? frame.name : null,
    });
  }

  /**
   * On uninterruptible reflow
   *
   * @param {DOMHighResTimeStamp} start
   * @param {DOMHighResTimeStamp} end
   */
  reflow(start, end) {
    this.sendReflow(start, end, false);
  }

  /**
   * On interruptible reflow
   *
   * @param {DOMHighResTimeStamp} start
   * @param {DOMHighResTimeStamp} end
   */
  reflowInterruptible(start, end) {
    this.sendReflow(start, end, true);
  }

  /**
   * Unregister listener.
   */
  destroy() {
    this.docshell.removeWeakReflowObserver(this);
    this.listener = this.docshell = null;
  }
}

exports.ConsoleReflowListener = ConsoleReflowListener;
