#!/usr/bin/env bash

shopt -s extglob
PS4="+ \${BASH_SOURCE##\${rvm_path:-}} : \${FUNCNAME[0]:+\${FUNCNAME[0]}()}  \${LINENO} > "
export PS4
set -o errtrace
set -o errexit

log()  { printf "$*\n" ; return $? ;  }

fail() { log "\nERROR: $*\n" ; exit 1 ; }

usage()
{
  printf "

Usage

  rvm-installer [options] [action]

Options

  --branch <name>               - Install RVM head, from named branch
  --version <head|latest|x.y.z> - Install RVM version [head|latest|x.y.z]
  --trace                       - used to debug the installer script

Actions

  stable - Install RVM stable branch from wayneeseguin rvm repo.
  help   - Display CLI help (this output)

Branches:

  branch <branch>
  branch /<branch>
  branch <repo>/
  branch <repo>/<branch>

  Defaults:

    branch: master
    repo:   wayneeseguin

"
}

fetch_version()
{
  version=$(curl -s -B "${rvm_releases_url}/latest-version.txt" 2>/dev/null)
}

fetch_md5()
{
  md5=$(curl -s -B "${rvm_releases_url}/rvm-${version}.tar.gz.md5" 2>/dev/null)
}

md5_match()
{
  local archive="$1"

  case "$(uname)" in
    Darwin|FreeBSD)
      archive_md5="$(/sbin/md5 -q "${archive}")"
      ;;

    OpenBSD)
      archive_md5="$(/bin/md5 -q "${archive}")"
      ;;

    Linux|*)
      archive_md5="$(md5sum "${archive}")"
      archive_md5="${archive_md5%% *}"
      ;;
  esac

  if [[ "$archive_md5" == "$md5" ]]
  then
    return 0
  else
    return 1
  fi
}

install_release()
{
  local archive url

  archive="${rvm_archives_path}/rvm-${version}.tar.gz"
  url="${rvm_releases_url}/rvm-${version}.tar.gz"

  fetch_md5

  if [[ -s "${archive}" && -n "${md5}" ]] && ! md5_match "${archive}"
  then
    # Remove old installs, if they exist and have incorrect md5.
    if [[ -f "${archive}" ]]
    then
      rm -f "${archive}"
    fi
  fi

  if curl -L "${url}" -o "${archive}"
  then
    true
  else
    fail "Failed to download ${url} to ${archive} using 'curl', error code ($?)"
  fi

  if ! md5_match "$archive"
  then
    fail "ERROR:

Archive package downloaded does not match its calculated md5 checksum ${md5}:

  $rvm_archives_path/rvm-${version}.tar.gz

Retry the installation and/or check your networking setup.

Halting installation.
"
  fi

  if tar zxf "${archive}" -C "$rvm_src_path/" --no-same-owner
  then
    cd "$rvm_src_path/rvm-${version}"
  else
    fail "Failed to extract ${archive} to ${rvm_src_path}/,"\
      "tar command returned error code $?"
  fi
}

install_head()
{
  typeset _repo _name _branch _local_branch
  case "$1" in
    (/*)
      _repo=wayneeseguin
      _branch=${1#/}
      ;;
    (*/)
      _repo=${1%/}
      _branch=master
      ;;
    (*/*)
      _repo=${1%/*}
      _branch=${1#*/}
      ;;
    (*)
      _repo=wayneeseguin
      _branch=$1
      ;;
  esac
  case ${_repo} in
    (wayneeseguin)
      _name=origin
      _local_branch=${_branch}
      ;;
    (*)
      _name=${_repo}
      _local_branch=${_repo}/${_branch}
      ;;
  esac

  [[ -d "${rvm_src_path}/rvm" ]] ||
    \mkdir -p "${rvm_src_path}/rvm"

  builtin cd "${rvm_src_path}/rvm"

  if [[ ! -d "${rvm_src_path}/rvm/.git" ]] &&
    ! git clone --depth 1 git://github.com/wayneeseguin/rvm.git $PWD &&
    ! git clone https://github.com/wayneeseguin/rvm.git $PWD
  then
    log "Could not clone master RVM repository, try \`rvm get latest\`."
    return 1
  fi

  # no warning for referencing branch that matches local and remote
  # by default first matched (local) is used and it's what we want
  git config core.warnambiguousrefs false

  if git remote | grep "^${_name}$" >/dev/null
  then
    if ! git fetch --no-tags --depth 1 ${_name}
    then
      log "Could not update RVM repository '${_name}', check your network."
      return 2
    fi

  else

    if git remote add ${_name} git://github.com/${_repo}/rvm.git &&
      git fetch --no-tags --depth 1 ${_name}
    then
      true
    elif git remote set-url ${_name} https://github.com/${_repo}/rvm.git &&
      git fetch --no-tags --depth 1 ${_name}
    then
      true
    else
      git remote rm ${_name}
      log "Could not find repository '${_repo}', check list of available repositories here https://github.com/wayneeseguin/rvm/network/members."
      return 3
    fi
  fi

  if ! git branch -r | grep " ${_name}/${_branch}$" >/dev/null
  then
    log "Branch ${_branch} does not exists at https://github.com/${_repo}/rvm/branches."
    return 4
  fi

  if ! git branch | grep " ${_local_branch}$" >/dev/null &&
    ! git branch --track --force ${_local_branch} remotes/${_name}/${_branch}
  then
    if [[ "${_local_branch}" == "master" ]]
    then
      log "Could not create local branch ${_local_branch}, cleaning sources, please try again."
      builtin cd "${rvm_src_path}"
      __rvm_rm_rf "${rvm_src_path}/rvm"
      return 5
    else
      log "Could not create local branch ${_local_branch}."
      return 5
    fi
  fi

  if ! git branch | grep "\* ${_local_branch}$" >/dev/null &&
    ! git checkout --force ${_local_branch}
  then
    log "Could not checkout branch ${_local_branch}."
    return 6
  fi

  if ! git reset --hard remotes/${_name}/${_branch}
  then
    log "Could not update to HEAD of ${_name}/${_branch}."
    return 7
  fi
}

# Tracing, if asked for.
if [[ "$*" =~ --trace ]] || (( ${rvm_trace_flag:-0} > 0 ))
then
  set -o xtrace
  export rvm_trace_flag=1
fi

# Variable initialization, remove trailing slashes if they exist on HOME
true \
  ${rvm_trace_flag:=0} ${rvm_debug_flag:=0} ${rvm_user_install_flag:=0}\
  ${rvm_ignore_rvmrc:=0} HOME="${HOME%%+(\/)}"


if (( rvm_ignore_rvmrc == 0 ))
then
  for rvmrc in /etc/rvmrc "$HOME/.rvmrc"
  do
    if [[ -s "$rvmrc" ]]
    then
      if \grep '^\s*rvm .*$' "$rvmrc" >/dev/null 2>&1
      then
        printf "\nError: $rvmrc is for rvm settings only.\n"
        printf "rvm CLI may NOT be called from within $rvmrc. \n"
        printf "Skipping the loading of $rvmrc\n"
        return 1
      else
        source "$rvmrc"
      fi
    fi
  done
fi

if [[ -z "${rvm_path:-}" ]]
then
  if (( UID == 0 ))
  then
    rvm_path="/usr/local/rvm"
  else
    rvm_path="${HOME}/.rvm"
  fi
fi
export HOME rvm_path

# Parse CLI arguments.
while (( $# > 0 ))
do
  token="$1"
  shift
  case "$token" in

    --trace)
      set -o xtrace
      export rvm_trace_flag=1
      ;;

    --path)
      if [[ -n "${1:-}" ]]
      then
        rvm_path="$1"
        shift
      else
        fail "--path must be followed by a path."
      fi
      ;;

    --branch) # Install RVM from a given branch
      if [[ -n "${1:-}" ]]
      then
        version="head"
        branch="$1"
        shift
      else
        fail "--branch must be followed by a branchname."
      fi
      ;;

    --user-install|--auto)
      token=${token#--}
      token=${token//-/_}
      export "rvm_${token}_flag"=1
      printf "Turning on ${token/_/ } mode.\n"
      ;;

    --version)
      case "$1" in
        +([[:digit:]]).+([[:digit:]]).+([[:digit:]]))
          version="$1"
          ;;
        latest)
          version="latest"
          ;;
        stable)
          version="head"
          branch="stable"
          ;;
        head|master)
          version="head"
          branch="master"
          ;;
        *)
          fail "--version must be followed by a vaild version number x.y.z"
          ;;
      esac
      shift
      ;;

    +([[:digit:]]).+([[:digit:]]).+([[:digit:]]))
      version="$token"
      ;;

    stable)
      version="head"
      branch="stable"
      ;;

    head|master)
      version="head"
      branch="master"
      ;;

    help|usage)
      usage
      exit 0
      ;;
  *)
    usage
    exit 1
    ;;

  esac
done

true "${version:=head}"

if [[ "$rvm_path" != /* ]]
then
  fail "The rvm install path must be fully qualified. Tried $rvm_path"
fi

rvm_src_path="$rvm_path/src"
rvm_archives_path="$rvm_path/archives"
rvm_releases_url="https://rvm.beginrescueend.com/releases"

for dir in "$rvm_src_path" "$rvm_archives_path"
do
  if [[ ! -d "$dir" ]]
  then
    mkdir -p "$dir"
  fi
done

# Perform the actual installation, first we obtain the source using whichever
# means was specified, if any. Defaults to head.
case "${version}" in
  (head)
    install_head ${branch:-master} || exit $?
    ;;

  (latest)
    fetch_version
    install_release
    ;;

  (+([[:digit:]]).+([[:digit:]]).+([[:digit:]])) # x.y.z
    install_release
    ;;
  (*)
    fail "Something went wrong, unrecognized version '$version'"
    ;;
esac

# No matter which one we are doing we install the same way, using the RVM
#   installer script.
flags=()
if (( rvm_trace_flag == 1 ))
then flags+=("--trace")
fi

if (( rvm_debug_flag == 1 ))
then flags+=("--debug")
fi

if (( rvm_auto_flag == 1 ))
then flags+=("--auto")
fi

chmod +x ./scripts/install

# Now we run the RVM installer.
./scripts/install ${flags[*]} --path "$rvm_path"
