class Console::Progress

def self.now

def self.now
	Process.clock_gettime(Process::CLOCK_MONOTONIC)
end

def average_duration

def average_duration
	if @current > 0
		duration / @current
	end
end

def duration

def duration
	Progress.now - @start_time
end

def duration_since_last_output

def duration_since_last_output
	if @last_output_time
		Progress.now - @last_output_time
	end
end

def estimated_remaining_time

def estimated_remaining_time
	if average_duration = self.average_duration
		average_duration * remaining
	end
end

def increment(amount = 1)

def increment(amount = 1)
	@current += amount
	
	if output?
		Console.call(@subject, self.to_s, event: self.to_hash, **@options)
		@last_output_time = Progress.now
	end
	
	return self
end

def initialize(subject, total = 0, minimum_output_duration: 0.1, **options)

def initialize(subject, total = 0, minimum_output_duration: 0.1, **options)
	@subject = subject
	@options = options
	
	@start_time = Progress.now
	
	@last_output_time = nil
	@minimum_output_duration = minimum_output_duration
	
	@current = 0
	@total = total
end

def mark(*arguments, **options)

def mark(*arguments, **options)
	Console.call(@subject, *arguments, **options, **@options)
end

def output?

def output?
	if remaining.zero?
		return true
	elsif duration = duration_since_last_output
		return duration > @minimum_output_duration
	else
		return true
	end
end

def ratio

def ratio
	Rational(@current.to_f, @total.to_f)
end

def remaining

def remaining
	@total - @current
end

def resize(total)

def resize(total)
	@total = total
	
	Console.call(@subject, self.to_s, event: self.to_hash, **@options)
	@last_output_time = Progress.now
	
	return self
end

def to_hash

def to_hash
	Hash.new.tap do |hash|
		hash[:type] = :progress
		hash[:current] = @current
		hash[:total] = @total
		
		hash[:duration] = self.duration
		hash[:estimated_remaining_time] = self.estimated_remaining_time
	end
end

def to_s

def to_s
	if estimated_remaining_time = self.estimated_remaining_time
		"#{@current}/#{@total} completed in #{Clock.formatted_duration(self.duration)}, #{Clock.formatted_duration(estimated_remaining_time)} remaining."
	else
		"#{@current}/#{@total} completed, waiting for estimate..."
	end
end