local al = require 'abletonlink'
local termio = require 'posix.termio'
local poll = require 'posix.poll'

function print_help()
  print([[
 < L I N K  H U T >

usage:
  enable / disable Link: a
  start / stop: space
  decrease / increase tempo: w / e
  decrease / increase quantum: r / t
  enable / disable start stop sync: s
  quit: q]])
end

function set_buffered_input(enable)
  local t = termio.tcgetattr(0)
  if enable then
    t.lflag = t.lflag | termio.ICANON
  else
    t.lflag = t.lflag & (~termio.ICANON)
  end
  termio.tcsetattr(0, termio.TCSANOW, t)
end

function wait_for_input()
  return poll.rpoll(0, 50) > 0
end

function clear_line()
  io.stdout:write('   \r')
  io.stdout:flush()
end

function print_state_header()
  print("\nenabled | num peers | quantum | start stop sync | tempo   | beats   | metro")
end

function print_state()
  link:capture_app_session_state(session_state)

  local time = link:clock_micros()
  local enabled = link:is_enabled() and "yes" or "no"
  local num_peers = link:num_peers()
  local start_stop = link:is_start_stop_sync_enabled() and "yes" or " no"
  local tempo = session_state:tempo()
  local playing = session_state:is_playing() and "[playing]" or "[stopped]"
  local beats = session_state:beat_at_time(time, quantum)
  local phase = session_state:phase_at_time(time, quantum)

  local bts = ''
  for i = 0, math.ceil(quantum) do
    bts = bts .. (i < phase and 'X' or 'O')
  end

  io.stdout:write(string.format(
    "%7s | %9d | %7.f | %3s %11s | %7.2f | %7.2f | %s",
    enabled, num_peers, quantum, start_stop, playing, tempo, beats, bts
  ))
end

function input()
  char = io.read(1)

  local time = link:clock_micros()
  local enabled = link:is_enabled()
  local start_stop = link:is_start_stop_sync_enabled()
  local tempo = session_state:tempo()

  link:capture_app_session_state(session_state)

  if char == 'q' then
    running = false
    clear_line()
  elseif char == 'a' then
    link:enable(not enabled)
  elseif char == 'w' then
    session_state:set_tempo(tempo - 1, time)
  elseif char == 'e' then
    session_state:set_tempo(tempo + 1, time)
  elseif char == 'r' then
    quantum = quantum - 1
  elseif char == 't' then
    quantum = quantum + 1
  elseif char == 's' then
    link:enable_start_stop_sync(not start_stop)
  elseif char == ' ' then
    if session_state:is_playing() then
      session_state:set_is_playing(false, time)
    else
      session_state:set_is_playing_and_request_beat_at_time(true, time, 0, quantum)
    end
  end

  link:commit_app_session_state(session_state)
end

link = al.create(120)
session_state = al.create_session_state()
running = true
quantum = 4

print_help()
print_state_header()
set_buffered_input(false)

while running do
  clear_line()
  if wait_for_input() then
    input()
  else
    print_state()
  end
end
set_buffered_input(true)
