System.register(['./utils.js'], function (_export, _context) {
  "use strict";

  var pushIfMissing, removeIfExisting, identity;
  return {
    setters: [function (_utilsJs) {
      pushIfMissing = _utilsJs.pushIfMissing;
      removeIfExisting = _utilsJs.removeIfExisting;
      identity = _utilsJs.identity;
    }],
    execute: function () {
      _recorder_._src_client_reactive_active_group_view_js = _recorder_._src_client_reactive_active_group_view_js || {};
      _recorder_._src_client_reactive_active_group_view_js.identity = identity;
      _recorder_._src_client_reactive_active_group_view_js.removeIfExisting = removeIfExisting;
      _recorder_._src_client_reactive_active_group_view_js.pushIfMissing = pushIfMissing;


      /**
       *
       * @class View
       * @classdesc This is the class representing a view.
       */
      class View {
        constructor() {
          this.items = [];
          this.downstream = [];
          this.enterCallbacks = [];
          this.exitCallbacks = [];

          this.layersByItem = new Map();
        }
        get isActiveGroup() {
          return true;
        }

        safeAdd(item) {
          var wasNewItem = _recorder_._src_client_reactive_active_group_view_js.pushIfMissing(this.items, item);
          if (wasNewItem) {
            console.log('added to selection', item);
            this.enterCallbacks.forEach(function (enterCallback) {
              enterCallback(item);
            });
            this.downstream.forEach(function (ea) {
              ea.newItemFromUpstream(item);
            });
          }
        }

        safeRemove(item) {
          var gotRemoved = _recorder_._src_client_reactive_active_group_view_js.removeIfExisting(this.items, item);
          if (gotRemoved) {
            console.log('removed from selection', item);
            this.exitCallbacks.forEach(function (exitCallback) {
              exitCallback(item);
            });
            this.downstream.forEach(function (ea) {
              ea.destroyItemFromUpstream(item);
            });
          }
        }

        // Get persistent version of the current state of the Selection.
        /**
         * Returns an Array of the objects that are currently in the set. This Array does not update automatically.
         * @function View#now
         * @return {Array}
         */
        now() {
          var arr = [];
          this.items.forEach(function (item) {
            arr.push(item);
          });

          return arr;
        }

        /**
         * Returns the current number of objects the set contains.
         * @function View#size
         * @return {Number}
         */
        size() {
          return this.now().length;
        }

        /**
         * Takes a callback that consumes a single parameter. This callback is called whenever an object is added to the reactive set with that very object.
         * @function View#enter
         * @param {View~enterCallback} callback - this is executed everytime an object is added to the set
         * @return {View} The callee of this method.
         */
        enter(callback) {
          this.enterCallbacks.push(callback);
          this.now().forEach(function (item) {
            callback(item);
          });

          return this;
        }

        /**
         * Similar to \texttt{enter}, but the callback is called everytime an object is removed from the set.
         * @function View#exit
         * @param {View~exitCallback} callback
         * @return {View} The callee of this method.
         */
        exit(callback) {
          this.exitCallbacks.push(callback);

          return this;
        }

        /**
         * Define partial behavior attached to each object while it is contained in the set.
         * @function View#layer
         * @param {Object} partialBehavior - the mixin to be applied.
         * @returns {View} The callee of this method.
         */
        // TODO: is this currently limited to 1 layer per item-view combination?
        layer(partialBehavior) {
          var layersByItem = this.layersByItem;

          this.enter(function (item) {
            // lazy initialization
            if (!layersByItem.has(item)) {
              layersByItem.set(item, new Layer().refineObject(item, partialBehavior));
            }

            var layerForItem = layersByItem.get(item);
            if (!layerForItem.isGlobal()) {
              layerForItem.beGlobal();
            }
          });

          this.exit(function (item) {
            var layerForItem = layersByItem.get(item);
            if (layerForItem && layerForItem.isGlobal()) {
              layerForItem.beNotGlobal();
            }
          });

          return this;
        }
      }

      _export('default', View);

      _recorder_._src_client_reactive_active_group_view_js.View = View;
    }
  };
});