# Renders a text based list of options that can be selected by the
# user using up, down and enter keys and returns the chosen option.
#
#   Arguments   : list of options, maximum of 256
#                 "opt1" "opt2" ...
#   Return value: selected index (0 for opt1, 1 for opt2 ...)

. ./@Core/Scripts/templates.sh

function select_option {
  # little helpers for terminal print control and key input
  ESC=$( printf "\033")
  cursor_blink_on()  { printf "$ESC[?25h"; }
  cursor_blink_off() { printf "$ESC[?25l"; }
  cursor_to()        { printf "$ESC[$1;${2:-1}H"; }
  print_option()     { printf "   $1 "; }
  print_selected()   { printf " ${GREEN}> $1${NC}"; }
  get_cursor_row()   { IFS=';' read -sdR -p $'\E[6n' ROW COL; echo ${ROW#*[}; }
  key_input()        { read -s -n3 key 2>/dev/null >&2
                        if [[ $key = $ESC[A ]]; then echo up;    fi
                        if [[ $key = $ESC[B ]]; then echo down;  fi
                        if [[ $key = ""     ]]; then echo enter; fi; }

  # initially print empty new lines (scroll down if at bottom of screen)
  for opt; do printf "\n"; done

  # determine current screen position for overwriting the options
  local lastrow=`get_cursor_row`
  local startrow=$(($lastrow - $#))

  # ensure cursor and input echoing back on upon a ctrl+c during read -s
  trap "cursor_blink_on; stty echo; printf '\n'; exit" 2
  cursor_blink_off

  local selected=0
  while true; do
    # print options by overwriting the last lines
    local idx=0
    for opt; do
      cursor_to $(($startrow + $idx))
      if [ $idx -eq $selected ]; then
          print_selected "$opt"
      else
          print_option "$opt"
      fi
      ((idx++))
    done

    # user key control
    case `key_input` in
      enter) break;;
      up)    ((selected--));
              if [ $selected -lt 0 ]; then selected=$(($# - 1)); fi;;
      down)  ((selected++));
              if [ $selected -ge $# ]; then selected=0; fi;;
    esac
  done

  # cursor position back to normal
  cursor_to $lastrow
  printf "\n"
  cursor_blink_on

  return $selected
}

# Clears the entire current line regardless of terminal size.
# See the magic by running:
# { sleep 1; clear_this_line ; }&
clear_this_line(){
  printf '\r'
  cols="$(tput cols)"
  for i in $(seq "$cols"); do
    printf ' '
  done
  printf '\r'
}

# Erases the amount of lines specified.
# Usage: erase_lines [AMOUNT]
# See the magic by running:
# { sleep 1; erase_lines 2; }&
erase_lines(){
  # Default line count to 1.
  test -z "$1" && lines="1" || lines="$1"

  # This is what we use to move the cursor to previous lines.
  UP='\033[1A'

  # Exit if erase count is zero.
  [ "$lines" = 0 ] && return

  # Erase.
  if [ "$lines" = 1 ]; then
          clear_this_line
  else
    lines=$((lines-1))
    clear_this_line
    for i in $(seq "$lines"); do
            printf "$UP"
            clear_this_line
    done
  fi
}