/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'foam.core',
  name: 'Stub',
  extends: 'Property',

  properties: [
    'of',
    {
      name: 'methods',
      expression: function(of) {
        var cls = foam.lookup(of);

        if ( cls ) {
          return cls.getAxiomsByClass(foam.core.Method)
            .filter(function (m) { return cls.hasOwnAxiom(m.name); })
            .map(function(m) { return m.name; })
        }
      }
    }
  ],

  methods: [
    function installInClass(cls) {
      var model = foam.lookup(this.of);
      var propName = this.name;

      var replyPolicyName = this.name + 'ReplyPolicy';

      cls.installAxiom(foam.core.Property.create({
        name: replyPolicyName
      }));

      var methods = this.methods
          .map(function(name) { return model.getAxiomByName(name); })
          .map(function(m) {
            var returns = m.returns;
            if ( m.returns && m.returns !== 'Promise' ) {
              var name = m.returns.split('.');
              name[name.length - 1] = 'Promised' + name[name.length - 1];
              returns = name.join('.');
            }

            var m2 = foam.core.Method.create({
              name: m.name,
              returns: returns,
              code: function() {
                if ( returns ) {
                  var returnBox = this.RPCReturnBox.create();
                  var replyBox = this.ReplyBox.create({
                    delegate: returnBox
                  });

                  var exportBox = this.registry.register2(
                    replyBox.id,
                    this[replyPolicyName],
                    replyBox
                  );

                  var ret = returnBox.promise;

                  // TODO: Move this into RPCReturnBox ?
                  if ( returns !== 'Promise' ) {
                    ret = foam.lookup(returns).create({ delegate: ret });
                  }
                }

                var msg = this.RPCMessage.create({
                  name: m.name,
                  args: Array.from(arguments)
                });
                if ( exportBox ) msg.replyBox = exportBox;

                this[propName].send(msg);

                return ret;
              }
            });
            return m2;
          });

      for ( var i = 0 ; i < methods.length ; i++ ) {
        cls.installAxiom(methods[i]);
      }

      [
        'foam.box.SubscribeMessage',
        'foam.box.OneShotBox',
        'foam.box.RPCReturnBox',
        'foam.box.ReplyBox',
        'foam.box.RPCMessage',
      ].map(function(s) {
        var path = s.split('.');
        return foam.core.Requires.create({
          path: s,
          name: path[path.length - 1]
        });
      }).forEach(function(a) {
        cls.installAxiom(a);
      });

      [
        'registry'
      ].map(function(s) {
        cls.installAxiom(foam.core.Import.create({
          key: s,
          name: s
        }));
      });

      cls.installAxiom(foam.core.Method.create({
        name: 'sub',
        code: function() {
          this.SUPER.apply(this, arguments);

          if ( arguments.length < 2 ) {
            throw 'Currently network subscriptions must include at least one topic.';
          }

          var replyBox = this.registry.register2(
            foam.next$UID(),
            this[replyPolicyName],
            foam.box.EventDispatchBox.create({ target: this }));

          this[propName].send(this.SubscribeMessage.create({
            replyBox: replyBox,
            topic: Array.from(arguments).slice(0, -1)
          }));
        }
      }));
    }
  ]
});

@@ -732,16 +732,98 @@
 ,%0A    %7B%0A
+      class: 'Boolean',%0A      name: 'eventProxy',%0A      value: false%0A    %7D,%0A    %7B%0A
       na
@@ -3633,24 +3633,57 @@
 %0A      %7D);%0A%0A
+      if ( this.eventProxy ) %7B%0A  
       cls.in
@@ -3723,24 +3723,26 @@
 e(%7B%0A        
+  
 name: 'sub',
@@ -3742,16 +3742,18 @@
  'sub',%0A
+  
         
@@ -3777,24 +3777,26 @@
 %7B%0A          
+  
 this.SUPER.a
@@ -3825,24 +3825,26 @@
 %0A%0A          
+  
 if ( argumen
@@ -3857,24 +3857,26 @@
 gth %3C 2 ) %7B%0A
+  
             
@@ -3951,32 +3951,34 @@
 ic.';%0A          
+  
 %7D%0A%0A          var
@@ -3966,32 +3966,34 @@
    %7D%0A%0A          
+ 
+ 
 var replyBox = t
@@ -4024,24 +4024,26 @@
             
+  
 foam.next$UI
@@ -4047,16 +4047,18 @@
 $UID(),%0A
+  
         
@@ -4092,24 +4092,26 @@
             
+  
 foam.box.Eve
@@ -4148,24 +4148,26 @@
  this %7D));%0A%0A
+  
           th
@@ -4219,32 +4219,34 @@
 e(%7B%0A            
+  
 replyBox: replyB
@@ -4249,16 +4249,18 @@
 plyBox,%0A
+  
         
@@ -4311,29 +4311,33 @@
 )%0A          
+  
 %7D));%0A
+  
         %7D%0A  
@@ -4336,29 +4336,39 @@
     %7D%0A      
+  
 %7D));%0A
+      %7D%0A
     %7D%0A  %5D%0A%7D)

Make event proxy an optional switch.