#!/bin/sh

# --------------------------------------------------------------
# Konilo - Wrapper Script
# --------------------------------------------------------------
#
# This serves several roles:
#
# - obtaining a working VM, rom, and block store
# - updating an installed system
# - launching Konilo
#
# Supported Systems
#
# +------------+---------------------------------------------+
# | CPU Family | Host                                        |
# +============+=============================================+
# | amd64      | FreeBSD, Haiku, NetBSD, OpenBSD, Linux      |
# | x86        | FreeBSD, Linux                              |
# | aarch64    | Linux                                       |
# | arm64      | Darwin (macOS)                              |
# +------------+---------------------------------------------+
#
# Dependencies:
#
# - Supported host
# - Standard shell (ksh, bash, etc)
# - curl
# - gunzip
#
# Optional:
#
# - C compiler (`cc`)
# - Nim compiler (`nim`)
# - Go compiler (`go`)
# - Rust compiler (`rustc`)
# - Swift compiler (`swiftc`)
# - stty
# - readline
# - rlwrap
#
# Quick Start:
#
#   # install
#   doas cp konilo.sh /usr/local/bin/konilo
#   konilo install
#
#   # run
#   konilo
#
#   # update
#   konilo update
# --------------------------------------------------------------

# --------------------------------------------------------------
# Installation (Common)
# --------------------------------------------------------------

if [ "$1" = "install:common" ]; then
  echo "  -> create ~/.konilo"
  mkdir -p ~/.konilo/
  cd ~/.konilo || exit
  rm -f ilo.rom ilo.blocks

  echo "  -> fetch ilo.rom"
  curl --silent -o - http://ilo.retroforth.org/ilo.rom.gz | gunzip > ilo.rom

  echo "  -> fetch ilo.blocks"
  curl --silent -o - http://ilo.retroforth.org/ilo.blocks.gz | gunzip > ilo.blocks

  echo "  -> fetch tab completion data (for use with rlwrap)"
  curl --silent http://ilo.retroforth.org/retroforth.words.txt -o retroforth.words.txt

  exit
fi


# --------------------------------------------------------------
# Installation (Binary)
# --------------------------------------------------------------

if [ "$1" = "install" ]; then
  echo "** Konilo Installation (using precompiled ilo)"

  sh "$0" install:common
  cd ~/.konilo || exit

  # Detect host system to decide what VM to get

  H=$(uname | tr '[:upper:]' '[:lower:]')
  M=$(uname -m | tr '[:upper:]' '[:lower:]')

  # The output of "uname -m" is not standard; normalize some
  # variations I've seen.

  M=$(echo $M | sed 's/x86_64/amd64/')
  M=$(echo $M | sed 's/i386/x86/')
  M=$(echo $M | sed 's/i686/x86/')
  M=$(echo $M | sed 's/i86pc/x86/')
  M=$(echo $M | sed 's/sun4u/sparc/')

  V="ilo-$M-$H"

  echo "  -> fetch $V"
  curl --silent http://ilo.retroforth.org/binaries/"$V" -o ilo
  chmod +x ilo

  echo "** Installation complete. Run $0 to start."
  exit
fi


# --------------------------------------------------------------
# Installation (from source)
# --------------------------------------------------------------

if [ "$1" = "install:c" ]; then
  echo "** Konilo Installation (ilo.c)"

  sh "$0" install:common
  cd ~/.konilo || exit
  echo "  -> fetch ilo.c"
  curl --silent http://ilo.retroforth.org/ilo.c -o ilo.c
  echo "  -> compile ilo"
  cc -O2 -s ilo.c -o ilo

  echo "** Installation complete. Run $0 to start."
  exit
fi


if [ "$1" = "install:nim" ]; then
  echo "** Konilo Installation (ilo.nim)"

  sh "$0" install:common
  cd ~/.konilo || exit
  echo "  -> fetch ilo.nim"
  curl --silent http://ilo.retroforth.org/ilo.nim -o ilo.nim
  echo "  -> compile ilo"
  nim c -d:release ilo.nim

  echo "** Installation complete. Run $0 to start."
  exit
fi

if [ "$1" = "install:rust" ]; then
  echo "** Konilo Installation (ilo.rs)"

  sh "$0" install:common
  cd ~/.konilo || exit
  echo "  -> fetch ilo.rs"
  curl --silent http://ilo.retroforth.org/ilo.rs -o ilo.rs
  echo "  -> compile ilo"
  rustc ilo.rs -o ilo

  echo "** Installation complete. Run $0 to start."
  exit
fi

if [ "$1" = "install:go" ]; then
  echo "** Konilo Installation (ilo.go)"

  sh "$0" install:common
  cd ~/.konilo || exit
  echo "  -> fetch ilo.go"
  curl --silent http://ilo.retroforth.org/ilo.go -o ilo.go
  echo "  -> compile ilo"
  go build ilo.go
  strip ilo

  echo "** Installation complete. Run $0 to start."
  exit
fi

if [ "$1" = "install:swift" ]; then
  echo "** Konilo Installation (ilo.swift)"

  sh "$0" install:common
  cd ~/.konilo || exit
  echo "  -> fetch ilo.swift"
  curl --silent http://ilo.retroforth.org/ilo.swift -o ilo.swift
  echo "  -> compile ilo"
  swiftc -O ilo.swift

  echo "** Installation complete. Run $0 to start."
  exit
fi


# --------------------------------------------------------------
# Updating
# --------------------------------------------------------------

if [ "$1" = "update" ]; then
  echo "** Konilo Update"

  if [ -e ~/.konilo ]; then
    echo "** switch to ~/.konilo"
    cd ~/.konilo || exit

    echo "  -> fetch latest ilo.rom"
    rm -f ilo.rom
    curl --silent -o - http://ilo.retroforth.org/ilo.rom.gz | gunzip > ilo.rom

    echo "  -> fetch latest system blocks"
    curl --silent -o - http://ilo.retroforth.org/system.blocks.gz | gunzip > system.blocks

    echo "  -> merge system blocks into ilo.blocks"
    dd if=system.blocks of=ilo.blocks bs=4k count=125 seek=3 conv=notrunc

    echo "  -> fetch latest tab completion data (for use with rlwrap)"
    rm -f retroforth.words.txt
    curl --silent http://ilo.retroforth.org/retroforth.words.txt -o retroforth.words.txt

    echo "  -> cleanup"
    rm system.blocks
  else
    echo "** ERROR: Konilo not found in ~/.konilo"
    echo "**"
    echo "** Try running '$0 install'"
  fi
  exit
fi

# --------------------------------------------------------------
# Remove
# --------------------------------------------------------------

if [ "$1" = "uninstall" ]; then
  cd ~ || exit
  rm -rfi .konilo
  exit
fi

# --------------------------------------------------------------
# Backup
# --------------------------------------------------------------

if [ "$1" = "backup" ]; then
  cd ~/.konilo || exit
  D=$(date '+%Y%m%d-%H%M')
  tar cf $D.tar ilo.rom ilo.blocks
  gzip -9 $D.tar
  exit
fi

if [ "$1" = "cleanup" ]; then
  cd ~/.konilo || exit
  echo "Removing old backups:"
  find ~/.konilo/*.gz -mtime +30 -type f
  find ~/.konilo/*.gz -mtime +30 -type f -delete
  exit
fi

if [ "$1" = "restore" ]; then
  cd ~/.konilo || exit
  D=$(stat -f "%m%t%N" *.gz | sort -rn | head -1 | cut -f2-)
  echo "Restoring from: $D"
  tar xzvf $D
  exit
fi

if [ "$1" = "restore-from" ]; then
  cd ~/.konilo || exit
  echo "Restoring from: $2"
  tar xzvf $2
  exit
fi

if [ "$1" = "list-backups" ]; then
  cd ~/.konilo || exit
  ls -l *.tar.gz
  exit
fi

# --------------------------------------------------------------
# Help
# --------------------------------------------------------------

if [ "$1" = "help" ]; then
  echo "$0 help"
  echo "   Display this help text"
  echo
  echo "$0 install"
  echo "   Install Konilo into ~/.konilo"
  echo "   Requires curl and gunzip to be installed."
  echo
  echo "   Options:"
  echo
  echo "   install:c"
  echo "   As with 'install', but build ilo using the local C"
  echo "   compiler (needs to be runnable as 'cc')"
  echo
  echo "   install:nim"
  echo "   As with 'install', but build ilo using the local nim"
  echo "   compiler (needs to be runnable as 'nim')"
  echo
  echo "   install:rust"
  echo "   As with 'install', but build ilo using the local rust"
  echo "   compiler (needs to be runnable as 'rustc')"
  echo
  echo "   install:go"
  echo "   As with 'install', but build ilo using the local go"
  echo "   compiler (needs to be runnable as 'go')"
  echo
  echo "   install:swift"
  echo "   As with 'install', but build ilo using the local swift"
  echo "   compiler (needs to be runnable as 'swiftc')"
  echo
  echo "$0 uninstall"
  echo "   Uninstall Konilo by deleting ~/.konilo"
  echo
  echo "$0 update"
  echo "   Update the Konilo image & system blocks"
  echo
  echo "$0 backup"
  echo "   Make a backup of ilo.rom and ilo.blocks"
  echo
  echo "$0 restore"
  echo "   Restore from the the latest backup"
  echo
  echo "$0 restore-from filename"
  echo "   Restore from a specific backup"
  echo
  echo "$0 cleanup"
  echo "   Remove backups older than 30 days"
  echo
  echo "$0 list-backups"
  echo "   Display a list of backups"
  echo
  echo "$0"
  echo "   Start Konilo"
  echo
  echo "   Options:"
  echo
  echo "   --cbreak"
  echo "     Run in character breaking mode. This will process"
  echo "     input as you press space."
  echo
  echo "   --rlwrap"
  echo "     Run Konilo under rlwrap. This will provide"
  echo "     line editing, history, and tab completion."
  echo "     Requires readline and rlwrap to be installed."
  exit
fi

# --------------------------------------------------------------
# Launching Konilo
# --------------------------------------------------------------

if [ "$1" = "--cbreak" ]; then
  stty cbreak
fi

if [ -e ~/.konilo ]; then
  cd ~/.konilo || exit
  if [ "$1" = "--rlwrap" ]; then
    rlwrap -b " \n" -f retroforth.words.txt ./ilo
  else
    ./ilo
  fi
else
  echo "** ERROR: Konilo not found in ~/.konilo"
  echo "**"
  echo "** Try running '$0 install' or '$0 help'"
fi

if [ "$1" = "--cbreak" ]; then
  stty -cbreak
fi