#!/usr/bin/env bash

tmp=$(git_extra_mktemp)
above=0
color=

#
# get dates for the given <commit>
#
dates() {
  eval "git log --pretty='format: %ad' --date=short $args_to_git_log \"$1\""
}

#
# hide cursor
#

hide_cursor() {
  printf '\033[?25l'
}

#
# show cursor, and remove temporary file
#

show_cursor_and_cleanup() {
  printf '\033[?25h'
  printf '\033[m\n'
  rm "$tmp" > /dev/null 2>&1
  exit 0
}

#
# get active days for the given <commit>
#

active_days() {
  uniq <<<$(echo "$1") | wc -l
}

#
# set 'color' based on the given <num>
#

color_for() {
  test $1 -gt 10 && color='33'
  test $1 -gt 25 && color='33;1'
  test $1 -gt 50 && color='93'
  test $1 -gt 75 && color='93;1'
  test $1 -gt 100 && color='31'
  test $1 -gt 125 && color='31;1'
  test $1 -gt 150 && color='91'
  test $1 -gt 200 && color='91;1'
}

#
# compute the effort of the given <file ...>
#

effort() {
    file=$1
    local commit_dates
    commit_dates=`dates "$file"`
    [ $? -gt 0 ] && exit 255

    # Ensure it's not just an empty line
    if [ -z "`head -c 1 <<<$(echo $commit_dates)`" ]
    then
      exit 0
    fi

    commits=`wc -l <<<"$(echo "$commit_dates")"`
    color='90'

    # ignore <= --above
    test $commits -le $above && exit 0

    # commits
    color_for $(( $commits - $above ))
    len=${#file}
    dot="."
    f_dot="$file"
    i=0 ; while test $i -lt $((45-$len)) ; do
      f_dot=$f_dot$dot
      i=$(($i+1))
    done

    msg=$(printf "  \033[${color}m%s %-10d" "$f_dot" $commits)

    # active days
    active=`active_days "$commit_dates"`
    color_for $(( $active - $above ))
    msg="$msg $(printf "\033[${color}m %d\033[0m\n" $active)"
    echo "$msg"
}

#
# print heading
#

heading() {
  echo
  printf "  %-45s %-10s %s\n" 'file' 'commits' 'active days'
  echo
}

#
# output sorted results
#

sort_effort() {
  clear
  echo
  heading
  < $tmp sort -rn -k 2
}

above_index=0
has_above=false
next_is_above=false
num_files=0

# Some implementations of `seq` gives "1\n0" for seq 0
if [ $# -gt 0 ] ; then
  for i in `seq ${#@}`
  do
    cur="${!i}"

    if "$next_is_above" ; then
      above="$cur"
      next_is_above=false
      continue
    fi

    case "$cur" in
      --above)
              if "$has_above" ; then
                echo "error: --above can only be specified one time" 1>&2
                exit 1
              fi
              next_is_above=true
              has_above=true
              above_index=$(( i - 1 ))
              ;;
          --*)
              ;;
            *)
              num_files=$(( num_files + 1 ))
              ;;
    esac
  done
fi

# Exit if above-value is not an int
if [ -z "${above##*[!0-9]*}" ] ; then
  echo "error: argument to --above was not an integer" 1>&2
  exit 1
fi

args_before_above=`printf " %q" "${@:1:$above_index}"`

num_args=$(( i - num_files ))
if $has_above ; then offset=2 ; else offset=0 ; fi
from=$(( 1 + above_index + offset ))
len=$(( num_args - $(( above_index + offset)) ))
args_after_above=`printf " %q" "${@:$from:$len}"`

args_to_git_log="${args_before_above#\ \'\'}${args_after_above#\ \'\'}"

shift $num_args

export args_to_git_log

# [file ...]

declare -a files=()
if test $# -ge 1; then
  files=("$@")
else
  save_ifs=$IFS
  IFS=`echo -en "\n\b"`
  files=(`git ls-files`)
  IFS=$safe_ifs
  unset save_ifs
fi

# hide cursor

hide_cursor
trap show_cursor_and_cleanup INT

# export functions so subshells can call them
export -f effort
export -f color_for
export -f active_days
export -f dates
export above
export log_args


bash_params=
# If bash exits sucessfully with --import-functions,
# then we need to pass it (FreeBSD probably)
bash --import-functions -c ":" 1>/dev/null 2>&1
if [ $? -eq 0 ] ; then
  bash_params="--import-functions"
fi

heading
# send files to effort
printf "%s\0" "${files[@]}" | xargs -0 -n 1 -P 4 -I % bash $bash_params -c "effort \"%\"" | tee $tmp

# if more than one file, sort and print
test "$(wc -l $tmp | awk '{print $1}')" -gt 1 && sort_effort
echo

show_cursor_and_cleanup
