#!/bin/bash
#
# mopi - configuration tool for http://pi.gate.ac.uk/mopi
#
# Author: Hamish Cunningham <hamish@gate.ac.uk>
# This code is copyright Hamish Cunningham and the University of Sheffield
# and is licenced under GPL 3 or any later version.
#
# Ideas and idioms borrowed from
# https://github.com/asb/raspi-config/blob/master/raspi-config
# (thanks Alex & co!)

# standard locals
P="$0"
USAGE="`basename ${P}` [-h(elp)] [-d(ebug)] [-v(ersion)] [-l(og entries)]"
OPTIONSTRING=hdvl
alias cd='builtin cd'
DBG=:

# specific locals
DNAME=simbamond
CONFIG=
INST_DIR=`dirname ${P}`
CLI=${INST_DIR}/mopicli
LOG_STRING=simbamon

# message & exit if exit num present
usage() { echo -e Usage: $USAGE; [ ! -z "$1" ] && exit $1; }

# needs to be run as root
if [ $(id -u) -ne 0 ]
then
  echo "${P} must be run as root; try 'sudo mopi'?"
  usage 1
fi

# load current config
if [ -r ${INST_DIR}/${DNAME}.default ]  # development mode
then
  CONFIG=${INST_DIR}/${DNAME}.default
elif [ -r /etc/default/$DNAME ]
then
  CONFIG=/etc/default/$DNAME
else
  echo "${P}: cannot find ${DNAME} config" >&2
  usage 2
fi
source $CONFIG

# get recent log entries
do_log_grep() { grep -i $LOG_STRING /var/log/syslog |tail -${WT_HEIGHT}; }

# process options
while getopts $OPTIONSTRING OPTION
do
  case $OPTION in
    h)	usage 0 ;;
    v)	echo $P is at version $VERSION; exit 0 ;;
    d)	DBG=echo; CLI=echo ;;
    l)  do_log_grep; exit 0 ;;
    *)	usage 3 ;;
  esac
done 
shift `expr $OPTIND - 1`

# does mopicli work?
${CLI} -s >/dev/null || {
  COUT=`${CLI} -s 2>&1`
  echo "${P}: ${CLI} not working; installation problem? (${COUT})" >&2
  usage 4
}

# does bc work?
echo 1 |bc >/dev/null || {
  echo "${P}: bc not working; installation problem?" >&2
  usage 5
}

# figure out optimal size for whiptail
calc_wt_size() {
  WT_HEIGHT=24
  WT_WIDTH=$(tput cols)

  if [ -z "$WT_WIDTH" ] || [ "$WT_WIDTH" -lt 60 ]; then
    WT_WIDTH=80
  fi
  if [ "$WT_WIDTH" -gt 178 ]; then
    WT_WIDTH=120
  fi
  WT_MENU_HEIGHT=$(($WT_HEIGHT-6))
}
calc_wt_size

# menu actions etc.
do_about() {
  whiptail --title "About" --msgbox "\
    This is a configuration tool for MoPi
    (mobile and 24/7 power for the Raspberry Pi).

    Version ${VERSION}.

    See http://pi.gate.ac.uk/mopi for details.\
    " $WT_HEIGHT $(( $WT_WIDTH / 2 )) $WT_MENU_HEIGHT
}
do_supply_config() {
  # process options
  SETTING=both
  case $1 in
    -b) SETTING="both supplies"; S_FLAG=wc; ;;
    -1) SETTING="supply 1"; S_FLAG=wc1; ;;
    -2) SETTING="supply 2"; S_FLAG=wc2; ;;
  esac

  # what type of supply?
  BACKTITLE="Configuring MoPi power supplies (${SETTING})..."
  TITLE='Specify Supply Type'
  C="whiptail --title \"${TITLE}\" --backtitle \"${BACKTITLE}\" \
       --radiolist \"Specify type (for ${SETTING}):\" \
       $WT_HEIGHT $(( $WT_WIDTH / 2 + 9 )) $WT_MENU_HEIGHT \
       --cancel-button \"Cancel\" --ok-button \"Next\" \
       "${SUPPLY_TYPE_A[@]}" "
  SUPPLY_TYPE=`bash -c "${C} 3>&1 1>&2 2>&3"`
  RET=$?
  [ $RET -eq 1 ] && return 0
  [ $RET -eq 0 ] && \
    [ $SUPPLY_TYPE -ge 1 -a $SUPPLY_TYPE -le `supply_type_max` ] || {
       whiptail --msgbox "Error: unrecognized option ${SUPPLY_TYPE}" \
         --title "Oops!" --backtitle "${BACKTITLE}" \
         $WT_HEIGHT $(( $WT_WIDTH / 2 )) $WT_MENU_HEIGHT
       return 1
    }

  # get number of cells
  TITLE='Specify Number of Cells'
  C="whiptail --title \"${TITLE}\" --backtitle \"${BACKTITLE}\" \
       --radiolist \"Specify number of cells (for ${SETTING}):\" \
       $WT_HEIGHT $(( $WT_WIDTH / 2 + 9 )) $WT_MENU_HEIGHT \
       --cancel-button \"Cancel\" --ok-button \"Next\" \
       "${NUM_CELLS_A[@]}" "
  NUM_CELLS=`bash -c "${C} 3>&1 1>&2 2>&3"`
  RET=$?
  [ $RET -eq 1 ] && return 0
  [ $RET -eq 0 ] && \
    [ $NUM_CELLS -ge 1 -a $NUM_CELLS -le `num_cells_max` ] || {
      whiptail --msgbox "Error: unrecognized option ${NUM_CELLS}" \
        --title "Oops!" --backtitle "${BACKTITLE}" \
        $WT_HEIGHT $(( $WT_WIDTH / 2 )) $WT_MENU_HEIGHT
      return 1
    }

  # get chemistry
  TITLE='Specify Battery Chemistry'
  C="whiptail --title \"${TITLE}\" --backtitle \"${BACKTITLE}\" \
       --radiolist \"Specify battery chemistry (for ${SETTING}):\" \
       $WT_HEIGHT $(( $WT_WIDTH / 2 + 9 )) $WT_MENU_HEIGHT \
       --cancel-button \"Cancel\" --ok-button \"Next\" \
       "${BAT_CHEMISTRY_A[@]}" "
  CHEMISTRY=`bash -c "${C} 3>&1 1>&2 2>&3"`
  RET=$?
  [ $RET -eq 1 ] && return 0
  [ $RET -eq 0 ] && \
    [ $CHEMISTRY -ge 1 -a $CHEMISTRY -le `bat_chemistry_max` ] || {
      whiptail --msgbox "Error: unrecognized option ${CHEMISTRY}" \
        --title "Oops!" --backtitle "${BACKTITLE}" \
        $WT_HEIGHT $(( $WT_WIDTH / 2 )) $WT_MENU_HEIGHT
      return 1
    }

  # hokus pokus abracadabra, etc.
  calculate_config $SUPPLY_TYPE $NUM_CELLS $CHEMISTRY

  # validate config
  TITLE="Oops!"
  if [ `echo "$BAT_FULL>$OPERATING_CEILING" |bc` -eq 1 ]
  then
    whiptail --title "${TITLE}" --backtitle "${BACKTITLE}" \
      --msgbox "Configuration error!
The full level (${BAT_FULL}V) is greater than the safe
operating ceiling (${OPERATING_CEILING}V). Please try again!" 20 70 1
    return 0
  elif [ `echo "$BAT_FLOOR>$BAT_GOOD" |bc` -eq 1 ]
  then
    whiptail --title "${TITLE}" --backtitle "${BACKTITLE}" \
      --msgbox "Configuration error!
The discharge floor (${BAT_FLOOR}V) is greater than
the good charge level (${BAT_GOOD}V). Please try again!" 20 70 1
    return 0
  elif [ `echo "$BAT_GOOD<$OPERATING_FLOOR" |bc` -eq 1 ]
  then
    whiptail --title "${TITLE}" --backtitle "${BACKTITLE}" \
      --msgbox "Configuration error!
The good charge level (${BAT_GOOD}V) is less 
than the minimum operating level (${OPERATING_FLOOR}V).
Please try again!" 20 70 1
    return 0
  elif [ `echo "$BAT_GOOD>$BAT_FULL" |bc` -eq 1 ]
  then
    whiptail --title "${TITLE}" --backtitle "${BACKTITLE}" \
      --msgbox "Configuration error!
The good charge level (${BAT_GOOD}V) is greater than
the full level (${BAT_FULL}V). Please try again!" 20 70 1
    return 0
  elif [ `echo "$BAT_FLOOR<$OPERATING_FLOOR" |bc` -eq 1 ]
  then
    TITLE="Warning!"
    whiptail --title "${TITLE}" --backtitle "${BACKTITLE}" \
      --msgbox "Note:
The minimum safe discharge level (${BAT_FLOOR}V) is less 
than the minimum operating level (${OPERATING_FLOOR}V).
Discharge will stop at ${OPERATING_FLOOR}V." 20 70 1
  fi

  # confirm config and offer to write to MoPi
  TITLE="Finalising configuration..."
  whiptail --title "${TITLE}" --backtitle "${BACKTITLE}" --yesno "
The configuration for your supply has been calculated as:

  minimum safe discharge level: ${BAT_FLOOR}V
  low charge level:             ${BAT_LOW}V
  good charge level:            ${BAT_GOOD}V
  full charge level:            ${BAT_FULL}V

Do you want to write this configuration to MoPi?

(Supply type:
   $(supply_type ${SUPPLY_TYPE})
 Number of cells:
   $(num_cells ${NUM_CELLS})
 Chemistry:
   $(bat_chemistry ${CHEMISTRY}))
  " 25 70 1 || {
    whiptail --title "Cancelled" --backtitle "${BACKTITLE}" \
      --msgbox "Configuration cancelled" 20 70 1
    return 0
  }

  # write to mopi (and save locally)
  while :
  do
    F=`v2mv $BAT_FULL`; G=`v2mv $BAT_GOOD`
    L=`v2mv $BAT_LOW`; C=`v2mv $BAT_FLOOR`
    FLAGS="-${S_FLAG} $SUPPLY_TYPE $F $G $L $C"
    COM="${CLI} ${FLAGS}"
    if OUT=`${COM}`
    then
      whiptail --title "Configuration written successfully" \
        --backtitle "${BACKTITLE}" \
        --msgbox "MoPi has been configured :-)\n\n(${COM})" 20 70 1
      save_local_config ${S_FLAG} "$FLAGS"
      break
    else
      whiptail --title "Retry?" --backtitle "${BACKTITLE}" \
        --yesno "Problem writing config -- retry?\n\n(${COM}\n ${OUT})" \
        25 70 1 || {
          whiptail --title ":-(" --backtitle "${BACKTITLE}" \
            --msgbox "Configuration failed" 20 70 1
          break
        }
    fi
  done
}

# main loop
clear
while true; do
  SEL=$(whiptail --title "MoPi Configuration Tool (mopi)" \
    --menu "Configure MoPi" \
      $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT \
    --cancel-button Finish --ok-button Select \
      "1 Configure Both"        "Configure both power supplies" \
      "2 Configure Supply 1"    "Configure supply 1" \
      "3 Configure Supply 2"    "Configure supply 2" \
      "4 Status"                "Show current status from your MoPi board" \
      "5 Show Local Config"     "Show local configuration" \
      "6 Clear Local Config"    "Clear local configuration" \
      "7 Show Log Entries"      "Show the most recent log entries" \
      "8 About MoPi"            "Information about this configuration tool" \
    3>&1 1>&2 2>&3)
  RET=$?
  if [ $RET -eq 1 ]; then
    exit 0
  elif [ $RET -eq 0 ]; then
    case "$SEL" in
      1\ *) do_supply_config -b ;;
      2\ *) do_supply_config -1 ;;
      3\ *) do_supply_config -2 ;;
      4\ *) whiptail --title "MoPi Status" --msgbox \
              "`${CLI} -e |pr -e -t2 -w76 |expand`" $WT_HEIGHT 78 1 ;;
      5\ *) whiptail --title "MoPi Local Config" --msgbox \
              "`get_local_config`" 20 60 1 ;;
      6\ *) whiptail --title "Clear Local Config" --yesno \
              "This will DELETE all local configuration -- are you sure?!" \
              24 70 1 && \
            delete_local_config ;;
      7\ *) whiptail --title "simbamon Log Entries" --msgbox \
              "`do_log_grep`" $WT_HEIGHT $WT_WIDTH 1 ;;
      8\ *) do_about ;;
      *)    whiptail --msgbox "Error: unrecognized option" 20 60 1 ;;
    esac || whiptail --msgbox "There was an error running option $SEL" 20 60 1
  else
    exit 5
  fi
done
