1'use strict' 2var util = require('util') 3var TrackerBase = require('./tracker-base.js') 4var Tracker = require('./tracker.js') 5var TrackerStream = require('./tracker-stream.js') 6 7var TrackerGroup = module.exports = function (name) { 8 TrackerBase.call(this, name) 9 this.parentGroup = null 10 this.trackers = [] 11 this.completion = {} 12 this.weight = {} 13 this.totalWeight = 0 14 this.finished = false 15 this.bubbleChange = bubbleChange(this) 16} 17util.inherits(TrackerGroup, TrackerBase) 18 19function bubbleChange (trackerGroup) { 20 return function (name, completed, tracker) { 21 trackerGroup.completion[tracker.id] = completed 22 if (trackerGroup.finished) { 23 return 24 } 25 trackerGroup.emit('change', name || trackerGroup.name, trackerGroup.completed(), trackerGroup) 26 } 27} 28 29TrackerGroup.prototype.nameInTree = function () { 30 var names = [] 31 var from = this 32 while (from) { 33 names.unshift(from.name) 34 from = from.parentGroup 35 } 36 return names.join('/') 37} 38 39TrackerGroup.prototype.addUnit = function (unit, weight) { 40 if (unit.addUnit) { 41 var toTest = this 42 while (toTest) { 43 if (unit === toTest) { 44 throw new Error( 45 'Attempted to add tracker group ' + 46 unit.name + ' to tree that already includes it ' + 47 this.nameInTree(this)) 48 } 49 toTest = toTest.parentGroup 50 } 51 unit.parentGroup = this 52 } 53 this.weight[unit.id] = weight || 1 54 this.totalWeight += this.weight[unit.id] 55 this.trackers.push(unit) 56 this.completion[unit.id] = unit.completed() 57 unit.on('change', this.bubbleChange) 58 if (!this.finished) { 59 this.emit('change', unit.name, this.completion[unit.id], unit) 60 } 61 return unit 62} 63 64TrackerGroup.prototype.completed = function () { 65 if (this.trackers.length === 0) { 66 return 0 67 } 68 var valPerWeight = 1 / this.totalWeight 69 var completed = 0 70 for (var ii = 0; ii < this.trackers.length; ii++) { 71 var trackerId = this.trackers[ii].id 72 completed += 73 valPerWeight * this.weight[trackerId] * this.completion[trackerId] 74 } 75 return completed 76} 77 78TrackerGroup.prototype.newGroup = function (name, weight) { 79 return this.addUnit(new TrackerGroup(name), weight) 80} 81 82TrackerGroup.prototype.newItem = function (name, todo, weight) { 83 return this.addUnit(new Tracker(name, todo), weight) 84} 85 86TrackerGroup.prototype.newStream = function (name, todo, weight) { 87 return this.addUnit(new TrackerStream(name, todo), weight) 88} 89 90TrackerGroup.prototype.finish = function () { 91 this.finished = true 92 if (!this.trackers.length) { 93 this.addUnit(new Tracker(), 1, true) 94 } 95 for (var ii = 0; ii < this.trackers.length; ii++) { 96 var tracker = this.trackers[ii] 97 tracker.finish() 98 tracker.removeListener('change', this.bubbleChange) 99 } 100 this.emit('change', this.name, 1, this) 101} 102 103var buffer = ' ' 104TrackerGroup.prototype.debug = function (depth) { 105 depth = depth || 0 106 var indent = depth ? buffer.slice(0, depth) : '' 107 var output = indent + (this.name || 'top') + ': ' + this.completed() + '\n' 108 this.trackers.forEach(function (tracker) { 109 if (tracker instanceof TrackerGroup) { 110 output += tracker.debug(depth + 1) 111 } else { 112 output += indent + ' ' + tracker.name + ': ' + tracker.completed() + '\n' 113 } 114 }) 115 return output 116} 117