#!/usr/bin/env bash
if [ -f /etc/os-release ]; then
  source /etc/os-release
fi


ARCH=$(uname -m)

###############################################################################
##
## Check if arg2 is in arg1 list
##
###############################################################################
function list_include_item {
  local list="$1"
  local item="$2"
  if [[ $list =~ (^|[[:space:]])"$item"($|[[:space:]]) ]] ; then
    # yes, list include item
    result=0
  else
    result=1
  fi
  return $result
}

###############################################################################
##
## Return alternate arch name
##
###############################################################################
function alt_arch_names()
{
  ARM_ARCHS="armv71 aarch64"

  if `list_include_item "${ARM_ARCHS}" "${ARCH}"`; then
    echo "arm"
  elif [ "${ARCH}" == "x86_64" ]; then
    echo "amd64"
  fi
}

OUTPUT=$(mktemp)
SNAKEOIL_VERSION="1.3.0"
ARTIFACTS_HOME="https://artifacts.snakeoil-os.net"
ARTIFACTS_PATH="artifacts"
ARTIFACTS_CACHE="/media/snakeoil_cache"
LMS_FILE="logitechmediaserver_latest_$(alt_arch_names).deb"

ALREADY_INSTALLED="Already installed"

function error_out() {
  echo " !!!!! ERROR !!!!!"
  echo "$1"
  exit 1
}

###############################################################################
## Verify components
## $1 name
## $2 file
## $3 checksum to verify file again
###############################################################################
function verify_checksum() {
  if [ ! $# -eq 3 ]; then
    echo "# Error calling verify_checksum function: $#"
    quit 1
  fi
  echo -n "    - verifying component: ${1}... "
  if [ -f ${2} ]; then
  CHKSUM=$(sha1sum ${2} | awk '{print $1}')
  fi
  if [ ${CHKSUM} == $3 ]; then
    echo "OK"
  else
    echo "ERROR"
    error_out "Checksum failed"
  fi
}

###############################################################################
##
## Try and identify distro
##
###############################################################################
function identify_distro() {
  DISTRO=$(which lsb_release)
  if [ $? -eq 0 ]; then
    DISTRO=$(lsb_release -i|awk '{print $3}')
  fi

  echo "${DISTRO}"
}


###############################################################################
##
## Version compare
## 0 = Version match
## 1 = $1 is greater than $2
## 2 = $1 is less than $2
##
###############################################################################
vercomp () {
    if [[ $1 == $2 ]]
    then
        return 0
    fi
    local IFS=.
    local i ver1=($1) ver2=($2)
    # fill empty fields in ver1 with zeros
    for ((i=${#ver1[@]}; i<${#ver2[@]}; i++))
    do
        ver1[i]=0
    done
    for ((i=0; i<${#ver1[@]}; i++))
    do
        if [[ -z ${ver2[i]} ]]
        then
            # fill empty fields in ver2 with zeros
            ver2[i]=0
        fi
        if ((10#${ver1[i]} > 10#${ver2[i]}))
        then
            return 1
        fi
        if ((10#${ver1[i]} < 10#${ver2[i]}))
        then
            return 2
        fi
    done
    return 0
}

###############################################################################
##
## Returns true if program is found
##
###############################################################################

function program_exists() {
  echo -n "    * Checking program ($1)... "
  MSGS=$(which $1)
  if [ $? -eq 0 ]; then
    echo "FOUND"
  else
    echo "MISSING. please install $1"
    echo "# Snakeoil installation aborted"
    exit 1
  fi
}

die() { echo "$*" >&2; exit 2; }  # complain to STDERR and exit with error
needs_arg() { if [ -z "$OPTARG" ]; then die "No arg for --$OPT option"; fi; }

APT_UPDATE="yes"
###############################################################################
## Check commandline arguments
###############################################################################
function process_options() {
while getopts hn-: OPT;
do
  # support long options: https://stackoverflow.com/a/28466267/519360
  if [ "$OPT" = "-" ]; then   # long option: reformulate OPT and OPTARG
    OPT="${OPTARG%%=*}"       # extract long option name
    OPTARG="${OPTARG#$OPT}"   # extract long option argument (may be empty)
    OPTARG="${OPTARG#=}"      # if long option argument, remove assigning `=`
  fi

  case "${OPT}" in
    h | help )
       echo -e "Snakeoil Installer ${SNAKEOIL_VERSION}\n"
       echo "[options]"
       echo "          -h | --help: Show this help"
       echo " -n | --no-apt-update: Skip apt update"
       exit 0
       ;;
    n | no-apt-update)
       APT_UPDATE="no";;
   ??*) die "Illegal option --$OPT" ;;  # bad long option
     ?) exit 2 ;;  # bad short option (error reported via getopts)
  esac
done
}

###############################################################################
##
## Check for dependencies
##
## Needs tar, head, tail, xz
###############################################################################
function check_prerequisites() {
  echo "  + Checking pre-requistes..."
  if [ ! -f "/usr/bin/which" ]; then
    echo -e "Error. Install aborted!\n    * Program 'which' is missing. Please install which."
    quit 1
  fi
  if [ "${ARCH}" == "aarch64" ]; then
    NUM_BITS=$(getconf LONG_BIT)
    if [ ${NUM_BITS} == "32" ]; then
      echo "ERROR. 32 bit OS not supported.";
      quit 1
    fi
  fi

  # ip link show|grep UP |grep -v lo:|head -n 1|cut -d: -f2| xargs)
  program_exists ip
  program_exists grep
  program_exists head
  program_exists tail
  program_exists sed
  program_exists base64
  program_exists pgrep
  program_exists sha1sum
  program_exists tar
  program_exists ip
  program_exists cat
  program_exists mktemp
  program_exists cut
  program_exists xargs

  return 0
}


###############################################################################
##
## Copy function
##
###############################################################################
function copy() {
  cp "${@}" -rf
  if [ ${?} -ne 0 ]; then
    echo "Error"
    quit 1
  fi
}

###############################################################################
##
## Copy function (sudo
##
###############################################################################
function sudo_copy() {
  sudo cp "${@}" -rf
  if [ ${?} -ne 0 ]; then
    echo "Error"
    quit 1
  fi
}


###############################################################################
##
## Return 1 if deb is installed, 0 otherwise
## $1: deb file
##
###############################################################################
function is_deb_installed() {
  CHECK=$(sudo dpkg -l "${1}" 2> /dev/null|grep ii)

  if [ -z "${CHECK}" ]; then
    echo "no"
  else
    echo "yes"
  fi
}

###############################################################################
## Check if I need to update DEB
## $1: installed DEB file
## #2: New DEB file
###############################################################################
function is_deb_upgrade() {
  INSTALL=$(dpkg -l|grep logitechmediaserver|awk '{print $3}'|cut -d~ -f1)
  UPGRADE=$(echo $2 |cut -d_ -f2|cut -d~ -f1)

  vercomp ${INSTALL} ${UPGRADE}
  if [ $? -eq 2 ]; then
    echo "yes"
  else
    echo "no"
  fi
}

###############################################################################
##
## install package via apt
##
###############################################################################
function apt_install() {
  echo "    * Checking package: ${1}"
  echo -n -e "      - Status:\r"
  IS_INSTALLED=$(is_deb_installed ${1})

  if [ "${IS_INSTALLED}" == "no" ]; then
    echo -e -n "      - Status: Installing... \r"
    sudo apt-get --assume-yes install $1

    if [ $? -eq 0 ]; then
      rm -f ${OUTPUT}
      echo "      - Status: Installing... OK"
    else
      echo "      - Status: Installing... Failed"
      cat ${OUTPUT}

      rm -f ${OUTPUT}
      quit 1
    fi
  else
    echo "      - Status: ${ALREADY_INSTALLED}"
  fi
}

###############################################################################
## Common apt based packages
###############################################################################
function install_packages_debian() {
  echo -n "    * Updating repos... "
  if [ "${APT_UPDATE}" == "yes" ]; then
    sudo apt update > /dev/null 2> /dev/null
    echo "OK"
  else
    echo "Skipped"
  fi
  # If exist, do not prompt to restart services
  if [ -d /etc/needrestart/conf.d ]; then
    if [ ! -f /etc/needrestart/conf.d/snakeoil.conf ]; then
      echo "\$nrconf{restart} = 'a';" | sudo tee /etc/needrestart/conf.d/snakeoil.conf > /dev/null
    fi
  fi

  apt_install dialog
  apt_install rt-tests
  apt_install curl
  apt_install bzip2
  apt_install net-tools
  apt_install avahi-daemon
  apt_install icewm
  apt_install lighttpd
  apt_install php-cgi
  apt_install tigervnc-standalone-server
  apt_install libio-socket-ssl-perl
  apt_install libgomp1
  apt_install cifs-utils
  apt_install nfs-common
  apt_install samba
  apt_install timidity
  apt_install openssh-server
  apt_install python3-future
  apt_install libcrypt-openssl-bignum-perl
  apt_install libcrypt-openssl-random-perl
  apt_install libcrypt-openssl-rsa-perl

  if [ "${NAME}" == "Ubuntu" ]; then
    apt_install ubuntu-restricted-extras
  fi
}

###############################################################################
## For Raspbian
###############################################################################
function install_packages_raspbian(){
  install_packages_debian

  return 0
}


###############################################################################
## For Ubuntu
###############################################################################
function install_packages_ubuntu() {
  install_packages_debian

  return 0
}


###############################################################################
##
## Nice way of quitting
##
###############################################################################
function quit() {
  if [ -f ${OUTPUT} ]; then
    rm -f ${OUTPUT}
  fi

  if [ ${1} -ne 0 ]; then
    echo "# Install aborted with errors!"
  else
    # Check if snakeoil is already running. If PID exist this is likely
    # to be a pre-installed system
    PID_SNAKEOIL=$(pgrep snakeoil-rest)
    if [ -z "${PID_SNAKEOIL}" ]; then
        echo "# Installation complete. Please reboot your computer now."
    else
      /usr/local/sbin/snakeoil-rest --exit > /dev/null 2> /dev/null
      echo "# Installation complete."
      echo "# Restarting Snakeoil RestAPI server."
      echo "# Please wait at least 1 minute before trying the WebApp"
    fi
  fi

  exit ${1}
}

###############################################################################
##
## Install distro packages
##
###############################################################################
function install_packages() {
  echo -n "  + Checking CPU: "
  SUPPORTED_ARCHS="x86_64 armv71 aarch64"
  if `list_include_item "$SUPPORTED_ARCHS" "$ARCH"`; then
    echo "OK"
  else
    echo "Your CPU is unspported. Supported CPUs: $SUPPORTED_ARCHS";
    quit 1
  fi

  DISTRO=$(identify_distro)
  echo "  + System identified as: ${DISTRO}"

  if [ "${DISTRO}" == "Ubuntu" ]; then
    install_packages_ubuntu
    if [ $? -ne 0 ]; then
      echo ${MSGS}
      quit 1
    fi
  elif [ "${DISTRO}" == "Debian" ]; then
    install_packages_raspbian
    if [ $? -ne 0 ]; then
      echo ${MSGS}
      quit 1
    fi
  else
    echo "  + This distro is not supported yet. Install aborted."
    quit 1
  fi
}

###############################################################################
##
## Download artifact
##
###############################################################################
function download_artifact()
{
  echo -n "  + Download $1... "
  BASE_NAME=$(basename $2)


  if [ ! -f ${ARTIFACTS_CACHE}/${BASE_NAME} ]; then
    curl -f -s ${ARTIFACTS_HOME}${2} -o ${ARTIFACTS_CACHE}/${BASE_NAME}
    if [ $? -ne 0 ]; then
      echo "ERROR. File missing on server (404)."
      quti 1
    fi
    if [ ! -f ${ARTIFACTS_CACHE}/${BASE_NAME} ]; then
      echo "ERROR. Download failed..."
      quit 1
    fi

    echo "OK"
  else
    echo "Already Downloaded."
  fi
}

###############################################################################
##
## Install Snakeoil packages
##
###############################################################################
function install_snakeoil_components() {
  echo -n "  + Creating media folders... "
  sudo mkdir -p /media/music
  sudo mkdir -p /media/playlists
  sudo mkdir -p $ARTIFACTS_CACHE
  sudo chmod 777 /media -R
  sudo chown $(whoami):$(whoami) /media -R
  echo "OK"

  download_artifact "LMS" "/players/lms/${LMS_FILE}"
  download_artifact "Snakeoil RestAPI server" "/${ARTIFACTS_PATH}/snakeoil-rest_${VERSION_CODENAME}_${ARCH}_${SNAKEOIL_VERSION}"
  download_artifact "Snakeoil Blob" "/${ARTIFACTS_PATH}/snakeoil_${VERSION_CODENAME}_${ARCH}_${SNAKEOIL_VERSION}.blob"

  echo -n "  + Install Snakeoil RestAPI server... "
  sudo_copy ${ARTIFACTS_CACHE}/snakeoil-rest_${VERSION_CODENAME}_${ARCH}_${SNAKEOIL_VERSION} \
    "/usr/local/sbin/snakeoil-rest" -f
  sudo chmod 755 /usr/local/sbin/snakeoil-rest
  echo "OK"

  echo -n "  + Installing Snakeoil blob, please be patient... "
  sudo mkdir /var/cache/lighttpd/uploads/ -p
  sudo chown www-data:www-data /var/cache/lighttpd -R
  cp ${ARTIFACTS_CACHE}/snakeoil_${VERSION_CODENAME}_${ARCH}_${SNAKEOIL_VERSION}.blob /tmp
  sudo /usr/local/sbin/snakeoil-rest --recover=/tmp/snakeoil_${VERSION_CODENAME}_${ARCH}_${SNAKEOIL_VERSION}.blob > /tmp/snakeoil-install.log
  if [ $? -eq 0 ]; then
    echo "OK"
  else
    echo "ERROR"
    cat /tmp/snakeoil-install.log
    quit 1
  fi
}


###############################################################################
##
## Install Snakeoil packages
##
###############################################################################
function config_snakeoil() {
  echo "# Prepping Your System For Snakeoil."""
  echo -n "  + Creating Snakeoil startup script... "

  echo -e "#!/bin/bash
  # Last updated: 2020-02-28
  PID=\$(pidof -x \"snakeoil-server.sh\")
  if [ \"\${PID}\" != \"\$\$\" ]; then
    echo \"Snakeoil-server script already running\"
    exit 1
  fi

  snakeoil-rest --exit

  rm /tmp/stderr -f
  rm /tmp/stdout -f

  while true; do
    if [ -f /media/music/snakeoil-rest ]; then
      mv -f /media/music/snakeoil-rest /usr/local/sbin/snakeoil-rest
      chown root:root /usr/local/sbin/snakeoil-rest
      chmod 755 /usr/local/sbin/snakeoil-rest
    fi

    if [ -f /media/music/snakeoil-runme.sh ]; then
      sh /media/music/snakeoil-runme.sh
      if [ $? -eq 0 ]; then
        rm -rf /media/music/snakeoil-runme.sh
      fi
    fi

    HOME=/root/ USER=root /usr/local/sbin/snakeoil-rest 2>> /tmp/stderr >> /tmp/stdout
    sleep 1
  done" | sudo tee /usr/local/bin/snakeoil-server.sh > /dev/null

  sudo chmod 755 /usr/local/bin/snakeoil-server.sh
  echo "OK"

  # Check if /etc/rc.local exist, and remove new_issue and snakeoil if present
  echo -n "  + Remove Snakeoil from rc.local... "

  if [ -f "/etc/rc.local" ]; then
    NEW_ISSUE=$(grep new_issue /etc/rc.local)
    SNAKEOIL_SCRIPT=$(grep snakeoil-server.sh /etc/rc.local)

    if [ -f "/etc/systemd/system/rc-local.service" ] && [ ! -z "${NEW_ISSUE}" ] && [ ! -z "${SNAKEOIL_SCRIPT}" ]; then
      # check if "/etc/systemd/system/rc-local.service" exists, and create if missing
      sudo sed -i -e '\/usr\/local\/bin\/snakeoil-server.sh*/d' \
           -e '/^sleep 5 && \/usr\/local\/bin\/new_issue*/d' \
           -e '/^$/d' /etc/rc.local
      echo "OK"
      echo -n "  + Disable rc.local... "
      MSGS=$(sudo systemctl disable rc-local > /dev/null 2> /dev/null)
      echo "Removed"
    else
      echo "Not present"
    fi
  else
    echo "No rc.local file"
  fi

  echo -n "  + Install Snakeoil systemd service... "
    SERVICE_FILE="[payload removed: 300 characters]"
    echo $SERVICE_FILE | base64 -d | sudo tee /etc/systemd/system/snakeoil-rest.service > /dev/null
    sudo systemctl daemon-reload > /dev/null 2> /dev/null
    sudo systemctl enable snakeoil-rest > /dev/null 2> /dev/null
  echo "OK"

  echo -n "  + Web server... "
  MSGS=$(sudo sed -i /etc/lighttpd/lighttpd.conf -e "s/^\(server\.document-root.*=.*\).*/server\.document-root        = \"\/var\/www\/\"/g")
  sudo lighttpd-enable-mod fastcgi > /dev/null 2> /dev/null
  sudo lighttpd-enable-mod fastcgi-php 2> /dev/null > /dev/null
  sudo lighttpd-enable-mod proxy   > /dev/null 2> /dev/null
  sudo lighttpd-enable-mod rewrite > /dev/null 2> /dev/null
  API_PORT=$(grep 30511 /etc/lighttpd/lighttpd.conf)
  if [ -z "${API_PORT}" ]; then
    echo -e "\nproxy.server = (\n  \"/api\" => ( (\n    \"host\" => \"127.0.0.1\",\n    \"port\" => 30511\n  ) )\n )\n" | \
      sudo tee -a /etc/lighttpd/lighttpd.conf > /dev/null
  fi
  REWRITE=$(grep rewrite\-if\-not\-file /etc/lighttpd/lighttpd.conf)

  if [ -z "${REWRITE}" ]; then
    echo -e "\nurl.rewrite-if-not-file = ( \"(?!\\.\\w+\$)\" => \"/index.html\" )\n" | sudo tee -a /etc/lighttpd/lighttpd.conf > /dev/null
  fi

  sudo systemctl restart lighttpd
  if [ $? -eq 0 ]; then
    echo "OK"
  else
    echo "ERROR"
    error_out "Cannot restart Lighttpd server"
  fi

  ## LMS
  echo -n "  + Logitech Media Server... "
  IS_INSTALLED=$(is_deb_installed logitechmediaserver)
  NEEDS_UPGRADE=$(is_deb_upgrade "logitechmediaserver" "${LMS}")

  if [ "${IS_INSTALLED}" == "no" ] || [ "${NEEDS_UPGRADE}" == "yes" ]; then
    sudo dpkg -i ${ARTIFACTS_CACHE}/${LMS_FILE}

    if [ $? -ne 0 ]; then
      echo "ERROR"
      cat ${OUTPUT}
      error_out "Cannot install LMS"
    else
      MSGS=$(sudo systemctl stop logitechmediaserver > ${OUTPUT} 2>> ${OUTPUT})
      echo "OK"
    fi

    echo [payload removed: 9276 characters] \
      | base64 -d | sudo tee /var/lib/squeezeboxserver/prefs/server.prefs > /dev/null
    sudo chown squeezeboxserver:nogroup /var/lib/squeezeboxserver/prefs/server.prefs
  else
    echo "${ALREADY_INSTALLED}"
  fi

  echo -n "  + Disable LMS auto start... "
  MSGS=$(sudo systemctl disable logitechmediaserver > ${OUTPUT} 2>> ${OUTPUT})
  echo "OK"

  ## Check network
  echo -n "  + Configuring network... "
  INTERFACE=$(ip link show|grep UP |grep -v lo:|head -n 1|cut -d: -f2| xargs)
  if [ -z "${INTERFACE}" ]; then
    echo "Cannot detect interface, this might not work"
  else
    NETWORK_CONFIG=""
    FOUND=""
    if [ -d /etc/netplan ]; then
      files=$(shopt -s nullglob dotglob; echo /etc/netplan/*)
      if [ ${#files} -gt 0  ]; then
        FILE=$(grep "${INTERFACE}" /etc/netplan/* -l | head -n1)
        if [ ! -z "${FILE}" ]; then
          sudo sed -i ${FILE} -e "s/${INTERFACE}/eth0/g" > ${OUTPUT} 2>> ${OUTPUT}
          FOUND="netplan"
        fi
      fi
    fi

    if [ -z "${FOUND}" ] && [ -f /etc/network/interfaces ]; then
      sudo sed -i /etc/network/interfaces -e "s/${INTERFACE}/eth0/g" > ${OUTPUT} 2>> ${OUTPUT}
      FOUND="ifupdown"
    fi

    if [ -z "${FOUND}" ]; then
      echo "Not using netplan or ifupdown. This might not work"
    else
      echo "${FOUND} detected, interface ${INTERFACE}. OK"
    fi
  fi

  ##
  echo -n "  + Configuring virtual desktop... "
  sudo mkdir -p /root/.icewm
  echo -e "#!/bin/bash\n\nPLAYER=\$(cat /var/www/config/player)\nsource \"/var/www/players/\${PLAYER}/config\"\n\nif [ \"\${START_VNC}\" == \"1\" ]; then\n  /var/www/players/\${PLAYER}/\${PLAYER_START} &\nfi\n\nexit 0\n" | sudo tee /root/.icewm/startup > /dev/null
  sudo chmod 755 /root/.icewm/startup

  if [ ! -f /root/.dmrc ]; then
    echo -e "[Desktop]\nSession=icewm-session\n" > sudo tee /root/.dmrc > /dev/null
  fi
  echo "OK"

  ## grub
  echo -n "  + Configuring boot options... "
  if [ "${ARCH}" == "x86_64" ]; then
    MSGS=$(sudo sed -i /etc/default/grub -e "s/.*GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"text clocksource=hpet 3 biosdevname=0 net.ifnames=0\"/g" && sudo update-grub > ${OUTPUT} 2>> ${OUTPUT})
    if [ $? -eq 0 ]; then
      echo "OK"
    else
      echo "ERROR"
      cat "${OUTPUT}"
      error_out "Cannot setup boot options"
    fi
  elif [ -f "/lib/systemd/system/getty@.service" ]; then
    #Raspbian
    sudo systemctl set-default multi-user.target
    if [ ! -f /etc/systemd/system/getty.target.wants/getty@tty1.service ]; then
      sudo ln -fs /lib/systemd/system/getty@.service /etc/systemd/system/getty.target.wants/getty@tty1.service > /dev/null 2> /dev/null
    fi
    if [ -f tty1.service.d/autologin.conf ]; then
      sudo rm /etc/systemd/system/getty@tty1.service.d/autologin.conf
    fi
    echo "OK"
  else
    echo "Skipped"
  fi

  echo -n "  + Configuring samba... "
  if [ ! -d /etc/samba ]; then
    sudo mkdir -p /etc/samba
  fi
  echo [payload removed: 13476 characters] \
    | base64 -d | sudo tee /etc/samba/smb.conf > /dev/null
  sudo systemctl restart smbd 2> /dev/null > /dev/null
  echo "OK"

  echo -n "  + Configuring mympd... "
  if [ -f /usr/local/bin/mympd ]; then
    rm -f /usr/local/bin/mympd > /dev/null 2> /dev/null
  fi
  if [ ! -f /usr/bin/mympd ]; then
    sudo mpd_remote.sh install > /dev/null 2> /dev/null
  fi
  echo "OK"

  return 0
}


###############################################################################
##
## As close to main function as I'm gonna get
##
###############################################################################
process_options "${@}"
echo "# Begin installation of Snakeoil ${SNAKEOIL_VERSION} "
check_prerequisites
if [ -f /etc/systemd/system/snakeoil-rest.service ]; then
  sudo systemctl stop snakeoil-rest
fi
install_packages
install_snakeoil_components
config_snakeoil

quit 0

