#!/usr/bin/env bash

source "$rvm_scripts_path/base"

__rvm_attempt_single_exec()
{
  # Return if we have multiple rubies. or we're not running exec.
  if [[ "$action" = "exec" && ${#rvm_ruby_strings[@]} -lt 2 ]]; then

    __rvm_become "$rvm_ruby_strings"

    eval "exec ${args[@]}"
  fi

  return 1
}

# Perform an action using one of a selected ruby's specified binaries.
__rvm_ruby_do()
{
  # Return on invalid rubies.
  __rvm_become "$current_set_ruby" || return 1

  rvm_hook="before_do" ; source "$rvm_scripts_path/hook"

  if [[ "$action" = "exec" ]]
  then
    command="${args[@]}" # rvm exec is a special case.
  else
    binary="$(echo $action | sed 's#do$##')"
    if [[ -x "$rvm_ruby_home/bin/$binary" ]]
    then
      binary="$rvm_ruby_home/bin/$binary"
    elif [[ -x "$rvm_ruby_global_gems_path/bin/$binary" ]]
    then
      binary="$rvm_ruby_global_gems_path/bin/$binary"
    elif [[ -x "$rvm_ruby_gem_home/bin/$binary" ]]
    then
      binary="$rvm_ruby_gem_home/bin/$binary"
    elif [[ "system" = "$rvm_ruby_string" ]] && [[ -x "$(command -v $binary)" ]]
    then
      binary="$(basename $(command -v $binary) 2>/dev/null)"
    else
      rvm_warn "'$binary not found for $rvm_ruby_string' either does not exist or is not executable? :("
      __rvm_unset_ruby_variables
      return 1
    fi

    if [[ ! -z "$rvm_ruby_mode" ]]
    then
      rvm_ruby_string="${rvm_ruby_string}-${rvm_ruby_mode}"
      rvm_ruby_mode="--$(echo "$rvm_ruby_mode" | sed 's/^m//')"
    fi

    load_path="$(dirname $(command -v $binary) 2>/dev/null):$rvm_ruby_load_path"

    # TODO: the else case below should be run if $args =~ /\.rb$/
    if [[ "ruby" = "$(basename $binary)" && "$rvm_benchmark_flag" -ne 1 ]]
    then
      case "${args[@]}" in
        (exec[[:space:]]*)
          command="$binary $rvm_ruby_mode ${args[@]}"
          ;;
        (*[[:space:]]-S[[:space:]]*)
          command="$binary $rvm_ruby_mode $rvm_ruby_require -I$load_path ${args[@]}"

        (*)
          command="$binary $rvm_ruby_mode $rvm_ruby_require -I$load_path -S ${args[@]}"
          ;;
      esac
    else
      command="$binary $rvm_ruby_mode ${args[@]}"
    fi
  fi

  if [[ -n "$rvm_json_flag" || -n "$rvm_yaml_flag" || -n "$rvm_summary_flag" ]]
  then
    if [[ ! -d "./log/$rvm_ruby_string/" ]] ; then
      mkdir -p "./log/$rvm_ruby_string/"
    fi
    touch "./log/$rvm_ruby_string/$action.log"
    eval "$command" >> "./log/$rvm_ruby_string/$action.log" 2>&1
  else
    if (( ${rvm_verbose_flag:-0} > 0 ))
		then
      current_env="$(__rvm_env_string)"
      if [[ "$current_env" != "$current_set_ruby" ]]
			then
        current_env="$current_set_ruby ($current_env)"
      fi
      rvm_log "$current_env: $(ruby -v $rvm_ruby_mode | \tr "\n" ' ')\n"
      unset current_env
    fi
    eval "$command"
  fi
  result=$?

  string=$(basename $rvm_ruby_gem_home)

	if (( result == 0 ))
	then
    eval "successes=(${successes[*]} $string)"
  else
    eval "errors=(${errors[*]} $string)"
  fi
  eval "rubies=(${rubies[*]} $string)"
  eval "statuses=(${statuses[*]} $result)"
  unset string
  rvm_hook="after_do" ; source "$rvm_scripts_path/hook"
  __rvm_unset_ruby_variables
}

# Output the summary in a human readable format.
__rvm_summary()
{
  export successes errors statuses

  summary="\nSummary:\n\n"

  if [[ ${#successes[*]} -gt 0 ]] ; then

    summary="$summary \033[0;32m${#successes[*]} successful: $(echo "${successes[*]}" | sed 's# #, #g')\033[0m\n"

  fi

  if [[ ${#errors[*]} -gt 0 ]] ; then

    summary="$summary \033[0;31m${#errors[*]} errors: $(echo "${errors[*]}" | sed 's# #, #g')\033[0m\n"

  fi

  total=${#rubies[*]}

  [[ -z "${ZSH_VERSION:-}" ]] ; array_start=$?

  printf "$summary" | tee -a log/summary.log

  return ${#errors[*]}

}

# Output the summary in a yaml format.
__rvm_yaml()
{
  export successes errors statuses

  yaml="totals:\n  rubies: ${#rubies[*]}\n  successes: ${#successes[*]}\n  errors: ${#errors[*]}\nsuccesses:"

  for var in ${successes[*]} ; do yaml="$yaml\n  - $var" ; done

  yaml="$yaml\nerrors:"

  for var in ${errors[*]} ; do yaml="$yaml\n  - $var" ; done

  yaml="$yaml\nrubies:"

  total=${#rubies[*]}

  [[ -z "${ZSH_VERSION:-}" ]] ; array_start=$?

  for (( index = $array_start ; index < $total + $array_start ; index++ )) ; do

    if [[ ${rvm_debug_flag:-0} -gt 0 ]] ; then

      rvm_debug "${rubies[$index]}: ${statuses[$index]}"

    fi

    yaml="$yaml\n  \"${rubies[$index]}\": ${statuses[$index]}"

  done ; unset index array_start

  \mkdir -p log

  printf "$yaml" | tee -a log/summary.yaml

  return ${#errors[*]}
}

# Output the summary in a json format.
__rvm_json()
{
  local index array_start

  json="{
\"totals\": { \"rubies\": ${#rubies[*]}, \"successes\": ${#successes[*]}, \"errors\": ${#errors[*]} },
\"successful\": [$(echo \"${successes[*]}\" | sed 's# #", "#g' | sed 's#\"\"##')],
\"errors\": [$(echo \"${errors[*]}\" | sed 's# #", "#g' | sed 's#\"\"##')],
\"rubies\": { "

  total=${#rubies[*]}
  [[ -z "${ZSH_VERSION:-}" ]] ; array_start=$?

  for (( index = $array_start ; index < $total + $array_start ; index++ )) ; do

    if [[ ${rvm_debug_flag:-0} -gt 0 ]] ; then

      rvm_debug "${rubies[$index]}: ${statuses[$index]}"

    fi

    json="$json\n    {\"${rubies[$index]}\": ${statuses[$index]}}"

    if (( $index + 1 < $total + $array_start )) ; then json="$json,  " ; fi

  done

  json="$json\n  }\n}"

  if [[ ! -d log ]] ; then
    mkdir -p log
  fi

  printf "$json" | tee -a log/summary.json

  return ${#errors[*]}
}

# Loop over a set or all rvm installed rubies to perform some action.
# Record the results and report based on CLI selections.

rubies=() ; successes=() ; errors=() ; statuses=()

args=($*)
action="${args[$__array_start]}"
args[$__array_start]=""
args=(${args[@]})

if [[ -z "$action" ]]
then
  rvm_error "Action must be specified."
  exit 1
fi

if [[ "$action" == "ruby" ]] && echo "$args" | \grep "^'--[^[:space:]]*'$" >/dev/null 2>&1
then
  rvm_warn "You called rvm ruby with the arguments $args which look like use options.
    Please note that 'rvm ruby' invokes set operations instead."
fi

rvm_ruby_strings=$(__rvm_expand_ruby_string "$rvm_ruby_strings")

rvm_ruby_strings=(${rvm_ruby_strings//default}) # No quotes here is intentional.

# Check for a single ruby && exec if present.
__rvm_attempt_single_exec

for current_set_ruby in ${rvm_ruby_strings[@]}
do
  __rvm_ruby_do
done

if [[ ! -z "$rvm_summary_flag" ]] ; then __rvm_summary ; fi
if [[ ! -z "$rvm_yaml_flag" ]]    ; then __rvm_yaml    ; fi
if [[ ! -z "$rvm_json_flag" ]]    ; then __rvm_json    ; fi

rvm_hook="after_do" ; source "$rvm_scripts_path/hook"

exit ${#errors[*]}
