#!@BASH@
# -*- mode: sh; sh-basic-offset: 3; indent-tabs-mode: nil; -*-
# vim: set filetype=sh sw=3 sts=3 expandtab autoindent:

# copyright 2002 lmoore@tump.com under the terms of the GNU LGPL.
# additions 2005 collective@riseup.net

# whiptail has trouble being called in the foo=$(whiptail ...) fashion for
# some reason.  this is very annoying.  this means that we need to use
# temporary files to store the answers from the input and list based boxes
# and then read the answers into a REPLY variable.  that just really
# stinks, oh well, that's what you get when you have a weak link
# implementation...
#
# inputBox and passwordBox could be refactored to use a common function

test -z "$WIDTH" && WIDTH=0
test -z "$HEIGHT" && HEIGHT=0
BACKTITLE=""
DIALOG=dialog
HELP=

setApplicationTitle() {
   BACKTITLE=$*
}

setHelp() {
   HELP="$@"
}

setDimension() {
   WIDTH=$1
   HEIGHT=$2
}

booleanBox() {
   $DIALOG --backtitle "$BACKTITLE" --title "$1" \
      `[ "$3" == no ] && echo '--defaultno'` --yesno "$2" $HEIGHT $WIDTH
}

msgBox() {
   $DIALOG --backtitle "$BACKTITLE" --title "$1" \
      --msgbox "$2" $HEIGHT $WIDTH
}

gaugeBox() {
   $DIALOG --backtitle "$BACKTITLE" --title "$1" \
      --gauge "$2" $HEIGHT $WIDTH 0
}

inputBox() {
   local temp=$(@MKTEMP@ -t backupninja.XXXXXX) || exit 1
   trap "rm -f $temp" 0
   REPLY=
   $DIALOG --backtitle "$BACKTITLE" --title "$1" \
      --inputbox "$2" $HEIGHT $WIDTH "$3" 2> $temp
   local status=$?
   [ $status = 0 ] && REPLY=$(cat $temp)
   rm -f $temp
   return $status
}

# Xdialog and {dialog,whiptail} use different mechanism to "qoute" the
# values from a checklist.  {dialog,whiptail} uses standard double quoting
# while Xdialog uses a "/" as the separator.  the slash is arguably better,
# but the double quoting is more standard.  anyway, this function can be
# overridden to allow a derived implementation to change it's quoting
# mechanism to the standard double-quoting one.  it receives two
# arguements, the file that has the data and the box type.
_listReplyHook() {
   cat $1
}

# this is the base implementation of all the list based boxes, it works
# out nicely that way.  the real function just passes it's arguments to
# this function with an extra argument specifying the actual box that
# needs to be rendered.
_genericListBox() {
   local box=$1
   shift 1
   local title=$1
   local text=$2
   shift 2
   local temp=$(@MKTEMP@ -t backupninja.XXXXXX) || exit 1
   trap "rm -f $temp" 0
   REPLY=
   $DIALOG $HELP $_DEFAULT --backtitle "$BACKTITLE" --title "$title" \
      $box "$text" $HEIGHT $WIDTH 10 \
      "$@" 2> $temp
   local status=$?
   [ $status = 0 ] && REPLY=$(_listReplyHook $temp $box)
   rm -f $temp
   _DEFAULT=
   return $status
}

setDefault() {
   _DEFAULT="--default-item $1"
}

menuBox() {
   _genericListBox --menu "$@"
}

## a menu box with additional help info displayed
## at the bottom of the window when an item is selected
menuBoxHelp() {
   HELP="--item-help"
   _genericListBox --menu "$@"
   status=$?
   HELP=
   return $status
}

## a menu box with an addition button 'help'
menuBoxHelpFile() {
   HELP="--help-button"
   _genericListBox --menu "$@"
   status=$?
   HELP=
   return $status
}

checkBox() {
   _genericListBox --checklist "$@"
}

radioBox() {
   _genericListBox --radiolist "$@"
}

textBox() {
   $DIALOG --backtitle "$BACKTITLE" --title "$1" --textbox "$2" $HEIGHT $WIDTH
}

passwordBox() {
   local temp=$(@MKTEMP@ -t backupninja.XXXXXX) || exit 1
   trap "rm -f $temp" 0
   REPLY=
   $DIALOG --backtitle "$BACKTITLE" --title "$1" \
      --passwordbox "$2" $HEIGHT $WIDTH 2> $temp
   local status=$?
   [ $status = 0 ] && REPLY=$(cat $temp)
   rm -f $temp
   return $status
}


#########################################################
## begin-item-display style lists
##
## these lists are built by calling fuctions multiple times.
## this can make it easier to build your list in a loop
##

listBegin() {
   _menu_title=$1
   _menu_msg=$2
   _menu_items=0
   _menu_text=
   _menu_labels=
   _menu_status=
}

listItem() {
   _menu_labels[$_menu_items]=$1
   _menu_text[$_menu_items]=$2
   _menu_status[$_menu_items]=$3 # available only for checklist
   let "_menu_items += 1"
}


##
## takes one of:
## menu, checklist, radiolist
##
listDisplay() {
   boxtype=$1
   local temp=$(@MKTEMP@ -t backupninja.XXXXXX) || exit 1
   trap "rm -f $temp" 0

   local label
   local text
   local status
   (
      echo -ne " $HELP $_DEFAULT "
      echo -ne " --backtitle '$BACKTITLE' "
      echo -ne " --title '$_menu_title' "
      echo -ne " --$boxtype '$_menu_msg' "
      echo -ne " $HEIGHT $WIDTH 10 "
      for ((i=0; i < $_menu_items ; i++)); do
         label=${_menu_labels[$i]}
         text=${_menu_text[$i]}
         status=${_menu_status[$i]}
         echo -ne " $label '$text' $status "
      done
   ) | xargs $DIALOG 2> $temp

   local status=$?
   REPLY=""
   [ $status = 0 ] && REPLY=`cat $temp`
   rm -f $temp
   _DEFAULT=
   return $status
}

####################################################
## FORM

_form_gap=2
formBegin() {
   _form_title=$1
   _form_items=0
   _form_labels=
   _form_text=
}

formItem() {
   _form_labels[$_form_items]=$1
   _form_text[$_form_items]=$2
   let "_form_items += 1"
}

formDisplay() {
   local temp=$(@MKTEMP@ -t backupninja.XXXXXX) || exit 1

   max_length=0
   for ((i=0; i < ${#_form_labels[@]} ; i++)); do
      label=${_form_labels[$i]}
      length=`expr length $label`
      if [ $length -gt $max_length ]; then
         max_length=$length
      fi
   done
   let "max_length += 2"

   local xpos=1
   (
      echo -n -e "--form '$_form_title' 0 0 20"
      for ((i=0; i < $_form_items ; i++)); do
         label=${_form_labels[$i]}
         text=${_form_text[$i]}
         echo -n -e " $label $xpos 1 '$text' $xpos $max_length 30 100"
         let "xpos += _form_gap"
      done
   ) | xargs $DIALOG 2> $temp
   local status=$?

   ##
   ## the exit status is meaningless, it is always 0.
   ## i can't figure out how to get the exit status of dialog
   ## if we do "dialog `arg code`" or "dialog $args", then the quotes
   ## get messed up and dialog won't run.
   ## if we do "(arg code) | xargs dialog", then the exit status is
   ## swallowed by xargs. xargs should return different exit status
   ## depending on the exit status of the command run, but i have
   ## never been able to get that to work.
   ##

   REPLY=
   if [ $status = 0 ]; then
      IFS=$''
      REPLY=`cat $temp`
      IFS=$' \t\n'
   fi
   rm -f $temp
   return $status
}
