import Switchboard from '../lib/switchboard';

describe.only('Switchboard', function() {
  let switchboard;

  beforeEach(function() {
    switchboard = new Switchboard();
  });

  describe('events', function() {
    let sub;

    afterEach(function() {
      sub && sub.dispose();
    });

    it('synchronously broadcasts events', function() {
      let observed = 0;
      sub = switchboard.onDid('test', () => observed++);

      assert.equal(observed, 0);
      switchboard.did('test');
      assert.equal(observed, 1);
    });
  });

  describe('promises', function() {
    it('creates and resolves a Promise for an event', async function() {
      const promise = switchboard.getPromise('testing');

      const payload = {};
      switchboard.did('testing', payload);

      const result = await promise;
      assert.strictEqual(result, payload);
    });

    it('supports multiple consumers of the same Promise', async function() {
      const promise0 = switchboard.getPromise('testing');
      const promise1 = switchboard.getPromise('testing');
      assert.strictEqual(promise0, promise1);

      const payload = {};
      switchboard.did('testing', payload);

      assert.strictEqual(await promise0, payload);
      assert.strictEqual(await promise1, payload);
    });

    it('creates new Promises for repeated events', async function() {
      const promise0 = switchboard.getPromise('testing');

      switchboard.did('testing', 0);
      assert.equal(await promise0, 0);

      const promise1 = switchboard.getPromise('testing');

      switchboard.did('testing', 1);
      assert.equal(await promise1, 1);
    });

    it('"resolves" an event that has no Promise', function() {
      switchboard.did('anybody-there', {});
    });
  });

  // Ensure that all of the `didXyz`, `onDidXyz`, and `getXyzPromise` method triplets are aligned correctly.
  describe('function triplets', function() {
    const baseNames = Object.getOwnPropertyNames(Switchboard.prototype)
      .map(methodName => /^did(.+)$/.exec(methodName))
      .filter(match => match !== null)
      .map(match => match[1]);
    let functionPairs;

    beforeEach(function() {
      functionPairs = baseNames.map(baseName => {
        return {
          baseName,
          subscriber: switchboard[`onDid${baseName}`].bind(switchboard),
          getter: switchboard[`get${baseName}Promise`].bind(switchboard),
          resolver: switchboard[`did${baseName}`].bind(switchboard),
        };
      });
    });

    baseNames.forEach(baseName => {
      it(`resolves the correct Promise for ${baseName}`, async function() {
        const allPromises = [];
        const positiveResults = [];
        const negativeResults = [];

        let positiveResolver = null;
        const negativeResolvers = [];

        for (let i = 0; i < functionPairs.length; i++) {
          const functionPair = functionPairs[i];

          if (functionPair.baseName === baseName) {
            const positivePromise = functionPair.getter().then(payload => {
              positiveResults.push(payload);
            });
            allPromises.push(positivePromise);

            positiveResolver = functionPair.resolver;
          } else {
            const negativePromise = functionPair.getter().then(payload => {
              negativeResults.push(payload);
            });
            allPromises.push(negativePromise);

            negativeResolvers.push(functionPair.resolver);
          }
        }

        // Resolve positive resolvers with "yes" and negative resolvers with "no"
        positiveResolver('yes');
        negativeResolvers.forEach(resolver => resolver('no'));

        await Promise.all(allPromises);

        assert.lengthOf(positiveResults, 1);
        assert.isTrue(positiveResults.every(result => result === 'yes'));

        assert.lengthOf(negativeResults, baseNames.length - 1);
        assert.isTrue(negativeResults.every(result => result === 'no'));
      });
    });
  });
});

@@ -1,8 +1,81 @@
+import %7BCompositeDisposable%7D from 'atom'; // FIXME import from event-kit%0A
 import S
@@ -2191,20 +2191,22 @@
 function
-Pair
+Triple
 s;%0A%0A    
@@ -2243,20 +2243,22 @@
 function
-Pair
+Triple
 s = base
@@ -2849,32 +2849,90 @@
 esolvers = %5B%5D;%0A%0A
+        const subscriptions = new CompositeDisposable();%0A%0A
         for (let
@@ -2951,20 +2951,22 @@
 function
-Pair
+Triple
 s.length
@@ -2998,20 +2998,22 @@
 function
-Pair
+Triple
  = funct
@@ -3015,20 +3015,22 @@
 function
-Pair
+Triple
 s%5Bi%5D;%0A%0A 
@@ -3050,20 +3050,22 @@
 function
-Pair
+Triple
 .baseNam
@@ -3118,36 +3118,38 @@
 omise = function
-Pair
+Triple
 .getter().then(p
@@ -3300,36 +3300,38 @@
 olver = function
-Pair
+Triple
 .resolver;%0A     
@@ -3324,16 +3324,180 @@
 esolver;
+%0A%0A            const positiveSubscription = functionTriple.subscriber(payload =%3E positiveResults.push(payload));%0A            subscriptions.add(positiveSubscription);
 %0A       
@@ -3552,20 +3552,22 @@
 function
-Pair
+Triple
 .getter(
@@ -3742,21 +3742,187 @@
 tion
-Pair.resolver
+Triple.resolver);%0A%0A            const negativeSubscription = functionTriple.subscriber(payload =%3E negativeResults.push(payload));%0A            subscriptions.add(negativeSubscription
 );%0A 
@@ -4159,24 +4159,58 @@
 Promises);%0A%0A
+        subscriptions.dispose();%0A%0A
         asse
@@ -4238,17 +4238,17 @@
 esults, 
-1
+2
 );%0A     
@@ -4358,16 +4358,17 @@
 esults, 
+(
 baseName
@@ -4380,16 +4380,21 @@
 gth - 1)
+ * 2)
 ;%0A      

Test subscription method triples too