<!DOCTYPE html>
<html ng-app="app">

  <head>
    <script data-require="angular.js@*" data-semver="1.3.0-beta.5" src="https://code.angularjs.org/1.3.0-beta.5/angular.js"></script>
    <script data-require="lodash.js@*" data-semver="2.4.1" src="http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body>
    <div data-first=""></div>
    <div data-second=""></div>
  </body>

</html>
(function(angular) {

  function MediatorService($log) {
    var Mediator = {};

    var channels = {};
    var subscriberId = 0;


    Mediator.publish = function(channel, publisher, data) {
      if (!hasSubscriber(channel)) {
        return;
      }

      var subscribers = channels[channel];

      _.map(subscribers, function(subscriber) {
        try {
          subscriber.callback(data);
        } catch (e) {
          $log.error(e, publisher, subscriber.name)
        }
      });
    };


    Mediator.subscribe = function(channel, subscriber, callback) {
      if (!hasSubscriber(channel)) {
        channels[channel] = [];
      }

      channels[channel].push({
        "callback": callback,
        "name": subscriber,
        "subscriberId": ++subscriberId
      });

      return function() {
        unsubscribe(subscriberId);
      };
    };


    function hasSubscriber(channel) {
      return _.has(channels, channel);
    }


    function unsubscribe(subscriberId) {
      channels = _.map(channels, function(channel) {
        return _.filter(channel, function(subscriber) {
          return subscriber.subscriberId !== subscriberId;
        });
      });
    }

    return Mediator;
  }

  angular
    .module("app", [])
    .factory("Mediator", ["$log", "$timeout", MediatorService])
    .directive("first", function() {

      return {
        controller: function() {
          this.name = "First";
        },
        controllerAs: "first",
        template: "<p ng-bind='first.name'></p><div data-third></div>"
      };

    })
    .directive("second", function(Mediator) {

      return {
        controller: function() {
          this.name = "Second";
          this.tellThird = Mediator.publish.bind(this, "NewName", "second", this.name);
        },
        controllerAs: "second",
        template: "<a ng-bind='second.name' ng-click='second.tellThird()'></a>"
      };

    })
    .directive("third", function(Mediator) {

      return {
        controller: function() {
          this.name = "Third";
          var unsubscribe = Mediator.subscribe("NewName", "third", setName.bind(this));
          function setName(name) {
            this.name = name;
            unsubscribe();
          }
        },

        controllerAs: "third",
        template: "<p ng-bind='third.name'></p>"
      };

    })


})(angular);
/* Styles go here */