#!/bin/bash

# /usr/sbin/lessdisks-install
# install script for lessdisks, with easydialog frontend

# copyright 2004 vagrant@freegeek.org, distributed under the terms of the
# GNU General Public License version 2 or any later version.

# TODO generate the /etc/lessdisks/server.config file
# or as much as we can get...

# TODO make firstMenu pretty

# TODO get rid of easydialog?

# process commandline arguments
for ARGUMENT in "$@"
do
  case $1 in
    -a|--arch) newarch="$2"
      echo "setting terminal architechure to $newarch"
      shift ;;
    -c|--configfile) LESSDISKS_CONFIG="$2"
      echo "setting configuration file to $LESSDISKS_CONFIG"
      shift ;;
    -d|--dialog) DIALOG="$2"
      echo "setting dialog to $DIALOG"
      shift ;;
    --skip|--skip-menus) echo -e "skipping menu configuration,\
        proceeding with default values"
      BEGIN_INSTALL="yes";;
    --logfile|-l) logfile="$2"
      echo "setting log file to $logfile"
      shift ;;
    -h|--help) echo -e "lessdisks-install [options] [blah blah]\n\
        -c, --configfile  configuration file, normally /etc/lessdisks-install.conf\n\
        -l , --logfile  log file, normally /var/log/lessdisks-install.log\n\"
        -d, --dialog  set dialog type: whiptail, dialog, Xdialog, cmdline\n\
        --skip, --skip-menus  skip menu configuration and proceed with defaults\n\
        -h, --help  show these help options"
      exit 0;;
  esac
  shift
done

showValues() {
  egrep '^[[:space:]]*[a-zA-Z].*=' $1
}

# if configuration file not specified set default
if [ "" = "$LESSDISKS_CONFIG" ]
then
  LESSDISKS_CONFIG="/etc/lessdisks-install.conf"
fi

if [ ! -e "$LESSDISKS_CONFIG" ]
then
  # can't use exitbox yet.
  echo -e "configuration file for lessdisks\n\
    not found!\n\
    exiting..."
  exit 1
fi

# get default values from config file...
. $LESSDISKS_CONFIG

if [ -z "$logfile" ]; then
  logfile="/var/log/lessdisks-install.log"
  echo "setting logfile to $logfile"
  logmessage="maybe check the logfile, $logfile"
fi
touch $logfile

# TODO test for existance of easydialog?

PATH="/usr/local/lib/easydialog:/usr/share/easydialog:/usr/lib/easydialog:$PATH" . easydialog.sh

# dialog's size detection seems broken... so lets set a few stupid
# defaults
if [ "$DIALOG" = "dialog" ] ; then
  if [ -z "$LINES" ]; then
    LINES=20
  fi
  if [ -z "$COLUMNS" ]; then
    COLUMNS=70
  fi
  setDimension $((COLUMNS-10)) $(($LINES-5))
fi

firstMenu() {
menuBox "lessdisks install menu" \
  "please select an option" \
  1 "Begin Installation" \
  2 "Display Values" \
  3 "Simple Configuration" \
  4 "Advanced Configuration" \
  5 "Exit, Quit, etc.."

case $REPLY in
  1) BEGIN_INSTALL="yes" ;;
  2) showValues $LESSDISKS_CONFIG ;;
  3) dpkg-reconfigure --priority=medium lessdisks
  # get default values from config file, in case they changed.
  . $LESSDISKS_CONFIG ;;
  4) dpkg-reconfigure --priority=low lessdisks
  # get default values from config file, in case they changed.
  . $LESSDISKS_CONFIG ;;
  5) exit 15 ;;
  *) echo "urk! something went wrong..."
  exit 20 ;;
esac
if [ "yes" != "$BEGIN_INSTALL" ]; then
  echo
  echo "hit enter to continue"
  read pause
fi
}

exitBox() { 
  if [ "" = "$1" ]; then 
    msgBox "exiting" "exiting..."
  else
    msgBox "exiting" "$@" 
  fi 
  exit 1 
}

while [ "yes" != "$BEGIN_INSTALL" ]; do
  firstMenu
done

# if defined, export 
if [ -n "$http_proxy" ]; then
  HTTP_PROXY="$http_proxy"
  export HTTP_PROXY http_proxy
fi

#### debootstrap configuration

debootstrapvalid="no"
while [ "no" = "$debootstrapvalid" ]; do
  if [ -x $debootstrap ]; then
    echo " "
    echo "debootstrap is where we expect it, we can continue as planned"
    echo " "
    debootstrapvalid="yes"
  else
    inputBox "debootstrap missing" \
    "debootstrap not found, or is not executable\n\
    where is a valid path to an executable debootstrap?"
    debootstrap="$REPLY"
    if [ "1" = "$?" ]; then
      exitBox
    fi
    debootstrapvalid="no"
  fi
done

if [ "" = "$newarch" ]; then
  msgBox "determining architecture" \
  "debootstrap will attempt to automatically determine\n\
  the machine architecture automatically\n\
  if the wrong architecture is detected, such as\n\
  i386-none, edit $LESSDISKS_CONFIG to\n\
  specify the arch manually or specify it on command\n\
  line:\n\n\
  lessdisks-install <arch>\n\n\
  some valid arch values- i386, powerpc, m68k, sparc"
else
  echo "setting terminal architecture to $newarch"
  debootstrap_opts="$debootstrap_opts --arch $newarch "
fi

# TODO support other methods...
# someday we might support methods other than web, but for now just go with it.
method="web"

TestArchive() {
#### get information about archive location

if [ "web" = "$method" ]; then
  if [ "" = "$archive" ]; then
    echo "setting archive to default: $defaultarchive"
    archive="$defaultarchive"
  fi
  archive=`echo $archive | awk -F "http://" '{print $1 $2}'`
else
  while [ "" = "$archive" ]; do
    validarchive="no"
    while [ "no" = "$validarchive" ]; do
      inputBox "location of archive" \
        "where the $method mounted?\n\
        it must already be mounted,\n\
        and must begin with a /"
      archive="$REPLY"

      # test to see if base archive is a valid path
      if [ -d "$archive/dists/$debian_dist" ]; then
        echo " "
        echo "using archive $archive"
        echo " "
        validarchive="yes"
      else
        # TODO attempt to mount archive
        msgBox "archive invalid" \
        "$archive invalid, please\n\
        specify valid path to archive\n\
        \n\
        perhaps it needs to be mounted?"
        validarchive="no"
      fi
    done
  done
fi
}

debootstrap_error_check() {
  egrep "^E:" $logfile
}

getPercent() {
  filename="$logfile"
  sleep_time=2
  percent=0
  number_packages="$1"
  base_number_sections=4
  number_sections="$base_number_sections"
  while [ "$percent" -lt "100" ]; do
    number_lines=$(egrep "Validating|Checking|Extracting|^Selecting|^Setting up" $filename | wc -l)
    if [ "$base_number_sections" = "$number_sections" ]; then
      if [ -n "$(egrep Checking $filename)" ]; then
        number_sections=$(($number_sections+1))
      fi
    fi
    # approximate a percentage by:
    # number of lines containing search term(Validating, Extracting, Selecting...), 
    # divided by $number_sections search terms, 
    # multiplied by 110 (fudge factor since Extracting is not done for all packages),
    # divided by the number of packages.

    percent=$(($number_lines/$number_sections*109/$number_packages))
    if [ "99" -lt "$percent" ]; then
      # stay at 99%
      percent=99
    fi
    steps=$(awk '/^I:/{print $2}' $filename | sort -u)
    number_steps=$(echo $steps | wc -w)
    # TODO break when a trigger file exists
    if [ -n "$(echo $steps | egrep Base)" ]; then
      # if we hit the "Base system installed" line, we're 100%
      echo 100
      break
    elif [ -n "$(debootstrap_error_check)" ]; then
      # Error detected... stop the progress bar
      break
    fi
    echo $percent
    sleep $sleep_time
  done
}


gaugeBox() {
  $DIALOG --gauge "Installing Debian base system" $(($HEIGHT/2)) $(($WIDTH)) 0
}

getPackageList() {
  package_list=""
  list_type="$1"
  for package in $2; do
    if [ -z "$package_list" ]; then
      package_list="--$list_type=$package"
    else
      package_list="$package_list,$package"
    fi
  done
  echo $package_list
}

DebootstrapInstall() {
  #### begin the download process

  if [ "web" = "$method" ]; then
    archive="http://$archive"
  else
    archive="file:$archive"
  fi
  excludes=$(getPackageList exclude "$exclude_packages")
  includes=$(getPackageList include "$include_packages")
  if [ -n "$DEBIAN_FRONTEND" ]; then
    export DEBIAN_FRONTEND=$DEBIAN_FRONTEND
  fi
  if [ -n "$DEBIAN_PRIORITY" ]; then
    export DEBIAN_PRIORITY=$DEBIAN_PRIORITY
  fi
  debootstrap_opts="$debootstrap_opts $includes $excludes $debian_dist $lessdisks_path $archive $dbs_script"

  downloadok="1"
  while [ "0" != "$downloadok" ]; do
  echo "proceeding with installation... (this will also check for missing or incomplete files again)"
    if [ -z "$logfile" ]; then
      $debootstrap $debootstrap_opts
      downloadok="$?"
    elif [ -w "$logfile" ]; then
      echo "this may take a long long time...."
      echo "switch to another console and tail -f $logfile if you get bored"
      mv -f $logfile $logfile.old
      echo "beginning debootstrap install..." >> $logfile
      date >> $logfile
      number_packages=$($debootstrap --print-debs $debootstrap_opts | wc -w)
      # TODO it's a little too fragile backgrounding this...
      getPercent $number_packages | gaugeBox &
      $debootstrap $debootstrap_opts >> $logfile 2>&1
      # give a little time for the progress bar to catch up
      downloadok="$?"
      sleep 5
    fi
    if [ "0" != "$downloadok" ]
    then
        error_message=$(debootstrap_error_check)
        sleep 3 
        reset
        echo "Base system failed to install..."
        echo
        if [ -n "$error_message" ]; then
          echo "possible error messages:"
          echo
          echo "$error_message"
          echo
        fi
        echo "hit enter to continue"
        read
        booleanBox "verify download" "download appears to\
           have failed, would you like to try again? $logmessage"
        if [ "$?" != "0" ]
        then
          exitBox
        fi
    fi
  done
}

CheckInstalled () {
  # checks to see if installed already, and changes
  # behavior if so.
  for somefile in etc/hostname etc/hosts usr/bin/awk bin/bash usr/bin/dpkg
  do
    if [ -e $lessdisks_path/$somefile ]
    then
      update="yes"
    fi
  done
  if [ "yes" = "$update" ]
  then
    echo "it seems like you've got an existing lessdisks install..."
    echo "setting to update mode..."
  fi
}

AptSources () {
# TODO include more intelligent generation of sources.list stuff

# slightly more intelligent generation of sources.list...
sources_list="$lessdisks_path/etc/apt/sources.list"
if [ -e "$sources_list" ]
then
  mv $sources_list $sources_list.old
fi

echo "generating $sources_list"
if [ -n "$lessdisksarchive" ]; then
  # only include lessdisks archive if it is set.
  echo "deb http://$lessdisksarchive" >> $sources_list
fi
echo "deb http://$defaultarchive $debian_dist main" >> $sources_list
if [ -n "$archive_nonus" ]; then
  echo "deb http://$archive_nonus $debian_dist/non-US main" >> $sources_list
fi
if [ -n "$archive_security" ]; then
  echo "deb http://$archive_security $debian_dist/updates main" >> $sources_list
fi

# needed for proper hostname resolution
echo "copying resolv.conf file"
cp /etc/resolv.conf $lessdisks_path/etc/resolv.conf
# useful if nameserver is installed
echo "nameserver 127.0.0.1" >> $lessdisks_path/etc/resolv.conf
}

updateExistingInstall() {
  AptSources
  lessdisks-aptget -f install
  lessdisks-aptget update
  lessdisks-aptget -y dist-upgrade
  updateok="$?"
  if [ "0" != "$updateok" ]
  then
    booleanBox "update failed" "update appears to\
      have failed, would you like to \
      try a regular install?"
    if [ "$?" = "0" ]
    then
      tar cvzpf $lessdisks_path/lessdisks_backup.tgz \
        $lessdisks_path/etc/lessdisks/*
      if [ -d "$lessdisks_path" ]
      then
        cd $lessdisks_path
        if [ "$?" = "0" ]
        then
          # remove the whole lessdisks filesystem
           # except var, lessdisks_backup.tgz, lost+found
          rm -rvf $(ls | egrep -v "lessdisks_backup.tgz|var|lost+found")
          cd -
          mkdir -p $lessdisks_path/etc/lessdisks/
          DebootstrapInstall
          AptSources
        else
          exitBox "couldn't cd to $lessdisks_path... update failed..."
        fi
      else
        exitBox "couldn't cd to $lessdisks_path... update failed..."
      fi
    else
      exitBox
    fi
  fi
}

TestArchive

CheckInstalled

if [ "yes" = "$update" ]
then
  updateExistingInstall
else
  DebootstrapInstall
  AptSources
fi

# redirect configuration directory appropriately
ln -s $lessdisks_path/etc/lessdisks /etc/
cd $lessdisks_path
echo "ok to install lessdisks-base" > etc/ok-to-install

# TODO cleaner way to handle this?
# server.config values have been incorporated into lessdisks-install.conf
# just need to migrate them over, like so....

mkdir -p $lessdisks_path/etc/lessdisks/
egrep -A 99 "### begin lessdisks server.config ###" $LESSDISKS_CONFIG | \
  egrep -B 99 "### end lessdisks server.config ###" > \
    $lessdisks_path/etc/lessdisks/server.config

########## stage2 install

# populate kernel-img.conf file
echo "image_in_boot = Yes" >> $lessdisks_path/etc/kernel-img.conf
echo "do_symlinks = Yes" >> $lessdisks_path/etc/kernel-img.conf
echo "relative_links = Yes" >> $lessdisks_path/etc/kernel-img.conf
echo "do_initrd = Yes" >> $lessdisks_path/etc/kernel-img.conf
echo "do_bootloader = No" >> $lessdisks_path/etc/kernel-img.conf
echo "do_bootifloppy = No" >> $lessdisks_path/etc/kernel-img.conf

# in case gid is not present, make it so...
if [ ! -e "$lessdisks_path/etc/lessdisks/gid" ]; then
  awk -F : '/^lessdisks:/{print $3}' /etc/group >> $lessdisks_path/etc/lessdisks/gid
fi

# TODO are the variables available in server.config already available?
. /etc/lessdisks/server.config

# update lists of available packages
lessdisks-aptget update

if [ "0" != "$?" ]
then
  sleep 5
  lessdisks-aptget update
  if [ "0" != "$?" ]
  then
    echo "apt-get update failed, exiting..." 
    exit 1
  fi 
fi

OLD_DEBIAN_FRONTEND=$DEBIAN_FRONTEND
if [ -n "$lessdisks_frontend" ]; then
  # temporarily use this frontend...
  export DEBIAN_FRONTEND=$lessdisks_frontend
fi

# upgrade to newest packages
lessdisks-aptget -y dist-upgrade

# add mknbi to packages to be installed
if [ "yes" = "$use_mknbi" ] || [ "true" = "$use_mknbi" ]; then
  packages="$packages mknbi"
fi

case $export_type in
  none|"") echo "no export type configured" ;;
  khttpd) echo "using khttpd for export type..." ;;
  thy|thttpd) packages="$packages $export_type" ;;
  *) echo "uknown export type, $export_type, you'll have to install it manually"
    echo "perhaps \"lessdisks-aptget install $export_type\"" ;;
esac

install_packages(){
  for p in $@ ; do
    status=""
    lessdisks-aptget -y install $p
    status="$?"
    if [ "0" != "$status" ]; then
      echo "WARNING: package $p failed to install.  will try again later..."
      failed_packages="$p $failed_packages"
      sleep 3
    fi
  done
}

# download-only first to assure packages download properly
lessdisks-aptget -yd install lessdisks-terminal $packages $kernel_packages
install_packages lessdisks-terminal
# set default values for symlinked files...
# (ssmtp breaks on installs without fully qualified domain names otherwise)
mkdir -p $lessdisks_path/var/state/lessdisks/etc/
echo "127.0.0.1 $disk_server" > $lessdisks_path/var/state/lessdisks/etc/hosts
echo "$disk_server" > $lessdisks_path/var/state/lessdisks/etc/hostname

if [ -n "$packages" ]; then
  install_packages $packages
fi

unset_initrd_root(){
  mkinitrd_conf="$lessdisks_path/etc/mkinitrd/mkinitrd.conf"
  if [ "$initrd_hack" != "false" ] && [ -e "$mkinitrd_conf" ]; then
    echo "NOTE: using initrd hack, setting ROOT=\"\" in $mkinitrd_conf"
    sed -e 's/ROOT=.*/ROOT=""/g' $mkinitrd_conf > $mkinitrd_conf.new \
      && cp -a --remove-destination $mkinitrd_conf $mkinitrd_conf.old \
      && mv -vf $mkinitrd_conf.new $mkinitrd_conf
  fi
}

if [ -n "$kernel_packages" ]; then
  if [ -e $lessdisks_path/var/cache/apt/archives/initrd-tools* ] ; then
    # FIXME: this is a hackish workaround. figure out why initrd won't build.
    install_packages initrd-tools
    unset_initrd_root
  fi
  install_packages $kernel_packages
fi

# for certain failed packages, attempt resolutions...
for package in $failed_packages ; do
  case $package in
    kernel-image-*) unset_initrd_root
      # try try again...
      install_packages $package 
      # TODO remove package from failed_packages if sucessful?
      ;;
  esac
done

# just in case there are loose ends, attempt to fix broken dependencies
lessdisks-aptget -f install || lessdisks-aptget -f install

# restore DEBIAN_FRONTEND
if [ -z "$OLD_DEBIAN_FRONTEND" ]; then
  unset DEBIAN_FRONTEND
else
  DEBIAN_FRONTEND="$OLD_DEBIAN_FRONTEND"
fi

# TODO move into post-install script: lessdisks-terminal
#chroot $lessdisks_path dpkg-reconfigure lessdisks-terminal
lessdisks-chroot /usr/share/lessdisks/lessdisks-terminal-install

if [ -x $lessdisks_path/var/lib/dpkg/info/lessdisks-xterminal.postinst ]; then
  lessdisks-chroot dpkg-reconfigure lessdisks-xterminal
fi

if [ -n "$failed_packages" ]; then
  echo "NOTE: the following packages or their dependencies"
  echo "  may not have been properly installed:"
  echo "$failed_packages"
  echo
  echo "showing all packages which may not be properly installed:"
  lessdisks-chroot dpkg -l | egrep -v "^ii"
  echo
fi

echo "lessdisks stage2 install finished. hit enter to continue"
read pause

booleanBox "run lessdisks-configure?" "would you like to run\n\
  the lessdisks-configure script?\n\
  lessdisks-configure walks you through a few other\n\
  installation steps, such as setting up NFS, dhcpd, etc..."
if [ "$?" = "0" ] ; then
  lessdisks-configure
fi
