exports = class Exercise { constructor(params) { this.completed = false; this.sets = []; this.title = params.title; this.weight = params.weight; this.weightIncrement = params.weightIncrement; this.unit = params.unit; this.restPeriod = params.restPeriod; this._originalRestPeriod = params.restPeriod; this._restTimeout = null; this._restInterval = null; this._state = null; } get humanTitle() { return `${this.title} ${this.weight}${this.unit}`; } get subTitle() { const totalSets = this.sets.length; const uncompletedSets = this.sets.filter((set) => !set.isCompleted()).length; const currentSet = (totalSets - uncompletedSets) + 1; return `Set ${currentSet} of ${totalSets}`; } decRestPeriod() { this.restPeriod--; } addSet(set) { this.sets.push(set); } currentSet() { return this.sets.filter(set => !set.isCompleted())[0]; } isLastSet() { return this.sets.filter(set => !set.isCompleted()).length === 1; } isCompleted() { return !!this.completed; } canSetCompleted() { return this.sets.filter(set => set.isCompleted()).length === this.sets.length; } setCompleted() { if (!this.canSetCompleted()) throw "All sets must be completed"; if (this.canProgress()) this.weight += this.weightIncrement; this.completed = true; } canProgress() { let completedRepsTotalSum = 0; let targetRepsTotalSum = 0; this.sets.forEach(set => completedRepsTotalSum += set.reps); this.sets.forEach(set => targetRepsTotalSum += set.maxReps); return (targetRepsTotalSum - completedRepsTotalSum) === 0; } startRestTimer(workout) { this._restTimeout = setTimeout(() => { this.next(workout); }, 1000 * this.restPeriod); this._restInterval = setInterval(() => { this.decRestPeriod(); if (this.restPeriod < 0) { this.resetRestTimer(); this.next(); return; } workout.emit("redraw"); }, 1000 ); } resetRestTimer() { clearTimeout(this._restTimeout); clearInterval(this._restInterval); this._restTimeout = null; this._restInterval = null; this.restPeriod = this._originalRestPeriod; } isRestTimerRunning() { return this._restTimeout != null; } setupStartedButtons(workout) { clearWatch(); setWatch(() => { this.currentSet().incReps(); workout.emit("redraw"); }, BTN1, {repeat: true}); setWatch(workout.next.bind(workout), BTN2, {repeat: false}); setWatch(() => { this.currentSet().decReps(); workout.emit("redraw"); }, BTN3, {repeat: true}); } setupRestingButtons(workout) { clearWatch(); setWatch(workout.next.bind(workout), BTN2, {repeat: false}); } next(workout) { const STARTED = 1; const RESTING = 2; const COMPLETED = 3; switch(this._state) { case null: this._state = STARTED; this.setupStartedButtons(workout); break; case STARTED: this._state = RESTING; this.startRestTimer(workout); this.setupRestingButtons(workout); break; case RESTING: this.resetRestTimer(); this.currentSet().setCompleted(); if (this.canSetCompleted()) { this._state = COMPLETED; this.setCompleted(); } else { this._state = null; } // As we are changing state and require it to be reprocessed // invoke the next step of workout workout.next(); break; default: throw "Exercise: Attempting to move to an unknown state"; } workout.emit("redraw"); } };