#! /usr/bin/ruby
#
# Copyright(C) 2011  Yuichi Kobayashi <kobayasy@kobayasy.com>
# Last modified: Sat Mar 19 13:34:39 JST 2011 (kobayasy)

def ttyPlay(io, seek = false)
  diffTimeFirst, cutTime = nil, 0
  recTimeFirst, recTimeLast = nil, nil
  until io.eof
    sec, usec, length = io.read(12).unpack('VVV')
    tty = io.read(length)
    recTime, timeNow = Time.at(sec, usec).to_f, Time.now.to_f
    diffTime = recTime - timeNow
    unless diffTimeFirst
      diffTimeFirst = diffTime
      recTimeFirst = recTime
    else
      if block_given?
        waitTimeMax, playSpeed = yield(recTime, tty)
        waitTime = recTime - recTimeLast
        if waitTimeMax and (t = waitTime - waitTimeMax) > 0
          cutTime += t
          waitTime -= t
        end
        if playSpeed and playSpeed > 0
          t = waitTime - waitTime.quo(playSpeed)
          cutTime += t
          waitTime -= t
        end
      end
      unless seek
        t = diffTime - diffTimeFirst - cutTime
        sleep(t) if t > 0
      end
    end
    if seek.is_a?(IO)
      sec, usec = (recTime - recTimeFirst - cutTime).divmod(1)
      seek << [sec, usec * 1000000, length].pack('VVV') << tty
    elsif !seek
      $> << tty
      $>.flush
    end
    recTimeLast = recTime
  end
  [Time.at(recTimeFirst), Time.at(recTimeLast),
   recTimeLast - recTimeFirst - cutTime ]
end

def ttyPlayInfo(io, seek = true, &block)
  recTimeFirst, recTimeLast, timePlay = ttyPlay(io, seek, &block)
  recMin, recSec = (recTimeLast - recTimeFirst).divmod(60)
  recHour, recMin = recMin.divmod(60)
  playMin, playSec = timePlay.divmod(60)
  playHour, playMin = playMin.divmod(60)
  info = []
  unless recTimeFirst.to_f.zero?
    info << ['Record start', recTimeFirst.strftime('%a %-d %b %Y %X %Z')]
    info << ['last', recTimeLast.strftime('%a %-d %b %Y %X %Z')]
  end
  info << ['Record time', '%3d:%02d:%06.3f' % [recHour, recMin, recSec]]
  info << ['Play time', '%3d:%02d:%06.3f' % [playHour, playMin, playSec]]
  length = 0
  info.each do |name, value|
    length = name.length if name.length > length
  end
  $> << io.path << "\n" if io.is_a?(File)
  info.each do |name, value|
    $> << '%*s: %s' % [length, name, value] << "\n"
  end
  [recTimeFirst, recTimeLast, timePlay]
end

unless $0 == __FILE__
  class TTYPlay
    alias_method(:play, :ttyPlay)
    alias_method(:info, :ttyPlayInfo)
    public :play, :info
  end
  undef :ttyPlay, :ttyPlayInfo
else
  Version = '0.7'
  require 'optparse'
  playMode, seek, waitTimeMax, playSpeed = :ttyPlay, false, nil, nil
  ARGV.options do |opt|
    opt.on('--play'){playMode, seek = :ttyPlay, false}
    opt.on('--conv'){playMode, seek = :ttyPlay, $>}
    opt.on('--info'){playMode, seek = :ttyPlayInfo, true}
    opt.on('--cut=SEC', Float){|value| waitTimeMax = value}
    opt.on('-s', '--speed=NUM', Float){|value| playSpeed = value}
    opt.on('-n'){waitTimeMax = 0}
    opt.parse!
  end
  proc = method(playMode)
  if ARGV.size.zero?
    proc.call(ARGF, seek){[waitTimeMax, playSpeed]}
  else
    ARGV.each{|arg| open(arg){|f| proc.call(f, seek){[waitTimeMax, playSpeed]}}}
  end
end
