#!/bin/ash
# sourced by /init
#
# requires: wait_for_usb() get_part_info() check_status()
#           decode_id()
#           ensure_mounted()

#===================================================================
#                      init-bootmenu_funcs
#===================================================================

TOP_LEFT_CORNER='╔'
TOP_RIGHT_CORNER='╗'
BOTTOM_LEFT_CORNER='╚'
BOTTOM_RIGHT_CORNER='╝'
HORIZONTAL_LINE='═'
VERTICAL_LINE='║'
MENU_COLOR=`echo -en '\033[97;44m'` # blue bg color bright white fg
KEY_UP=`echo -en '\033[A'`
KEY_DOWN=`echo -en '\033[B'`
KEY_ESC=`echo -en '\033\033'`

decode_entry() {
 Z_PDEV1=""
 Z_PDRV=""
 Z_PFIX=""
 Z_PIMOD=""
 Z_PMEDIA=""
 Z_PSAVE=""
 Z_PSAVEMARK=""
 Z_PSUBDIR=""
 Z_PUPSFS=""
 Z_UNDERDOG=""
 Z_ZDRV=""
 Z_FDRV=""
 Z_ADRV=""
 Z_YDRV=""
 Z_SEARCH_DIR=""
 Z_SEARCH_DRIVE=""
 Z_DISTRO_SPECS=""
 #CHOSEN_ENTRY="LABEL raspup|PMEDIA usbflash|"
 while read FIELD VALUE
 do
  [ -z "$FIELD" ] && continue #empty line
  #echo "'$FIELD' = '$VALUE'"
  case "$FIELD" in
   LABEL)  continue ;; #ignore LABEL
   PDEV1)  Z_PDEV1=${VALUE}  ;;
   PDRV)   Z_PDRV=${VALUE}   ;;
   PFIX)   Z_PFIX=${VALUE}   ;;
   PIMOD)  Z_PIMOD=${VALUE}  ;;
   PMEDIA) Z_PMEDIA=${VALUE} ;;
   PSAVE)  Z_PSAVE=${VALUE}  ;;
   PSAVEMARK) Z_PSAVEMARK=${VALUE} ;;
   PSUBDIR)   Z_PSUBDIR=${VALUE}   ;;
   PUPSFS)    Z_PUPSFS=${VALUE}    ;;
   UNDERDOG)  Z_UNDERDOG=${VALUE}  ;;
   ZDRV) Z_ZDRV=${VALUE} ;;
   FDRV) Z_FDRV=${VALUE} ;;
   ADRV) Z_ADRV=${VALUE} ;;
   YDRV) Z_YDRV=${VALUE} ;;
   SEARCH_DIR)   Z_SEARCH_DIR=${VALUE}   ;;
   SEARCH_DRIVE) Z_SEARCH_DRIVE=${VALUE} ;;
   DISTRO_SPECS) Z_DISTRO_SPECS=${VALUE} ;;
   *) echo "Ignoring unknown keyword: $ENTRY_PART" ;;
  esac
 done <<EOF
$(echo "$CHOSEN_ENTRY" | tr '|' '\n')
EOF
}

draw_screen() {
 echo -en '\033[s' # save cursor position

 echo -en '\033[2J' # clear screen
 echo -en "\033[${MENU_ROW_START};${MENU_COLUMN_START}H" # goto menu start
 CURRENT_ROW=${MENU_ROW_START}
 CURRENT_COLUMN=${MENU_COLUMN_START}

 echo -n "$MENU_COLOR"
 echo -n "$TOP_LEFT_CORNER"
 let MENU_COLUMN_END=MENU_COLUMN_START+MAX_LABEL_WIDTH+2
 while [ "$CURRENT_COLUMN" -lt "$MENU_COLUMN_END" ]
 do
  echo -n "$HORIZONTAL_LINE"
  let CURRENT_COLUMN++
 done
 echo "$TOP_RIGHT_CORNER"

 echo -en "\033[${MENU_COLUMN_START}G" # move to MENU_COLUMN_START
 CURRENT_COLUMN=${MENU_COLUMN_START}

 CURRENT_ENTRY_NR=0
 while read ONE_ENTRY #$ALL_ENTRIES
 do
  [ -z "$ONE_ENTRY" ] && continue

  let CURRENT_ENTRY_NR++

  if [ "${ONE_ENTRY#LABEL}" != "$ONE_ENTRY" ]; then
   ECHO_STRING=${ONE_ENTRY%%|*}
   ECHO_STRING=${ECHO_STRING:6}
  else
   ECHO_STRING=${ONE_ENTRY%%|*}
  fi

  echo -n "$VERTICAL_LINE"
  if [ "$CURRENT_ENTRY_NR" = "$CHOSEN_ENTRY_NR" ]; then
   CHOSEN_ENTRY=${ONE_ENTRY}
   echo -ne '\033[7m' # reverse video
  fi
  echo -n " $ECHO_STRING"
  let CURRENT_COLUMN=CURRENT_COLUMN+${#ECHO_STRING}+1
  while [ "$CURRENT_COLUMN" -lt "$MENU_COLUMN_END" ]
  do
   echo -n " "
   let CURRENT_COLUMN++
  done
  [ "$CURRENT_ENTRY_NR" = "$CHOSEN_ENTRY_NR" ] && echo -ne '\033[27m' # reset reverse video
  echo "$VERTICAL_LINE"

  echo -en "\033[${MENU_COLUMN_START}G" # move to MENU_COLUMN_START
  CURRENT_COLUMN=${MENU_COLUMN_START}
 done <<EOF
$(echo "${ALL_ENTRIES}")
EOF

 echo -n "$BOTTOM_LEFT_CORNER"
 let MENU_COLUMN_END=MENU_COLUMN_START+MAX_LABEL_WIDTH+2
 while [ "$CURRENT_COLUMN" -lt "$MENU_COLUMN_END" ]
 do
  echo -n "$HORIZONTAL_LINE"
  let CURRENT_COLUMN++
 done
 echo "$BOTTOM_RIGHT_CORNER"
 echo -en '\033[0m' # reset color

 if [ "$TIMEOUT" -ge 10 ]; then
  echo -en "\033[${MENU_COLUMN_START}G" # move to MENU_COLUMN_START
  echo -n "Booting in ${TIMEOUT%[[:digit:]]} seconds..."
 fi

 echo -en '\033[u' # restore cursor position
 echo -en '\033[10D' # backup cursor position
}

exec_init() {
 [ "$Z_PDEV1" ]     && export pdev1=$Z_PDEV1
 [ "$Z_PDRV" ]      && export pdrv=$Z_PDRV
 [ "$Z_PFIX" ]      && export pfix=$Z_PFIX
 [ "$Z_PIMOD" ]     && export pimod=$Z_PIMOD
 [ "$Z_PMEDIA" ]    && export pmedia=$Z_PMEDIA
 [ "$Z_PSAVE" ]     && export psave=$Z_PSAVE
 [ "$Z_PSAVEMARK" ] && export psavemark=$Z_PSAVEMARK
 [ "$Z_PSUBDIR" ]   && export psubdir=$Z_PSUBDIR
 [ "$Z_PUPSFS" ]    && export pupsfs=$Z_PUPSFS
 [ "$Z_UNDERDOG" ]  && export underdog=$Z_UNDERDOG
 [ "$Z_ZDRV" ]      && export zdrv=$Z_ZDRV
 [ "$Z_FDRV" ]      && export fdrv=$Z_FDRV
 [ "$Z_ADRV" ]      && export adrv=$Z_ADRV
 [ "$Z_YDRV" ]      && export ydrv=$Z_YDRV
 clear
}

show_menu() {
 let MENU_ROW_START=ROWS-ENTRY_COUNT
 let MENU_ROW_START=MENU_ROW_START/2
 #echo "MENU_ROW_START = $MENU_ROW_START"

 let MENU_COLUMN_START=COLUMNS-MAX_LABEL_WIDTH
 let MENU_COLUMN_START=MENU_COLUMN_START/2
 #echo "MENU_COLUMN_START = $MENU_COLUMN_START"

 [ -z "$CHOSEN_ENTRY_NR" ] && CHOSEN_ENTRY_NR=1
 [ -z "$TIMEOUT" ] && TIMEOUT=0

 while true
 do
  draw_screen

  local TEMP_INPUT=""
  local INPUT=""
  while true
  do
   if [ "$TIMEOUT" -eq 0 ]; then
    read -n1 INPUT
   else
    while true
    do
     read -n1 -t 1 INPUT
     [ "$?" -eq 0 ] && TIMEOUT=0 && break
     if [ "$TIMEOUT" -gt 10 ]; then
      let TIMEOUT=TIMEOUT-10
      draw_screen
     else
      TIMEOUT=0
      break
     fi
    done
   fi
   [ "$INPUT" = "" ] && break

   TEMP_INPUT=${TEMP_INPUT}${INPUT}
   [ "${#TEMP_INPUT}" -gt 3 ] && TEMP_INPUT=${TEMP_INPUT:1}

   # Because arrow key codes start with the ESC charactor, ESC must be pressed
   # twice to exit menu.  KEY_ESC = '\033\033', two ESC chars in a row.
   [ "${TEMP_INPUT}" = "$KEY_ESC" ] && INPUT="" && CHOSEN_ENTRY="" && break
   [ "${TEMP_INPUT:1}" = "$KEY_ESC" ] && INPUT="" && CHOSEN_ENTRY="" && break

   [ "$TEMP_INPUT" = "$KEY_UP"  -a "$CHOSEN_ENTRY_NR" -gt 1 ] && let CHOSEN_ENTRY_NR-- && draw_screen
   [ "$TEMP_INPUT" = "$KEY_DOWN"  -a "$CHOSEN_ENTRY_NR" -lt "$ENTRY_COUNT" ] && let CHOSEN_ENTRY_NR++ && draw_screen

  done
  [ "$INPUT" = "" ] && break
 done
}

#===================================================================
#                        init-bootmenu
#===================================================================

search_bootmenu(){
 for ONETRY in $HAVE_PARTS;do
  ONE_PART="$(echo -n "$ONETRY" | cut -f 1 -d '|')"
  ensure_mounted "$ONE_PART" "/mnt/pdrv"
  if [ "$ONE_MP" ];then
   if [ -f /mnt/pdrv/boot/bootmenu.txt ]; then
    cp /mnt/pdrv/boot/bootmenu.txt /tmp/bootmenu.txt
   elif [ -f /mnt/pdrv/bootmenu.txt ]; then
    cp /mnt/pdrv/bootmenu.txt /tmp/bootmenu.txt
   fi
   umount $ONE_MP
   [ -f /tmp/bootmenu.txt ] && break
  fi
 done
}

wait_for_usb

search_bootmenu
[ -f /tmp/bootmenu.txt ] || echo -n > /tmp/bootmenu.txt

while true
do
 # ALL_ENTRIES format:
 # LABEL text|KEYWORD text|KEYWORD text|etc...
 ALL_ENTRIES=""
 NEW_ENTRY=""
 ENTRY_COUNT=0
 MAX_LABEL_WIDTH=0

 while read FIELD VALUE
 do
  case "$FIELD" in
   "")   continue ;; # empty line
   "#"*) continue ;; # ignore any comments
   DEFAULT) DEFAULT=${VALUE} ; continue ;;
   TIMEOUT) TIMEOUT=${VALUE} ; continue ;;
   LABEL)
    LABEL_TEXT=${VALUE//\"/}
    [ "${#LABEL_TEXT}" -gt "$MAX_LABEL_WIDTH" ] && MAX_LABEL_WIDTH=${#LABEL_TEXT}
    # save previous entry
    if [ -n "$NEW_ENTRY" ]; then
     ALL_ENTRIES="$ALL_ENTRIES
$NEW_ENTRY"
    fi
    NEW_ENTRY="LABEL ${LABEL_TEXT}|"
    let ENTRY_COUNT++
    [ "$LABEL_TEXT" = "$DEFAULT" ] && CHOSEN_ENTRY_NR=$ENTRY_COUNT
   ;;

   *) NEW_ENTRY="${NEW_ENTRY}${FIELD} ${VALUE}|" ;;
  esac
 done < /tmp/bootmenu.txt

 # save last entry
 ALL_ENTRIES="$ALL_ENTRIES
$NEW_ENTRY"
 #echo "$ALL_ENTRIES"
 #echo "ENTRY_COUNT = $ENTRY_COUNT"
 #echo "MAX_LABEL_WIDTH = $MAX_LABEL_WIDTH"

 if [ "$ENTRY_COUNT" -eq 0 ]; then
  exec_init
  break
 fi

 if [ "$ENTRY_COUNT" -eq 1 ]; then
  CHOSEN_ENTRY=${NEW_ENTRY}
 else
  #echo "$ENTRY_COUNT is more than 1"
  ROWS=`stty -a | grep -o "rows .[^;]"`
  ROWS=${ROWS#rows }
  #echo "ROWS = '$ROWS'"
  COLUMNS=`stty -a | grep -o "columns .[^;]"`
  COLUMNS=${COLUMNS#columns }
  #bugfix - busybox stty returns a two digit number
  [ "$COLUMNS" -lt 40 ] && let COLUMNS=COLUMNS*10
  #echo "COLUMNS = '$COLUMNS'"

  show_menu
  #echo "CHOSEN_ENTRY = $CHOSEN_ENTRY"
 fi

 if [ -n "$CHOSEN_ENTRY" ]; then
  decode_entry
  # need to decode_entry before testing SEARCH_DIR and SEARCH_DRIVE
  if [ -z "$SEARCH_DIR" -a -z "$SEARCH_DRIVE" ]; then
   if [ -n "$DISTRO_SPECS" ]; then
   #echo "DISTRO_SPECS = $DISTRO_SPECS"
    ensure_mounted "${DISTRO_SPECS%%:*}" "/mnt/pdrv"
    if [ "$ONE_MP" ];then
      [ -f "/mnt/pdrv/${DISTRO_SPECS#*:}" ] && cp -f /mnt/pdrv/${DISTRO_SPECS#*:} ./DISTRO_SPECS
     umount $ONE_MP
    fi
   fi
   exec_init
   break
  fi
 else
  SEARCH_DIR=""
  SEARCH_DRIVE=""
 fi

 while [ -n "$SEARCH_DIR" -o -n "$SEARCH_DRIVE" ]
 do
  # SEARCH_DRIVE=any and SEARCH_DRIVE=all will be ignored by decode_id.
  if [ -n "$SEARCH_DRIVE" ]; then
   decode_id $SEARCH_DRIVE
   [ -z "$ONE_PART" -a "$SEARCH_DRIVE" != "any" -a "$SEARCH_DRIVE" != "all" ] && ONE_PART="not found"
  else
   ONE_PART=""
  fi

  SDIR=/mnt/pdrv/${SEARCH_DIR#/} # remove any leading '/' before appending
  ALL_ENTRIES=""
  ENTRY_COUNT=0
  MAX_LABEL_WIDTH=0
  CHOSEN_ENTRY_NR=1
  MAXDEPTH=3
  [ -n "$SEARCH_DIR" ] && MAXDEPTH=1

  if [ -n "$DISTRO_SPECS" ]; then
  #echo "DISTRO_SPECS = $DISTRO_SPECS"
   ensure_mounted "${DISTRO_SPECS%%:*}" "/mnt/pdrv"
   if [ "$ONE_MP" ];then
     [ -f "/mnt/pdrv/${DISTRO_SPECS#*:}" ] && cp -f /mnt/pdrv/${DISTRO_SPECS#*:} ./DISTRO_SPECS
    umount $ONE_MP
   fi
  fi
  [ -f ./DISTRO_SPECS ] && . ./DISTRO_SPECS

  for ONETRY in $HAVE_PARTS;do
   ONE_HAVE_PART="$(echo -n "$ONETRY" | cut -f 1 -d '|')"
   [ -n "$ONE_PART" -a "$ONE_HAVE_PART" != "$ONE_PART" ] && continue
   ensure_mounted "$ONE_HAVE_PART" "/mnt/pdrv"
   #echo "ONE_HAVE_PART = $ONE_HAVE_PART"
   if [ "$ONE_MP" ];then
    while read ONE_SAVE ; do
      NEW_ENTRY="PSAVE ${ONE_HAVE_PART}:${ONE_SAVE#/mnt/pdrv}"
      [ "${#NEW_ENTRY}" -gt "$MAX_LABEL_WIDTH" ] && MAX_LABEL_WIDTH=${#NEW_ENTRY}
      ALL_ENTRIES="$ALL_ENTRIES
$NEW_ENTRY"
      let ENTRY_COUNT++
    done <<EOF
$(find "$SDIR" -maxdepth $MAXDEPTH -iname "${DISTRO_FILE_PREFIX}save*" -type d -o -iname "${DISTRO_FILE_PREFIX}save*.[2-4]fs" -type f)
EOF
    while read ONE_SFS ; do
      NEW_ENTRY="PUPSFS ${ONE_HAVE_PART}:${ONE_SFS#/mnt/pdrv}"
      [ "${#NEW_ENTRY}" -gt "$MAX_LABEL_WIDTH" ] && MAX_LABEL_WIDTH=${#NEW_ENTRY}
      ALL_ENTRIES="$ALL_ENTRIES
$NEW_ENTRY"
      let ENTRY_COUNT++
    done <<EOF
$(find "$SDIR" -maxdepth $MAXDEPTH -iname 'puppy_*.sfs' -type f)
EOF
    while read ONE_DISTRO_SPECS ; do
      NEW_ENTRY_TEXT="DISTRO_SPECS ${ONE_HAVE_PART}:${ONE_DISTRO_SPECS#/mnt/pdrv}"
      NEW_ENTRY="${NEW_ENTRY_TEXT}|SEARCH_DIR ${SEARCH_DIR}|SEARCH_DRIVE ${SEARCH_DRIVE}|"
      [ "${#NEW_ENTRY_TEXT}" -gt "$MAX_LABEL_WIDTH" ] && MAX_LABEL_WIDTH=${#NEW_ENTRY_TEXT}
      ALL_ENTRIES="$ALL_ENTRIES
$NEW_ENTRY"
      let ENTRY_COUNT++
    done <<EOF
$(find "$SDIR" -maxdepth $MAXDEPTH -iname 'DISTRO_SPECS' -type f)
EOF
    umount $ONE_MP
   fi
  done

  if [ "$ENTRY_COUNT" -gt 0 ]; then
   show_menu
  else
   ALL_ENTRIES="Found nothing. :-("
   MAX_LABEL_WIDTH=18
   draw_screen
   CHOSEN_ENTRY=""
   sleep 3
  fi

  if [ -n "$CHOSEN_ENTRY" ]; then
   # need to decode_entry after checking if there is one
   decode_entry
   if [ -z "$DISTRO_SPECS" ]; then
    exec_init
    break 2
   fi
  else
   SEARCH_DIR=""
   SEARCH_DRIVE=""
  fi

 done

done
