var _ = require('underscore');
var Mountpoint = require('mountpoint');

function PluginRtpbroadcast(server) {
  this.server = server;
  this.mountpoints = [];
  this.infoSession = null;
  this.mountpointsSession = null;
  this.watchSession = null;
}

PluginRtpbroadcast.prototype.getUpstreamPlugin = function() {
  return _.find(this.server.upstream.plugins, function(plugin) {
    return plugin instanceof this.constructor;
  }.bind(this));
};

PluginRtpbroadcast.prototype.onRegister = function() {
  return this.listenForMountpointInfo();
};

PluginRtpbroadcast.prototype.onUnregister = function() {
  return Promise.all([
    this.closeInfoSession(),
    this.closeMountpointsSession(),
    this.closeWatchSession()
  ]);
};

PluginRtpbroadcast.prototype.onSetUpstream = function() {
  if (null === this.upstream) {
    this.upstream.off('mountpoint-change');
    return Promise.all([
      this.closeMountpointsSession(),
      this.closeWatchSession()
    ]);
  } else {
    this.upstream.on('mountpoint-change', this.replicateUpstreamMountpoints.bind(this));
    return Promise.all([
      this.openMountpointsSession(),
      this.openWatchSession()
    ]).then(function() {
      this.replicateUpstreamMountpoints();
    }.bind(this))
  }
};


PluginRtpbroadcast.prototype.listenForMountpointInfo = function() {
  var self = this;
  return this.server.getConnection()
    .then(function(connection) {
      return self.infoSession = connection.createSession();
    })
    .then(function(session) {
      return session.attachPlugin('rtpbroadcast');
    })
    .then(function(plugin) {
      plugin.on('message', function(message) {
        if (message['body']['request'] === 'mountpoint-info') {
          self.updateMountpoints(message['body']['data']);
        }
      });
      // add transaction
      return plugin.sendTransaction('upgrade connection');
    });
};

PluginRtpbroadcast.prototype.closeInfoSession = function() {
  return this.infoSession.destroy().finally(function() {
    this.infoSession = null;
  }.bind(this));
};

PluginRtpbroadcast.prototype.replicateUpstreamMountpoints = function() {
  var upstreamMountpointsIds = _.pluck(this.getUpstreamPlugin().mountpoints, 'id');
  var mountpointsIds = _.pluck(this.mountpoints, 'id');

  _.difference(upstreamMountpointsIds, mountpointsIds).forEach(function(mountpointId) {
    this.removeMountpoint(mountpointId);
  }.bind(this));

  this.differentMountpoints(mountpointsIds, upstreamMountpointsIds).forEach(function(mountpointId) {
    this.createMountpoint(mountpointId);
  }.bind(this));
};

PluginRtpbroadcast.prototype.createMountpoint = function(mountpointId) {
  return this.getMountpointsSession()
    .then(function(session) {
      return session.attachPlugin('rtpbroadcast');
    })
    .then(function(plugin) {
      // probably should check transaction response
      return plugin.send('create-mountpoint', mountpointId);
    });
};

PluginRtpbroadcast.prototype.removeMountpoint = function(mountpoint) {
  this.getMountpointsSession().detachPlugin(mountpoint.pluginId);
};


PluginRtpbroadcast.prototype.openMountpointsSession = function() {
  if (this.mountpointsSession) {
    throw new Error('Mountpoints session already present');
  }
  return this.server.getConnection()
    .then(function(connection) {
      return this.mountpointsSession = connection.createSession();
    }.bind(this));
};

PluginRtpbroadcast.prototype.getMountpointsSession = function() {
  return this.mountpointsSession;
};

PluginRtpbroadcast.prototype.closeMountpointsSession = function() {
  return this.mountpointsSession.destroy().finally(function() {
    this.mountpointsSession = null;
  }.bind(this));
};


PluginRtpbroadcast.prototype.openWatchSession = function() {
  if (this.watchSession) {
    throw new Error('Watch session already present');
  }
  return this.server.upstream.getConnection()
    .then(function(connection) {
      return this.watchSession = connection.createSession();
    }.bind(this));
};

PluginRtpbroadcast.prototype.getWatchSession = function() {
  return this.watchSession;
};

PluginRtpbroadcast.prototype.closeWatchSession = function() {
  return this.watchSession.destroy().finally(function() {
    this.watchSession = null;
  }.bind(this));
};


PluginRtpbroadcast.prototype.updateMountpoints = function(mountpointsData) {
  var realMountpoints = mountpointsData.map(function(mountpointInfo) {
    return new Mountpoint(this, mountpointInfo['id'], mountpointInfo['pluginId']);
  }.bind(this));

  this.differentMountpoints(realMountpoints, this.mountpoints).forEach(function(mountpoint) {
    this.watchUpstream(mountpoint);
  }.bind(this));

  this.differentMountpoints(this.mountpoints, realMountpoints).forEach(function(mountpoint) {
    this.stopWatchUpstream(mountpoint);
  }.bind(this));

  this.mountpoints = realMountpoints;
  this.emit('mountpoint-change');
};

PluginRtpbroadcast.prototype.watchUpstream = function() {
  return this.getWatchSession()
    .then(function(session) {
      return session.attachPlugin('rtpbroadcast');
    })
    .then(function(plugin) {
      return plugin.sendTransaction('watch-udp');
    });
};

PluginRtpbroadcast.prototype.stopWatchUpstream = function(mountpoint) {
  return this.getWatchSession().detachPlugin(mountpoint.pluginId);
};

PluginRtpbroadcast.prototype.differentMountpoints = function(mountpoints1, mountpoints2) {
  return _.reject(this.mountpoints, function(mountpoint) {
    return _.find(realMountpoints, function(realMountpoint) {
      return realMountpoint.id === mountpoint.id;
    });
  });
};

module.exports = PluginRtpbroadcast;

@@ -182,35 +182,30 @@
 ull;%0A  this.
-mountpoints
+create
 Session = nu
@@ -653,35 +653,30 @@
   this.close
-Mountpoints
+Create
 Session(),%0A 
@@ -884,35 +884,30 @@
   this.close
-Mountpoints
+Create
 Session(),%0A 
@@ -1080,35 +1080,30 @@
    this.open
-Mountpoints
+Create
 Session(),%0A 
@@ -2631,35 +2631,30 @@
 urn this.get
-Mountpoints
+Create
 Session()%0A  
@@ -2970,35 +2970,30 @@
 %7B%0A  this.get
-Mountpoints
+Create
 Session().de
@@ -3063,27 +3063,22 @@
 ype.open
-Mountpoints
+Create
 Session 
@@ -3099,35 +3099,30 @@
 %0A  if (this.
-mountpoints
+create
 Session) %7B%0A 
@@ -3268,35 +3268,30 @@
 return this.
-mountpoints
+create
 Session = co
@@ -3371,27 +3371,22 @@
 type.get
-Mountpoints
+Create
 Session 
@@ -3410,35 +3410,30 @@
 return this.
-mountpoints
+create
 Session;%0A%7D;%0A
@@ -3467,27 +3467,22 @@
 pe.close
-Mountpoints
+Create
 Session 
@@ -3506,35 +3506,30 @@
 return this.
-mountpoints
+create
 Session.dest
@@ -3564,27 +3564,22 @@
    this.
-mountpoints
+create
 Session 

Rename mountpointsSession to createSession