#!/usr/bin/env bash

rubygems_remove()
{
  typeset rubygems_path ruby entry

  rvm_log "Removing old Rubygems files..."

  case "$rvm_ruby_string" in
    (rbx-*)
      ruby="['prefix']"
      ;;
    (*)
      ruby=".values_at('sitelibdir','vendorlibdir').detect{ |path| File.directory?(File.join(path.to_s, 'rubygems')) }.to_s"
      ;;
  esac
  rubygems_path="$(ruby -rrbconfig -e "puts ::Kernel.const_get('RbConfig')::CONFIG$ruby")"

  # Remove common files installed by ruby gems.
  entries=(
  "${rubygems_path}/ubygems.rb"
  "${rubygems_path}/gauntlet_rubygems.rb"
  "${rubygems_path}/rbconfig/"
  )
  for entry in "${entries[@]}" "${rubygems_path}/rubygems"*
  do
    __rvm_rm_rf "$entry"
  done
}

can_switch_rubygems()
{
  case "$rvm_ruby_string" in
    maglev*)
      return 1
      ;;
    *)
      return 0
      ;;
  esac
}

make_sure_jruby_can_work_with_rubygems()
{
  case "$rvm_ruby_string" in
    jruby-head*)
      true
      ;;
    jruby*)
      __rvm_version_compare "$rvm_ruby_version" -ge 1.7.1 || return 1
      ;;
    *)
      return 0 # do not care about other rubies
      ;;
  esac

  case "${rvm_rubygems_version}" in
    head|master)
      true
      ;;
    *)
      __rvm_version_compare "$rvm_rubygems_version" -ge 2.0.0 || return 1
      ;;
  esac
}

rubygems_fatal_error()
{
  rvm_error "$1"
  exit ${2:-1}
}

rubygems_version_list()
{
  __rvm_curl -sS https://rubygems.org/api/v1/versions/rubygems-update.json |
    __rvm_awk -v RS=',' -v FS='"' '$2=="number"{print $4}' | __rvm_version_sort |
    __rvm_grep '^[[:digit:]\.]*$'
}

rubygems_master_sha()
{
  __rvm_curl -s "https://api.github.com/repos/rubygems/rubygems/commits?page=last&per_page=1" |
    __rvm_sed -n '/^    "sha":/ {s/^.*".*": "\(.*\)".*$/\1/;p;}'
}

rubygems_select_version_url()
{
  case "$version" in
    latest|current)
      case "$rvm_ruby_string" in
        ruby-1.8*|ree-1.8*)
          typeset _rbv
          _rbv=${rvm_ruby_version##*.}
          if (( _rbv <= 5 ))
          then
            version=1.3.5
          elif (( _rbv == 6 ))
          then
            version=1.3.7
          fi
          ;;
      esac
      ;;
  esac

  case "$version" in
    latest|current)
      version="$(__rvm_db "${rvm_ruby_string//-/_}_rubygems_version")"
      version="${version:-"$(__rvm_db "${rvm_ruby_interpreter}_${rvm_ruby_version}_rubygems_version")"}"
      if (( ${rvm_head_flag:-0} == 1 )) && [[ -z "${version:-}" ]]
      then version="$(__rvm_db "${rvm_ruby_interpreter}_head_rubygems_version")"
      fi
      version="${version:-"$(__rvm_db "${rvm_ruby_interpreter}_rubygems_version")"}"
      version="${version:-"$(__rvm_db "rubygems_version")"}"
      ;;
  esac

  case "$version" in
    latest-*)
      version="${version#latest-}"
      version="$(rubygems_version_list | __rvm_grep "^${version}\." | __rvm_tail -n 1 )"
      version="${version}"
      ;;
  esac

  case "${version:-missing}" in
    head|master)
      typeset sha
      sha="$(rubygems_master_sha)"
      rvm_rubygems_version="$version"
      rvm_gem_package_name="rubygems-${sha}"
      rvm_gem_url="https://github.com/rubygems/rubygems/archive/${sha}.tar.gz"
      export rvm_verify_downloads_flag=1
      ;;
    v*)
      rvm_rubygems_version="$version"
      rvm_gem_package_name="rubygems-${version#v}"
      rvm_gem_url="https://github.com/rubygems/rubygems/archive/$version.tar.gz"
      export rvm_verify_downloads_flag=1
      ;;
    missing)
      rvm_error "There was an error while trying to resolve rubygems version for '$1'. \nHalting the installation."
      return 4
      ;;
    *)
      rvm_rubygems_version="$version"
      rvm_gem_package_name="rubygems-${rvm_rubygems_version}"
      rvm_rubygems_url=$(__rvm_db "rubygems_url")
      rvm_gem_url="${rvm_rubygems_url}/${rvm_gem_package_name}.tgz"
      ;;
  esac
}

__rvm_warn_on_rubyopt()
{
  if [[ -n "${RUBYOPT:-""}" ]]; then
    rvm_warn \
      "Please note: You have the RUBYOPT environment variable set and this \
            may interfere with normal rvm operations. We sugges unsetting it."
    return 1
  else
    return 0
  fi
}

rubygems_setup_lang_fallback()
{
  if
    [[ -z "${LANG:-}" ]]
  then
    LANG="$(
      {
        locale -a | __rvm_grep "^en_US.utf8" ||
        locale -a | __rvm_grep "^en_US" ||
        locale -a | __rvm_grep "^en" ||
        locale -a
      } 2>/dev/null | head -n 1
    )"
    : LANG=${LANG:=en_US.utf-8}
    export LANG
    rvm_warn "\$LANG was empty, setting up LANG=$LANG, if it fails again try setting LANG to something sane and try again."
  fi
}

rubygems_setup()
{
  export version="$1"

  rvm_debug "rubygems_setup version:${version} rvm_ruby_string:${rvm_ruby_string} rvm_ruby_home:${rvm_ruby_home} rvm_ruby_binary:${rvm_ruby_binary}"

  can_switch_rubygems ||
  rubygems_fatal_error "RVM can not install rubygems for maglev and older jruby, select other ruby and try again." $?

  __rvm_warn_on_rubyopt

  true ${rvm_ruby_selected_flag:=0}

  unset RUBYOPT

  (( rvm_ruby_selected_flag == 0 )) || __rvm_select

  rubygems_select_version_url "$version" || return $?

  make_sure_jruby_can_work_with_rubygems ||
  rubygems_fatal_error "RVM can not install rubygems for older jruby, select other ruby and try again." $?

  # always cleanup!
  [[ -d "${rvm_src_path}/$rvm_gem_package_name" ]] ||
    __rvm_rm_rf "${rvm_src_path}/$rvm_gem_package_name"

  rvm_log "Retrieving $rvm_gem_package_name"
  "$rvm_scripts_path/fetch" "$rvm_gem_url" "${rvm_gem_package_name}.tgz" ||
  rubygems_fatal_error "There has been an error while trying to fetch rubygems. \nHalting the installation." $?

  __rvm_log_command "rubygems.extract" "Extracting $rvm_gem_package_name ..." \
  __rvm_package_extract "${rvm_archives_path}/$rvm_gem_package_name.tgz" "${rvm_src_path}" ||
  rubygems_fatal_error "There has been an error while trying to extract rubygems. \nHalting the installation." $?

  rubygems_remove # Remove old gems.

  __rvm_cd "${rvm_src_path}/$rvm_gem_package_name"

  typeset -a __command
  __command=(
    GEM_PATH="$GEM_PATH:${GEM_PATH%%@*}@global" GEM_HOME="$GEM_HOME"
    "${rvm_ruby_binary}" -d "${rvm_src_path}/$rvm_gem_package_name/setup.rb"
  )
  if [[ ${rvm_debug_flag:-0} == 1 || ${rvm_trace_flag:-0} == 1 ]]
  then __command+=( --verbose )
  fi
  rubygems_setup_lang_fallback
  if
    __rvm_log_command "rubygems.install" "Installing $rvm_gem_package_name for ${rvm_ruby_string}" \
      "${__command[@]}"
  then
    typeset program_suffix
    program_suffix="$( __rvm_ruby_config_get configure_args "${rvm_ruby_binary}" )"
    case "${program_suffix:-}" in
      (*--program-suffix=*)
        program_suffix="${program_suffix#*--program-suffix=}"
        program_suffix="${program_suffix%%[\' ]*}"
        __rvm_run "link.gem" "ln -s \"$rvm_ruby_home/bin/gem${program_suffix}\" \
          \"$rvm_ruby_home/bin/gem\"" "$rvm_ruby_string - #linking gem${program_suffix} -> gem "
        ;;
    esac
    rvm_log "Installation of rubygems completed successfully."
  else
    rvm_warn "Installation of rubygems did not complete successfully."
  fi

  __rvm_rubygems_create_link "${rvm_ruby_binary}"
}

rubygems_link()
{
  __rvm_rubygems_create_link
}

rubygems_validate_gemfile_extract()
(
  \mkdir -p "$2/gem" &&
  \tar -C "$2" -xf "$1" --touch &&
  \cd "$2" &&
  \gzip -d "metadata.gz" &&
  \tar -C gem -xzf "data.tar.gz" --touch &&
  \rm "data.tar.gz" ||
  {
    typeset ret=$?
    rvm_error "Error extracting '$1' to '$2'."
    \rm -rf "${rvm_tmp_path}/rg$$"
    return $ret
  }
)

# Adapted from: https://gist.github.com/4678778
rubygems_validate_gemfile()
(
  gem_file="$1"
  downloaded_file="${gem_file##*/}"
  gem__url="${2:-https://d2chzxaqi4y7f8.cloudfront.net/gems/$downloaded_file}"
  dir_local_copy="${downloaded_file%.gem}--local"
  dir_remote_copy="${downloaded_file%.gem}-remote"

  mkdir -p "${rvm_tmp_path}/rg$$"
  cd "${rvm_tmp_path}/rg$$"

  __rvm_curl "$gem__url" -o "$downloaded_file" &&
  [[ -f "$downloaded_file" ]] ||
  {
    typeset ret=$?
    rvm_error "Could not download '$gem__url'."
    \rm -rf "${rvm_tmp_path}/rg$$"
    return $ret
  }

  rubygems_validate_gemfile_extract "$gem_file"        "$dir_local_copy"  || return $?
  rubygems_validate_gemfile_extract "$downloaded_file" "$dir_remote_copy" || return $?

  # compare
  diff -ru "$dir_local_copy" "$dir_remote_copy"

  # cleanup
  \rm -rf "${rvm_tmp_path}/rg$$"
)

rubygems_validate_list_gemdirs()
{
  for gemdir in "$@"
  do
    __rvm_readlink_deep gemdir
    echo "${gemdir}"
  done | sort -u
}

# Adapted from: https://gist.github.com/4678189
rubygems_validate()
{
  __rvm_which openssl > /dev/null ||
    rubygems_fatal_error "'openssl' was not found, please install it."

  typeset gemdir gemfile url gem loc rem log
  typeset -a gemdirs

  rvm_log  "Validating RubyGems... This will take a while..."

  __rvm_read_lines gemdirs <(
    rubygems_validate_list_gemdirs "$@"
  )

  (( ${#gemdirs[@]} )) ||
  __rvm_read_lines gemdirs <(
    rubygems_validate_list_gemdirs "$rvm_gems_path"/*/cache
  )

  for gemdir in "${gemdirs[@]}"
  do
    for gem in "$gemdir"/*.gem
    do
      gemfile="${gem##*/}"
      url="https://d2chzxaqi4y7f8.cloudfront.net/gems/$gemfile"
      printf "%b" "${rvm_notify_clr}${gem}${rvm_reset_clr}"

      loc=$(openssl md5 $gem |cut -d" " -f2)
      rem=$(__rvm_curl -3 -s -D - -X HEAD -H 'Connection:close' "$url" | __rvm_grep 'ETag' | cut -d'"' -f2)

      [[ $loc == $rem ]] ||
      {
        printf "%b" " "
        log="${rvm_log_path}/$gemfile.diff"
        rubygems_validate_gemfile "$gem" "$url" > "$log"
        printf "%b" "${rvm_error_clr}mismatch, local: $loc, remote: $rem${rvm_reset_clr}, differences recorded in '$log'"
      }
      printf "%b" ", "
    done
  done

  rvm_log "\nDone verifying gems."
}
