;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; console rendering and various helpers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define con-cmd-history make-vector())
(define con-cmd-line-ofs -1)
(define con-cmd-line-last "")
(define con-cmd-line "")

define sdl-render-console(line-skip height scr-w scr-h)
  define con-width max(1 {scr-w div 8})
  define cidx -1
  define clen con-buffer-length()
  define sv #nil
  ;;
  define prev-line()
    cond
      {{null? sv} or {zero? vector-length(sv)}}
        inc! cidx
        if {cidx >= clen}
          #nil
          else
            {sv := con-buffer-string(cidx con-width)}
            prev-line()
      else
        vector-pop! sv
  ;;
  constant line-height 10
  define ypos {{height + 1} * line-height}
  define chi 0
  lgfx:set-draw-color sdl:rgb(255 255 255)
  lgfx:draw-rect 0 ypos scr-w 2
  lgfx:set-draw-color sdl:rgb(0 0 0)
  lgfx:fill-rect 0 0 scr-w ypos
  dec! ypos line-height
  ;;
  define cxstr con-cmd-line
  if {string-length(cxstr) >= {con-width - 1}}
    {cxstr := substring(cxstr {string-length(cxstr) - con-width - -2})}
  sdl-print-char 0 ypos #\> sdl:rgb(255 255 255)
  sdl-print-str 8 ypos cxstr sdl:rgb(0 200 0)
  define cur-hi {{ticks-msec() mod 1200} >= 600}
  lgfx:set-draw-color (if cur-hi sdl:rgb(0 255 0) sdl:rgb(255 255 255))
  lgfx:fill-rect {{string-length(cxstr) + 1} * 8} ypos 8 9
  lgfx:set-draw-color sdl:rgb(0 0 0)
  ;;
  while {positive? line-skip}
    prev-line()
    dec! line-skip
  ;;
  define str
  while {positive? height}
    dec! ypos line-height
    {str := prev-line()}
    ;debug-printf "::: %o\n" str
    if {string? str}
      sdl-print-str 0 ypos str (if (odd? chi) sdl:rgb(255 255 0) sdl:rgb(200 200 0))
    inc! chi
    dec! height

define con-cmd-push(str)
  if {not {empty-string? str}}
    then
      define idx 0
      while {{idx <> vector-length(con-cmd-history)} and
             {con-cmd-history[idx] <> str}}
        inc! idx
      cond
        {idx <> vector-length(con-cmd-history)}
          inc! idx
          while {idx <> vector-length(con-cmd-history)}
            {con-cmd-history[{idx - 1}] := con-cmd-history[idx]}
            inc! idx
          vector-pop! con-cmd-history
        {vector-length(con-cmd-history) = 64}
          {idx := 1}
          while {idx <> vector-length(con-cmd-history)}
            {con-cmd-history[{idx - 1}] := con-cmd-history[idx]}
            inc! idx
          vector-pop! con-cmd-history
        else
          #void
      vector-push! con-cmd-history str
  gset! con-cmd-line-ofs -1
  gset! con-cmd-line-last ""
  gset! con-cmd-line ""
  str

define con-cmd-put-char(ch)
  define do-console-autocompletion()
    define cpl concmd:collect-completions(con-cmd-line)
    cond
      {string? cpl}
        gset! con-cmd-line cpl
      else
        assert {string? car(cpl)} "oops!"
        assert {vector? cdr(cpl)} "oops!"
        gset! con-cmd-line car(cpl)
        let vloop <* idx 0 \\ vec cdr(cpl) *>
          if {idx <> vector-length(vec)}
            then
              if {zero? idx}
                printf "=== COMPLETIONS ===\n"
              printf " %s\n" vec[idx]
              vloop {idx + 1} vec
  ;;
  cond
    {{ch = 1} and {not empty-string?(con-cmd-line)}}
      gset! con-cmd-line-ofs -1
      gset! con-cmd-line substring(con-cmd-line 0 {string-length(con-cmd-line) - 1})
      gset! con-cmd-line-last con-cmd-line
    {{ch = 8} and {not empty-string?(con-cmd-line)}}
      gset! con-cmd-line-ofs -1
      gset! con-cmd-line substring(con-cmd-line 0 {string-length(con-cmd-line) - 1})
      gset! con-cmd-line-last con-cmd-line
    {ch = 9}
      do-console-autocompletion()
      gset! con-cmd-line-ofs -1
      gset! con-cmd-line-last con-cmd-line
    between?(ch 32 126)
      gset! con-cmd-line-ofs -1
      gset! con-cmd-line string-append(con-cmd-line ch)
      gset! con-cmd-line-last con-cmd-line
    else
      #void

define con-cmd-prev()
  gset! con-cmd-line-ofs {con-cmd-line-ofs + 1}
  if {con-cmd-line-ofs >= vector-length(con-cmd-history)}
    gset! con-cmd-line-ofs {con-cmd-line-ofs - 1}
    else
      if {zero? con-cmd-line-ofs}
        gset! con-cmd-line-last con-cmd-line
      gset! con-cmd-line con-cmd-history[{vector-length(con-cmd-history) - con-cmd-line-ofs - 1}]

define con-cmd-next()
  cond
    {con-cmd-line-ofs > 0}
      gset! con-cmd-line-ofs {con-cmd-line-ofs - 1}
      gset! con-cmd-line con-cmd-history[{vector-length(con-cmd-history) - con-cmd-line-ofs - 1}]
    {zero? con-cmd-line-ofs}
      gset! con-cmd-line-ofs -1
      gset! con-cmd-line con-cmd-line-last
    else
      #void
