#!/usr/bin/env ruby

def die(msg)
 puts msg
 exit(1)
end

die("usage: #{$PROGRAM_NAME} <keylog.csv>") unless ARGV.length == 1
keylog = File.open(ARGV[0], 'r') { |f| f.readlines.map(&:chomp) }

KEYS = {
 0 => ' 0',
 1 => '.,\'?!"1-()@/:',
 2 => 'abc2',
 3 => 'def3',
 4 => 'ghi4',
 5 => 'jkl5',
 6 => 'mno6',
 7 => 'pqrs7',
 8 => 'tuv8',
 9 => 'wxyz9',
 10 => '@/:_;+&%*[]{}',
 11 => :hash,
 100 => :left,
 101 => :right,
 102 => :up,
 103 => :down,
 104 => :accept,
 105 => :reject
}

$last_length = nil

def report_progress(string)
 # puts string
 print " #{' ' * $last_length}\r" if $last_length
 print " #{string}\r"
 $last_length = string.length
 sleep(0.01)
end

$buffer = ''
$cursor = 0

def buffer_insert!(char)
 before = $buffer[0...$cursor] || ''
 after = $buffer[$cursor..-1] || ''
 $buffer = before + char + after
 $cursor += 1
end

def buffer_change!(char)
 before = $buffer[0...$cursor-1] || ''
 after = $buffer[$cursor..-1] || ''
 $buffer = before + char + after
end

def buffer_erase!
 before = $buffer[0...$cursor-1] || ''
 after = $buffer[$cursor..-1] || ''
 $buffer = before + after
 $cursor = [$cursor - 1, 0].max
end

def buffer_move!(amount)
 cursor = $cursor + amount
 $cursor = [cursor, 0].max
 $cursor = [cursor, $buffer.length].min
end

long_press = 1000
last_key = 0
last_index = 0
last_timestamp = 0
keylog.each do |line|
 timestamp, key = line.chomp.split(',').map(&:to_i)
 value = KEYS[key] || die("unknown key #{key}")
 case value
 when String
   if key != last_key || timestamp - last_timestamp >= long_press
     last_index = 0
     buffer_insert!(value[last_index])
   else
     last_index = (last_index + 1) % value.length
     buffer_change!(value[last_index])
   end
 when :right then buffer_erase!
 when :up then buffer_move!(-1)
 when :down then buffer_move!(1)
 end
 report_progress($buffer)
 last_key = key
 last_timestamp = timestamp
end
puts