Source: js/activity_window_manager.js

/* global Service */
'use strict';
(function(exports) {
  /**
   * ActivityWindowManager manages the activity window instances.
   *
   * Currently it's only responsible to kill an existing
   * activity window if the next creating instance has the same
   * manifestURL + pageURL.
   *
   * @class ActivityWindowManager
   */
  function ActivityWindowManager() {
  }
  ActivityWindowManager.prototype = {
    /**
     * The list of all current running activity window instances.
     * @access private
     * @type {Array}
     * @memberof ActivityWindowManager.prototype
     */
    _activities: [],

    /**
     * Register all event handlers.
     * @memberof ActivityWindowManager.prototype
     */
    start: function acwf_start() {
      if (this._started) {
        return;
      }
      this._started = true;

      this.activityPool = new Map();
      window.addEventListener('activityopened', this);
      window.addEventListener('popupopened', this);
      window.addEventListener('appopened', this);
      window.addEventListener('activityrequesting', this);
      window.addEventListener('activitycreated', this);
      window.addEventListener('activityterminated', this);
    },

    /**
     * Unregister all event handlers.
     * @memberof ActivityWindowManager.prototype
     */
    stop: function acwf_stop() {
      if (!this._started) {
        return;
      }
      this._started = false;

      this.activityPool = null;
      window.removeEventListener('activityopened', this);
      window.removeEventListener('popupopened', this);
      window.removeEventListener('appopened', this);
      window.removeEventListener('activityrequesting', this);
      window.removeEventListener('activitycreated', this);
      window.removeEventListener('activityterminated', this);
    },

    /**
     * Put all window ID which is involved in an activity here.
     * XXX: This is a workaround of bug 931339.
     * @type {Map}
     */
    activityPool: null,

    /**
     * Activity Config
     * @typedef {Object} ActivityConfig
     * @property {String} manifestURL The manifestURL of the activity
     * @property {String} url The URL of the activity handling page
     * @property {Boolean} isActivity
     * @property {Boolean} inline The disposition of the activty is inline
     *                            or not
     */

    handleEvent: function acwf_handleEvent(evt) {
      switch (evt.type) {
        // XXX: Workaround of bug 931339.
        // We are maintaining only one chain of activities here
        // in this.activityPool.
        // If the next coming activity request does not belong
        // to the previous pool,
        // kill all the background inline activities.
        case 'popupopened':
        case 'activityopened':
        case 'appopened':
          var app = evt.detail;
          var parent = app.callerWindow ||
                        app.bottomWindow ||
                        app.previousWindow;
          if (parent && this.activityPool.has(parent.instanceID)) {
            // We don't really care about the instance context,
            // so we set the value to a boolean.
            this.activityPool.set(app.instanceID, true);
          }
          break;
        case 'popupterminated':
        case 'appterminated':
          this.activityPool.delete(app.instanceID);
          break;
        case 'activityrequesting':
          // The request may come from the top most window
          // or the system app, but we don't care here.
          var caller = Service.query('getTopMostWindow');
          if (!this.activityPool.size) {
            this.activityPool.set(caller.instanceID, true);
          } else {
            if (!this.activityPool.has(caller.instanceID)) {
              // A new request from a new chain,
              // kill all the background.
              this._activities.forEach(function iterator(activity, index) {
                if (!activity.getBottomMostWindow().isActive() ||
                    !activity.isActive()) {
                  activity.kill();
                }
              }, this);
              this.activityPool.clear();
              this.activityPool.set(caller.instanceID, true);
            }
          }
          break;

        case 'activityterminated':
          this._activities.some(function iterator(activity, index) {
            if (activity.instanceID === evt.detail.instanceID) {
              this._activities.splice(index, 1);
              return true;
            }
          }, this);
          this.activityPool.delete(evt.detail.instanceID);
          break;

        case 'activitycreated':
          this._activities.push(evt.detail);
          break;
      }
    }
  };

  exports.ActivityWindowManager = ActivityWindowManager;
}(window));