All Downloads are FREE. Search and download functionalities are using the official Maven repository.

poly.util.progressbar.ProgressBar.scala Maven / Gradle / Ivy

The newest version!
package poly.util.progressbar

import java.time._
import poly.util.logging._

/**
 * A simple console-based progress bar.
 * @param task Name of the progress bar.
 * @param initialMax Initial estimation of the number of steps when the task is complete.
 * @param length The length of the progress bar shown in console. Default value is 25 characters.
 *
 * @author Tongfei Chen ([email protected]).
 */
class ProgressBar(val task: String, val initialMax: Int, val length: Int = 25) extends HasLogger {

  private[this] var current = 0
  private[this] var max = initialMax
  private[this] var startTime: LocalDateTime = null
  private[this] var lastTime: LocalDateTime = null

  private[this] def repeat(x: Char, n: Int): String = {
    new String(Array.fill[Char](n)(x))
  }

  private[this] def progress: Int = {
    if (max == 0) 0
    else math.round(current.toDouble / max * length).toInt
  }

  private[this] def formatDuration(d: Duration): String = {
    val s = d.getSeconds
    "%d:%02d:%02d".format(s / 3600, (s % 3600) / 60, s % 60)
  }

  private[this] def eta(elapsed: Duration) = {
    if (max == 0) "?"
    else if (current == 0) "?"
    else formatDuration(elapsed.dividedBy(current).multipliedBy(max - current))
  }

  private[this] def percentage: String = {
    val res = if (max == 0) "? %"
    else math.round(current.toDouble / max * 100).toString + "%"
    repeat(' ', 4 - res.length) + res // pad space before percentage
  }

  private[this] def forceShow(currentTime: LocalDateTime): Unit = {
    print('\r')
    val elapsed = Duration.between(startTime, currentTime)
    lastTime = currentTime
    print(
      task
        + s" $percentage"
        + " [" + repeat('=', progress) + repeat(' ', length - progress) + "] "
        + s"$current/$max "
        + "(" + formatDuration(elapsed) + " / " + eta(elapsed) + ")    "
    )
  }

  private[this] def show(): Unit = {
    val currentTime = LocalDateTime.now
    if (Duration.between(lastTime, currentTime).getSeconds < 1) return
    forceShow(currentTime)
  }

  /**
   * Starts the progress bar.
   */
  def start() = {
    startTime = LocalDateTime.now
    lastTime = LocalDateTime.now
    logger.info(s"Task ($task) starts.")
    forceShow(lastTime)
  }

  /**
   * Advances the progress bar by a specific amount.
   * @param n Step size
   */
  def stepBy(n: Int) = {
    current += n
    if (current > max) max = current
    show()
  }

  /**
   * Advances the progress bar by one step.
   */
  def step() = {
    current += 1
    if (current > max) max = current
    show()
  }

  /**
   * Gives a hint to the maximum value of the progress bar.
   * @param n Hint to the maximum value
   */
  def maxHint(n: Int) = {
    max = n
    show()
  }

  /**
   * Stops the progress bar.
   */
  def stop() = {
    forceShow(LocalDateTime.now)
    println()
    logger.info(s"Task ($task) is complete.")
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy