
/**
 * Mapping of torrent pieces to their respective availability in the torrent swarm. Used
 * by the torrent manager for implementing the rarest piece first selection strategy.
 */
class RarityMap {
  constructor (torrent) {
    const self = this

    self._torrent = torrent
    self._numPieces = torrent.pieces.length
    self._pieces = new Array(self._numPieces).fill(0)

    self._onWire = wire => {
      self.recalculate()
      self._initWire(wire)
    }
    self._onWireHave = index => {
      self._pieces[index] += 1
    }
    self._onWireBitfield = () => {
      self.recalculate()
    }

    self._torrent.wires.forEach(wire => {
      self._initWire(wire)
    })
    self._torrent.on('wire', self._onWire)
    self.recalculate()
  }

  /**
   * Get the index of the rarest piece. Optionally, pass a filter function to exclude
   * certain pieces (for instance, those that we already have).
   *
   * @param {function} pieceFilterFunc
   * @return {number} index of rarest piece, or -1
   */
  getRarestPiece (pieceFilterFunc) {
    let candidates = []
    let min = Infinity

    for (let i = 0; i < this._numPieces; ++i) {
      if (pieceFilterFunc && !pieceFilterFunc(i)) continue

      const availability = this._pieces[i]
      if (availability === min) {
        candidates.push(i)
      } else if (availability < min) {
        candidates = [ i ]
        min = availability
      }
    }

    if (candidates.length) {
      // if there are multiple pieces with the same availability, choose one randomly
      return candidates[Math.random() * candidates.length | 0]
    } else {
      return -1
    }
  }

  destroy () {
    const self = this
    self._torrent.removeListener('wire', self._onWire)
    self._torrent.wires.forEach(wire => {
      self._cleanupWireEvents(wire)
    })
    self._torrent = null
    self._pieces = null

    self._onWire = null
    self._onWireHave = null
    self._onWireBitfield = null
  }

  _initWire (wire) {
    const self = this

    wire._onClose = function () {
      self._cleanupWireEvents(wire)
      for (let i = 0; i < this._numPieces; ++i) {
        self._pieces[i] -= wire.peerPieces.get(i)
      }
    }

    wire.on('have', self._onWireHave)
    wire.on('bitfield', self._onWireBitfield)
    wire.once('close', wire._onClose)
  }

  /**
   * Recalculates piece availability across all peers in the torrent.
   */
  recalculate () {
    this._pieces.fill(0)

    for (const wire of this._torrent.wires) {
      for (let i = 0; i < this._numPieces; ++i) {
        this._pieces[i] += wire.peerPieces.get(i)
      }
    }
  }

  _cleanupWireEvents (wire) {
    wire.removeListener('have', this._onWireHave)
    wire.removeListener('bitfield', this._onWireBitfield)
    if (wire._onClose) wire.removeListener('close', wire._onClose)
    wire._onClose = null
  }
}

module.exports = RarityMap

@@ -229,35 +229,12 @@
     
-const self = this%0A%0A    self
+this
 ._to
@@ -253,20 +253,20 @@
 ent%0A    
-self
+this
 ._numPie
@@ -293,28 +293,28 @@
 .length%0A    
-self
+this
 ._pieces = n
@@ -322,20 +322,20 @@
 w Array(
-self
+this
 ._numPie
@@ -348,28 +348,28 @@
 ill(0)%0A%0A    
-self
+this
 ._onWire = w
@@ -375,36 +375,36 @@
 wire =%3E %7B%0A      
-self
+this
 .recalculate()%0A 
@@ -404,28 +404,28 @@
 ate()%0A      
-self
+this
 ._initWire(w
@@ -431,36 +431,36 @@
 wire)%0A    %7D%0A    
-self
+this
 ._onWireHave = i
@@ -471,28 +471,28 @@
  =%3E %7B%0A      
-self
+this
 ._pieces%5Bind
@@ -506,28 +506,28 @@
 1%0A    %7D%0A    
-self
+this
 ._onWireBitf
@@ -543,28 +543,28 @@
  =%3E %7B%0A      
-self
+this
 .recalculate
@@ -573,28 +573,28 @@
 %0A    %7D%0A%0A    
-self
+this
 ._torrent.wi
@@ -621,20 +621,20 @@
 %7B%0A      
-self
+this
 ._initWi
@@ -645,36 +645,36 @@
 ire)%0A    %7D)%0A    
-self
+this
 ._torrent.on('wi
@@ -670,36 +670,36 @@
 rent.on('wire', 
-self
+this
 ._onWire)%0A    se
@@ -696,20 +696,20 @@
 re)%0A    
-self
+this
 .recalcu
@@ -1623,34 +1623,12 @@
     
-const self = this%0A    self
+this
 ._to
@@ -1652,28 +1652,28 @@
 ner('wire', 
-self
+this
 ._onWire)%0A  
@@ -1670,28 +1670,28 @@
 onWire)%0A    
-self
+this
 ._torrent.wi
@@ -1710,36 +1710,36 @@
 wire =%3E %7B%0A      
-self
+this
 ._cleanupWireEve
@@ -1759,20 +1759,20 @@
  %7D)%0A    
-self
+this
 ._torren
@@ -1780,28 +1780,28 @@
  = null%0A    
-self
+this
 ._pieces = n
@@ -1805,28 +1805,28 @@
 = null%0A%0A    
-self
+this
 ._onWire = n
@@ -1825,36 +1825,36 @@
 Wire = null%0A    
-self
+this
 ._onWireHave = n
@@ -1861,20 +1861,20 @@
 ull%0A    
-self
+this
 ._onWire
@@ -1919,31 +1919,8 @@
 ) %7B%0A
-    const self = this%0A%0A
     
@@ -1939,19 +1939,13 @@
 e = 
-function ()
+() =%3E
  %7B%0A 
@@ -1949,20 +1949,20 @@
 %7B%0A      
-self
+this
 ._cleanu
@@ -2037,20 +2037,20 @@
         
-self
+this
 ._pieces
@@ -2114,20 +2114,20 @@
 'have', 
-self
+this
 ._onWire
@@ -2160,12 +2160,12 @@
 d', 
-self
+this
 ._on

stop using self