# $Id: progress.rb,v 1.1 2002/09/28 12:26:56 sdalu Exp $

#
# Copyrigth (C) 2002  Stephane D'Alu
# Code is under GPL v2 (see http://www.gnu.org/licenses/gpl.txt)
#
# WWW: http://www.sdalu.com/software/
#

module TTY
    class ProgressBar
        EraseEndLine            = "\033[K" 
        HideCursor              = "\033[?25l"
        ShowCursor              = "\033[?25h"
	ProgressBarSize		= 37
	DisplayNoFinalStatus    = 0x1

	def initialize(output, precision, display = 0)
            @output     = output
            @precision  = precision
            @display    = display
        end

        def start(length, totalrsize = 0)
            @length     = length
            @starttime  = @lasttime = Time.now
            @totaltime  = 0
            @totalsize  = 0
            @totalrsize = totalrsize
            @tick       = 0
            update_barstr
            unless @output.nil?
                @output.print HideCursor 
                @output.print @barstr
            end
        end

        def processed(size)
            @totalsize  += size;
            @totalrsize += size
            nowtime      = Time.now
            @deltatime   = nowtime - @lasttime
            
            if @deltatime > @precision
                @totaltime      = @lasttime == @starttime \
                                        ? 0.0 : nowtime - @starttime
                @lasttime       = nowtime
                
                update_barstr

                unless @output.nil?
                    @output.print "\r", @barstr, EraseEndLine
                    @output.flush
                end

                @tick += 1
            end
            @barstr.dup
        end

        def done(filename)
            filename = filename.slice(0,52) + ":"
            if @totaltime == 0.0 
                @barstr = sprintf "%-53s  %10d  [  --.--#{unit}]", 
                        filename, @totalsize
            else
                speed = @totalrsize.to_f / @totaltime
                @barstr = sprintf "%-53s  %10d  [%7.2f#{unit}]",
                        filename, @totalsize, unit_cvt(speed)
            end
            
            if (@display & DisplayNoFinalStatus) != 0
                str = "\r#{EraseEndLine}"
            else
                str = "\r#{@barstr}#{EraseEndLine}\n"
            end
            unless @output.nil?
                @output.print str
                @output.flush
            end
            @barstr.dup
        end

	def failed(filename)
            filename = filename.slice(0,52) + ":"
	    @barstr = sprintf "%-53s                 Failed", filename
            if (@display & DisplayNoFinalStatus) != 0
                str = "\r#{EraseEndLine}"
            else
                str = "\r#{@barstr}#{EraseEndLine}\n"
            end
            unless @output.nil?
                @output.print str
                @output.flush
            end
            @barstr.dup
	end

        def finish
            @output.print ShowCursor unless @output.nil?
        end
                
        def to_s
            @barstr.dup
        end

        #-- [protected] ---------------------------------------------
        protected

	def unit            ; "K/s"      ; end
	
	def unit_cvt(value) ; value/1024 ; end

        def update_barstr
            speed = @totaltime == 0.0 ? -1.0 : @totalrsize / @totaltime
	    speed_str = if speed < 0.0 
			then "--.--#{unit}"
			else "%7.2f#{unit}" % (unit_cvt(speed))
			end
            
            totalsizestr = @totalsize.to_s.reverse!
            totalsizestr.gsub!(/(...)/, '\1,')
            totalsizestr.reverse!
            totalsizestr.gsub!(/^,/, '')
            
            if @length > 0 then
                pct = 100 * @totalsize / @length
                rmt = speed < 0.0 ? -1 : ((@length-@totalrsize) / speed).to_i
                
                str = pct == 100 ? "100%%" : "%2d%% " % pct
                str << sprintf("[%-#{ProgressBarSize}.#{ProgressBarSize}s]",
                    "=" * (ProgressBarSize * pct / 100) + ">")
                str << sprintf(" %-11s", totalsizestr)
		str << sprintf(" %10s", speed_str)
                str << sprintf(" %12s", "ETA %s" % sec_to_timestr(rmt))
            else
                ind = @tick % (ProgressBarSize * 2 - 6)
                if ind < ProgressBarSize - 2
                    pos = ind + 1;
                else
                    pos = ProgressBarSize - (ind - ProgressBarSize + 5)
                end
                bar = (" " * ProgressBarSize)
                bar[pos-1,3] = '<=>'
                
                str = sprintf "    [%s] %-11s %10s", 
		    bar, totalsizestr, speed_str
            end
            @barstr = str
        end

        #-- [private] -----------------------------------------------
        private

        def sec_to_timestr(sec)
            return "--:--" if sec < 0
            
            hrs = sec / 3600; sec %= 3600;
            min = sec / 60;   sec %= 60;
            
            if (hrs > 0)
                return sprintf("%2d:%02d:%02d", hrs, min, sec)
            else
                return sprintf("%2d:%02d", min, sec)
            end
        end
    end
end
