Source: countdown.js

/**
 * @typedef {Object} TimeRemaining
 * @property {Number} days Days remaining
 * @property {Number} hours Hours remaining
 * @property {Number} minutes Minutes remaining
 * @property {Number} seconds Seconds remaining
 */

/**
 * Class representing a countdown.
 *
 * For full documentation, see the {@link https://wiki.tremorvideodsp.com/display/eng/Countdown Countdown Snippet Wiki Page}
 */
class Countdown {
  /**
   * Create a countdown.
   * @param {Object} opts
   * @param {Date} opts.date - Javascript Date Object.
   * @param {Number} [opts.frequency=1] - Frequency of COUNTDOWN_TIME event.
   * @param {String} [opts.suffix] - String to append to event names.
   */
  constructor (opts) {
    if (!opts || !opts.date) throw new Error('Countdown requires an options object with a date property')
    if (!(opts.date instanceof Date)) throw new Error('The provided date must be an instance of the Date class')
    this.date = opts.date
    this.frequency = isNaN(opts.frequency) ? 1 : +opts.frequency
    this.suffix = opts.suffix ? `_${opts.suffix}` : ''
    this._inProgress = false
    this._paused = false
    this._interval = null

    window.$b.on('AdPaused', () => {
      this._paused = true
      if (this._interval) this.stopCountdown()
    })
    window.$b.on('AdPlaying', () => {
      this._paused = false
      if (this._inProgress) this.startCountdown()
    })
  }

  /**
   * @summary Start the countdown.
   * @param {Date} [newDate] A new Javascript Date Object to use for the countdown.
   * @emits Countdown#COUNTDOWN_TIME - when called and at every tick
   * @emits Countdown#COUNTDOWN_COMPLETE - when countdown is finished
   */
  startCountdown (newDate) {
    if (newDate) {
      if (!(newDate instanceof Date)) throw new Error('The provided date must be an instance of the Date class')
      if (this._interval) {
        clearInterval(this._interval)
        this._interval = null
      }
      this.date = newDate
    }
    if (this._paused || this._interval) return
    let remainingTime = this.getRemainingTime()
    if (remainingTime) {
      /**
       * @summary Event emitted on $b to pass up-to-date time info.
       * @event Countdown#COUNTDOWN_TIME
       * @type {TimeRemaining}
       */
      window.$b.emit(`COUNTDOWN_TIME${this.suffix}`, remainingTime)
    } else {
      /**
       * @summary Event emitted on $b to indicate the countdown is complete.
       * @event Countdown#COUNTDOWN_COMPLETE
       */
      window.$b.emit(`COUNTDOWN_COMPLETE${this.suffix}`)
      return
    }
    this._interval = setInterval(() => {
      let remainingTime = this.getRemainingTime()
      if (remainingTime) {
        window.$b.emit(`COUNTDOWN_TIME${this.suffix}`, remainingTime)
      } else {
        this.stopCountdown()
        window.$b.emit(`COUNTDOWN_COMPLETE${this.suffix}`)
      }
    }, this.frequency * 1000)
    this._inProgress = true
  }

  /**
   * @summary Stop the countdown.
   * @emits Countdown#COUNTDOWN_STOPPED - when called
  */
  stopCountdown () {
    if (!this._interval) return
    clearInterval(this._interval)
    this._interval = null
    if (!this._paused) this._inProgress = false
    /**
     * @summary Event emitted on $b to indicate the countdown stopped.
     * @event Countdown#COUNTDOWN_STOPPED
     */
    window.$b.emit(`COUNTDOWN_STOPPED${this.suffix}`)
  }

  /**
   * @summary Get the time remaining in the countdown.
   * @return {TimeRemaining} Object with days, hours, minutes, and seconds properties.
   */
  getRemainingTime () {
    const ms = this.date - (new Date())
    if (ms <= 0) return null
    const totalS = Math.ceil(ms / 1000)
    const seconds = totalS % 60
    const totalM = Math.floor(totalS / 60)
    const minutes = totalM % 60
    const totalH = Math.floor(totalM / 60)
    const hours = totalH % 24
    const days = Math.floor(totalH / 24)
    return { days, hours, minutes, seconds }
  }

  /**
   * @summary Find out if countdown has completed.
   * @return {Boolean} True if countdown has finished, otherwise False.
   */
  hasCountdownFinished () {
    return (new Date()) >= this.date
  }
}

window.$b = window.$b || {}
window.$b.snippets = window.$b.snippets || {}
var snippets = window.$b.snippets
snippets.Countdown = Countdown

if (window.module) {
  window.module.exports = Countdown
}