#!/bin/sh
: ; exec klone $0 "$@"
; The above line finds the klone executable in the $PATH
;;Skeleton of a typical klone script
;;(stack-dump-on-error t)
;;(kdb t)


(setq args (getopts "USAGE: %0 [options] file"
    ("-c" () nsizes "number of columns (default 5)")
    ("-t" seconds time-delta "time in seconds between updates (def. 10)")
    ("-b" bytes bar-graph 
      "displays a bar-graph of progress, bytes being the expected
size in bytes. the program will end when the size is reached")
    ("-s" filename stop-file "stops if file exists")
))

(setq time-delta (if time-delta (Int time-delta) 10))
(setq nsizes (if nsizes (Int nsizes) 6))
(setq column-width (/ 64 nsizes))
(if (/= 1 (length args)) (getopts :usage))
(setq label "sliding averages:")
(setq corr (- (length label) 12))

(defun main (file &aux
    (start-time (get-internal-run-time))
    (sizes (vector))
    (start-size 0)
    s
  )
  (print-format label)
  (dotimes (i (- nsizes 1))
    (setq s (print-format String "%0s" (* (+ i 1) time-delta)))
    (print-format "%1%0" s (make-string (- (- column-width (length s))
	  (if (= i 0) corr 0)
  ))))
  (print-format "  | total\n")
  (setq start-size (get (file-stats file) 'size 0))
  (setq sizes (make-list nsizes start-size))
  (while t
    (monitor-file file)
    (select () :timeout (* 1000 time-delta))
  )
)

;; globals: time-delta sizes nsizes start-time start-size 
(defun monitor-file (filename
    &aux
    (size (get (file-stats filename) 'size 0))
    (time (- (get-internal-run-time) start-time))
    (time-string (print-time time))
    s n ss
  )
  (dotimes (i (- nsizes 1))		;move size one step
    (put sizes (- nsizes (+ i 1)) (get sizes (- nsizes (+ i 2)) 0))
  )
  (put sizes 0 size)
  (setq ss (print-size size))
  (print-format "%0%2%1: " time-string ss 
    (make-string (- 12 (+ (length ss) (length time-string))))
  )
  (dotimes (i (- nsizes 1))
    (setq n (+ i 1))
    (setq s (print-speed (/ (- size (get sizes n)) (* n time-delta))))
    (print-format "%1%0" s (make-string (- column-width (length s))))
  )
  (if (> (/ time 1000) 0)
    (print-format  "| %0" (print-speed (/ (- size start-size) (/ time 1000))))
  )
  (print-format "\n")
  (flush s)
)

;; printable version of a time in ms: hms
(defun print-time (ms &aux
    (s (mod (/ ms 1000) 60))
    (m (mod (/ ms 60000) 60))
    (h (/ ms 3600000))
    (res (copy ""))
  )
  (if (> h 0) (nconc res (print-format String "%0h" h)))
  (if (> m 0) (nconc res (print-format String "%0m" m)))
  (nconc res (print-format String "%0s" s))
  res
)
;; k or M
(defun print-size (s &aux
    (k (mod (/ s 1024) 1024))
    (m (/ s 1048576))
    (res (copy ""))
  )
  (if (> m 0) (nconc res (print-format String "%0M" m)))
  (nconc res (print-format String "%0k" 
      (expand-num (Int (* (/ k 1024.) 1000)) 3))
  )
  (if (and (= 0 m) (= 0 k))
    (nconc res (print-format String "%0" (/ (* s 10) 1024)))
  )
  res
)
;; speed: Kps or bps
(defun print-speed (speed)
  (if (> speed 64000) 
    (print-format String "%0Kps" (Int (/ speed 1024)))
    (>= speed 0)
    (print-format String "%0bps" (Int speed))
    "-"
))

(defun main-bar (file total)
  (ascii-progress-bar-with-speed (get (file-stats file) 'size 0) total)
  (catch 'Done
    (while t
      (if (and stop-file (file-stats stop-file)) (throw 'Done))
      (setq size (get (file-stats file) 'size 0))
      (if (>= size total) 
	(throw 'Done (ascii-progress-bar-with-speed total))
      )
      (ascii-progress-bar-with-speed size)
      (select () :timeout (* 1000 time-delta))
  ))
  (print-format  *standard-error* "%0\n\e[A" (make-string 78))
)

(with (file (get args 0 '(getopts :usage)))
  (if bar-graph
    (main-bar file (Int bar-graph))
    (main file)
))

;;; EMACS MODES
;;; Local Variables: ***
;;; mode:lisp ***
;;; End: ***

