/*jslint node: true, indent: 2, unused: true, maxlen: 80, camelcase: true */
/*
 * stompit.ChannelPool
 * Copyright (c) 2014 Graham Daws <graham.daws@gmail.com>
 * MIT licensed
 */
 
var ConnectFailover = require('./connect_failover');
var Channel         = require('./channel');
var util            = require('./util');

function ChannelPool(connectFailover, options) {
  
  if (!(this instanceof ChannelPool)) {
    var object = Object.create(ChannelPool.prototype);
    ChannelPool.apply(object, arguments);
    return object;
  }
  
  options = util.extend({
    
    minChannels: 0,
    
    minFreeChannels: 0,
    
    maxChannels: Infinity,
    
    freeExcessTimeout: null
    
  }, options || {});
  
  this._connectFailover = connectFailover;
  
  this._minChannels = options.minChannels;
  this._minFreeChannels = Math.min(options.minFreeChannels, this._minChannels);
  this._maxChannels = options.maxChannels;
  
  this._numChannels = 0;
  
  this._freeChannels = [];
  this._freeExcessTimeouts = [];
  
  for (var i = 0; i < this._minChannels; i++) {
    this._allocateFreeChannel();
  }
}

ChannelPool.prototype._createChannel = function() {
  
  return new Channel(this._connectFailover, {
    alwaysConnected: true
  });
};

ChannelPool.prototype._allocateFreeChannel = function() {
  
  if (this._numChannels >= this._maxChannels) {
    return;
  }
  
  var channel = this._createChannel();
  
  this._numChannels += 1;
  
  this._freeChannels.push(channel);
  
  return channel;
};

ChannelPool.prototype._addExcessTimeout = function() {
  
  if (this._freeChannels.length <= this._minChannels) {
    return;
  }
  
  var self = this;
  
  var close = function() {
    self._freeChannels.shift().close();
    self._numChannels -= 1;
  };
  
  if (this._freeExcessTimeout === null) {
    close();
    return;
  }
  
  this._freeExcessTimeouts.push(setTimeout(function() {
    
    self._freeExcessTimeouts.shift();
    
    if (self._freeChannels.length > self._minChannels) {
      close();
    }
    
  }, this._freeExcessTimeout));
};

ChannelPool.prototype._allocateBusyChannel = function() {
  
  if (this._freeChannels.length === 0 && !this._allocateFreeChannel()) {
    return;
  }
  
  var channel = this._freeChannels.shift();
  
  if (this._freeExcessTimeouts.length > 0) {
    clearTimeout(this._freeExcessTimeouts.shift());  
  }
  
  if (this._freeChannels.length < this._minFreeChannels) {
    this._allocateFreeChannel();
  }
  
  var self = this;
  
  channel.once('idle', function(){
    self._freeChannels.push(channel);
    self._addExcessTimeout();
  });
  
  return channel;
};

ChannelPool.prototype.channel = function(callback) {
  
  var self = this;
  
  process.nextTick(function() {
    
    var channel = self._allocateBusyChannel();
    
    if (!channel) {
      callback(new Error('failed to allocate channel'));
      return;
    }
    
    callback(null, channel);
  });
};

ChannelPool.prototype._forwardCall = function(method, methodArgs){
  
  this.channel(function(error, channel) {
    
    if (error) {
      
      var brokenConnection = {
        connect: function(callback) {
          process.nextTick(function() {
            callback(error);
          });
        }
      };
      
      channel = new Channel(brokenConnection);
    };
    
    method.apply(channel, methodArgs);
  });
  
};

ChannelPool.prototype.send = function() {
  this._forwardCall(Channel.prototype.send, arguments);
};

ChannelPool.prototype.subscribe = function() {
  this._forwardCall(Channel.prototype.subscribe, arguments);
};

ChannelPool.prototype.begin = function() {
  this._forwardCall(Channel.prototype.begin, arguments);
};

module.exports = ChannelPool;

@@ -180,61 +180,8 @@
 /%0A %0A
-var ConnectFailover = require('./connect_failover');%0A
 var 
@@ -3233,25 +3233,24 @@
 tion);%0A    %7D
-;
 %0A    %0A    me

Fix jshint warnings