#!/usr/bin/env bash

# Ensure this file is executable via `chmod a+x deken`, then place it
# somewhere on your ${PATH}, like ~/bin. The rest of Deken will self-install
# on first run into the ~/.deken/ directory.

# Much of this code is pilfered from Clojure's Leiningen tool


##############################################################################
# variable declarations
##############################################################################

export DEKEN_VERSION="0.6.0"
export DEKEN_HOME="${DEKEN_HOME:-"${HOME}/.deken"}"
DEKEN_GIT_BRANCH="${DEKEN_GIT_BRANCH:-master}"
if [ "x${DEKEN_BASE_URL}" = "x" ]; then
    DEKEN_BASE_URL="https://raw.githubusercontent.com/pure-data/deken/${DEKEN_GIT_BRANCH}/developer"
fi

VIRTUALENV_VERSION="16.0.0"
VIRTUALENV_URL="https://pypi.io/packages/source/v/virtualenv/virtualenv-${VIRTUALENV_VERSION}.tar.gz"

if [ "${OSTYPE}" = "cygwin" ] || [ "${OSTYPE}" = "msys" ]; then
    delimiter=";"
else
    delimiter=":"
fi

if [ "${OSTYPE}" = "cygwin" ]; then
  cygwin=true
  export DEKEN_HOME=$(cygpath -w "${DEKEN_HOME}")
else
  cygwin=false
fi

# allow the user to override the default python
if [ "x${PYTHON_BIN}" = x ]; then
 PYTHON_BIN=python3
fi

# This needs to be defined before we call HTTP_CLIENT below
if [ "${HTTP_CLIENT}" = "" ]; then
    if which curl >/dev/null; then
        if [ "${https_proxy}" != "" ]; then
            CURL_PROXY="-x ${https_proxy}"
        fi
        HTTP_CLIENT="curl ${CURL_PROXY} -f -L -o"
    else
        HTTP_CLIENT="wget -O"
    fi
fi

if test -z "${systeminstalled}"; then
 # if this script resides in /usr/ and there's a deken.hy relative to it in the
 # share/ folder, we consider it system-installed
 if test -z "${0##/usr/*}" && test -e "${0%/*}/../share/deken/deken.hy"; then
   systeminstalled=true
 else
   systeminstalled=false
 fi
fi

if ${systeminstalled}; then
    DEKENHY="${0%/*}/../share/deken/deken.hy"
else
    DEKENHY="${DEKEN_HOME}/deken.hy"
fi


##############################################################################
# helper functions
##############################################################################

error() {
    echo "$@" 1>&2
}

countdown() {
  local t
  t=$1
  t=$((t))
  while [ $t -gt 0 ]; do
     printf "\r%2d" $((t))
     sleep 1
     t=$((t-1))
  done
  printf "\r  \r"
}

uninstall_deken() {
    if ${systeminstalled}; then
      # on Debian we disallow uninstalling
      error "Uninstalling is disabled for system-provided deken!"
      error "Instead, use your package manager to remove deken."
      exit 1
    fi
    error "I'm going to uninstall myself and my dependencies from ${DEKEN_HOME} now."
    error "Feel free to Ctrl-C now if you don't want to do this."
    countdown 5
    error "Uninstalling deken."
    rm -rf "${DEKEN_HOME}" "$0"
    exit 0
}

bail_install() {
    error "Self-installation of Deken failed."
    error "Please paste any errors in the bug tracker at https://github.com/pure-data/deken/issues"
    # remove all traces of our attempts to install.
    rm -rf "${DEKEN_HOME}"
    # bail from this script.
    exit 1
}
bail_install_msg() {
    error "$@"
    bail_install
}

bail_requirements() {
    rm -f "${DEKEN_HOME}/requirements.txt"
    error "Installation of requirements failed."
    error "You probably should install the following packages first:"
    error " - 'python-dev'"
    error " - 'libffi-dev'"
    error " - 'libssl-dev'"
    error "You can run 'deken install' or 'deken upgrade' anytime to"
    error " re-install (or upgrade) your Deken installation"

    exit 1
}

install_virtualenv() {
    echo "Downloading & installing Virtualenv."
    rm -rf "${DEKEN_HOME}/virtualenv-source"
    mkdir -p "${DEKEN_HOME}/virtualenv-source" && \
	${HTTP_CLIENT} "${DEKEN_HOME}/virtualenv.tar.gz" "${VIRTUALENV_URL}" && \
	tar -zxvf "${DEKEN_HOME}/virtualenv.tar.gz" -C "${DEKEN_HOME}/virtualenv-source/" && \
	mv "${DEKEN_HOME}"/virtualenv-source/virtualenv-*/* "${DEKEN_HOME}/virtualenv-source"

    [ -d "${DEKEN_HOME}/virtualenv-source" ] && \
        ( \
	  cd "${DEKEN_HOME}/virtualenv-source" && \
	      /usr/bin/env "${PYTHON_BIN}" setup.py build \
        ) || \
	    bail_install
}

install_deken() {
    if ${systeminstalled}; then
       # on Debian, we can skip installation
       return
    fi

    which "${PYTHON_BIN}" >/dev/null || \
        bail_install_msg "Oops, no Python found! You need Python3 to run Deken: ${PYTHON_BIN}
You can specify an alternative Python interpreter via the PYTHON_BIN envvar"
    error "This is your first time running deken on this machine."
    error "I'm going to install myself and my dependencies into ${DEKEN_HOME} now."
    error "Feel free to Ctrl-C now if you don't want to do this."
    countdown 3
    error "Installing deken."

    mkdir -p "${DEKEN_HOME}"
    [ -e "${DEKEN_HOME}/requirements.txt" ] || (\
        ( echo "Fetching Python requirements file: ${DEKEN_BASE_URL}/requirements.txt" && \
        ${HTTP_CLIENT} "${DEKEN_HOME}/requirements.txt" "${DEKEN_BASE_URL}/requirements.txt" ) || bail_install)
    [ -e "${DEKEN_HOME}/requirements.txt" ] || bail_install
    [ -e "${DEKENHY}" ] || (\
        ( echo "Fetching main hylang file: ${DEKEN_BASE_URL}/deken.hy" && \
        ${HTTP_CLIENT} "${DEKENHY}" "${DEKEN_BASE_URL}/deken.hy" ) || bail_install)
    [ -e "${DEKENHY}" ] || bail_install
    [ -x "${DEKEN_HOME}/virtualenv-source/virtualenv.py" ] || install_virtualenv
    [ -d "${DEKEN_HOME}/virtualenv" ] || (\
        echo "Setting up the virtual environment." && \
        "${DEKEN_HOME}/virtualenv-source/virtualenv.py" -p "${PYTHON_BIN}" "${DEKEN_HOME}/virtualenv" || exit 1)
    [ -x "${DEKEN_HOME}/virtualenv/bin/hy" ] || (\
        echo "Installing deken library dependencies." && \
        "${DEKEN_HOME}/virtualenv/bin/pip" install -r "${DEKEN_HOME}/requirements.txt" || bail_requirements)
}

upgrade_deken() {
    if ${systeminstalled}; then
      # on Debian we disallow upgrading
      error "Direct upgrading is disabled for system-provided deken!"
      error "Instead, use your package manager to install newer versions."
      exit 1
    fi
    # first upgrade this script itself
    echo "Upgrading $0."
    ${HTTP_CLIENT} "$0" "${DEKEN_BASE_URL}/deken"
    # next upgrade our dependencies
    for f in requirements.txt deken.hy
    do
        echo "Fetching ${f} file: ${DEKEN_BASE_URL}/${f}"
        ${HTTP_CLIENT} "${DEKEN_HOME}/.upgrade-${f}" "${DEKEN_BASE_URL}/${f}" || ( error "Error upgrading ${f}"; exit 1; )
        mv "${DEKEN_HOME}/.upgrade-${f}" "${DEKEN_HOME}/${f}"
    done
    # finally update the python dependencies
    "${DEKEN_HOME}/virtualenv/bin/pip" install -r "${DEKEN_HOME}/requirements.txt" || bail_requirements
    echo "Successfully upgraded."
}

tryrun_deken() {
    if ${systeminstalled}; then
       hy3 "${DEKENHY}" "$@"
       exit $?
    fi
    if [ ! -x "${DEKEN_HOME}/virtualenv/bin/hy" ]; then
       error "Unable to find '${DEKEN_HOME}/virtualenv/bin/hy'"
       error "Try running '$0 install' or '$0 upgrade'"
       exit 1
    fi
    if [ -e "${DEKENHY}" ]; then
       "${DEKEN_HOME}/virtualenv/bin/hy" "${DEKENHY}" "$@"
    else
       error "Unable to find '${DEKENHY}'"
       error "Try running '$0 install' or '$0 upgrade'"
       exit 1
    fi
}

##############################################################################
# here starts the code
##############################################################################


if [ $# -eq 2  ] && [ "x$1" = "xuninstall" ] && [ "x$2" = "x--self" ]; then
  uninstall_deken
fi

if [ $# -eq 1  ] && [ "x$1" = "x--version" ]; then
  echo "${DEKEN_VERSION}"
  exit
fi


if [ $(id -u) -eq 0 ] && [ "${DEKEN_ROOT}" = "" ]; then
    error "WARNING: You're currently running as root; probably by accident."
    error "Press control-C to abort or Enter to continue as root."
    error "Set DEKEN_ROOT to disable this warning."
    read _
fi

# make sure we are deployed
[ -d "${DEKEN_HOME}" ] || install_deken

# last check to make sure we can bootstrap
[ -d "${DEKEN_HOME}" ] || bail_install

# catch the special "upgrade" command
if [ $# -eq 2  ] && [ "x$1" = "xinstall" ] && [ "x$2" = "x--self" ]; then
    echo install_deken
elif [ $# -eq 2  ] && [ "x$1" = "xupgrade" ] && [ "x$2" = "x--self" ]; then
    echo upgrade_deken
elif [ $# -eq 2  ] && [ "x$1" = "xupdate" ] && [ "x$2" = "x--self" ]; then
    echo upgrade_deken
else
    # run the real deken command with args passed through
    tryrun_deken "$@"
fi
