# Wrappers around interaction primitives that take a potentially fake object
# and are thus easier to test.

exclusive-container event [
  text:character
  keycode:number  # keys on keyboard without a unicode representation
  touch:touch-event  # mouse, track ball, etc.
  resize:resize-event
  # update the assume-console handler if you add more variants
]

container touch-event [
  type:number
  row:number
  column:number
]

container resize-event [
  width:number
  height:number
]

container console [
  index:number
  data:address:array:event
]

recipe new-fake-console [
  local-scope
  result:address:console <- new console:type
  buf:address:address:array:event <- get-address *result, data:offset
  *buf <- next-ingredient
  idx:address:number <- get-address *result, index:offset
  *idx <- copy 0
  reply result
]

recipe read-event [
  local-scope
  x:address:console <- next-ingredient
  {
    break-unless x
    idx:address:number <- get-address *x, index:offset
    buf:address:array:event <- get *x, data:offset
    {
      max:number <- length *buf
      done?:boolean <- greater-or-equal *idx, max
      break-unless done?
      dummy:address:event <- new event:type
      reply *dummy, x/same-as-ingredient:0, 1/found, 1/quit
    }
    result:event <- index *buf, *idx
    *idx <- add *idx, 1
    reply result, x/same-as-ingredient:0, 1/found, 0/quit
  }
  switch  # real event source is infrequent; avoid polling it too much
  result:event, found?:boolean <- check-for-interaction
  reply result, x/same-as-ingredient:0, found?, 0/quit
]

# variant of read-event for just keyboard events. Discards everything that
# isn't unicode, so no arrow keys, page-up/page-down, etc. But you still get
# newlines, tabs, ctrl-d..
recipe read-key [
  local-scope
  console:address:console <- next-ingredient
  x:event, console, found?:boolean, quit?:boolean <- read-event console
  reply-if quit?, 0, console/same-as-ingredient:0, found?, quit?
  reply-unless found?, 0, console/same-as-ingredient:0, found?, quit?
  c:address:character <- maybe-convert x, text:variant
  reply-unless c, 0, console/same-as-ingredient:0, 0/found, 0/quit
  reply *c, console/same-as-ingredient:0, 1/found, 0/quit
]

recipe send-keys-to-channel [
  local-scope
  console:address:console <- next-ingredient
  chan:address:channel <- next-ingredient
  screen:address:screen <- next-ingredient
  {
    c:character, console, found?:boolean, quit?:boolean <- read-key console
    loop-unless found?
    break-if quit?
    assert c, [invalid event, expected text]
    screen <- print-character screen, c
    chan <- write chan, c
    loop
  }
  reply console/same-as-ingredient:0, chan/same-as-ingredient:1, screen/same-as-ingredient:2
]

recipe wait-for-event [
  local-scope
  console:address:console <- next-ingredient
  {
    _, console, found?:boolean <- read-event console
    loop-unless found?
  }
  reply console/same-as-ingredient:0
]

# use this helper to skip rendering if there's lots of other events queued up
recipe has-more-events? [
  local-scope
  console:address:console <- next-ingredient
  {
    break-unless console
    # fake consoles should be plenty fast; never skip
    reply 0/false
  }
  result:boolean <- interactions-left?
  reply result
]