#!/usr/bin/env bash

showhelp() {
cat<<EOF
Usage: gitmail [option ...] -m recipient[,...] [-cc recipient[,...]]

Options:

    -from address       The "From" field in the message header.

    -sendmail command   The command for sending mail.

    -sign command       The command for signing the mail.

    -ct times           Commit times, default 1.

    -genpatch command   The command for generating patch for reviewing. The
                        default genpatch command is:
                        "git diff HEAD^<commit_time> HEAD"

    -genlog command     The command for generating log for reviewing. The
                        default genlog command is:
                        "git log -<commit_time>"

    -stat command       The command for getting file modification time. The
                        default stat command for Linux is:
                        "stat -c %y"

    --help, -h          Show this message.
EOF
}

# Avoid localized messages.
LANG=C
LANGUAGE=C
LC_CTYPE="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_COLLATE="C"
LC_MONETARY="C"
LC_MESSAGES="C"
LC_PAPER="C"
LC_NAME="C"
LC_ADDRESS="C"
LC_TELEPHONE="C"
LC_MEASUREMENT="C"
LC_IDENTIFICATION="C"
LC_ALL=

target_dir=`pwd`
while [[ ! -f "$target_dir/.gitmail" && "$target_dir" != "/" ]];
do
  target_dir=`dirname "$target_dir"`
done

if [ -f "$target_dir/.gitmail" ]; then
  . "$target_dir/.gitmail"
fi

commit_time=1

# Parse the command line.
state=0
for i in "$@"
do
  case $state in
  0 )
    case "$i" in
    -cc )
      state=1
      ;;
    -m )
      state=2
      ;;
    -from )
      state=3
      ;;
    -sendmail )
      state=4
      ;;
    -sign )
      state=5
      ;;
    -genpatch )
      state=6
      ;;
    -genlog )
      state=7
      ;;
    -stat )
      state=8
      ;;
    -ct )
      state=9
      ;;
    --help | -h )
      showhelp
      exit 0
      ;;
    esac
    ;;
  1 )
    if [ "$cc" = "" ]; then
      cc="$i"
    else
      cc="$cc,$i"
    fi
    state=0
    ;;
  2 )
    if [ "$m" = "" ]; then
      m="$i"
    else
      m="$m,$i"
    fi
    state=0
    ;;
  3 )
    from="$i"
    state=0
    ;;
  4 )
    sendmail="$i"
    state=0
    ;;
  5 )
    sign="$i"
    state=0
    ;;
  6 )
    genpatch="$i"
    state=0
    ;;
  7 )
    genlog="$i"
    state=0
    ;;
  8 )
    stat="$i"
    state=0
    ;;
  9 )
    commit_time="$i"
    state=0
    ;;
  esac
done

target_dir=`pwd`
while [[ ! -d "$target_dir/.git" && "$target_dir" != "/" ]];
do
  target_dir=`dirname "$target_dir"`
done

if [ ! -d "$target_dir/.git" ]; then
  echo "Not a working directory."
  exit 1
fi

while [ "$m" = "" ];
do
  read -p "Please enter the reviewer's id: " m
done

if [ "$default_host" = "" ];  then
  default_host="gmail.com"
fi

if [ "$stat" = "" ]; then
  stat="stat -c \"%y\""
fi

if [ "$sendmail" = "" ]; then
  sendmail="sendmail -t"
fi

if [ "$from" = "" ]; then
  from=$USER
fi

if [ "$genpatch" = "" ]; then
  genpatch="git diff HEAD~$commit_time HEAD"
fi

if [ "$genlog" = "" ]; then
  genlog="git log -$commit_time"
fi

if [ "$VISUAL" != "" ]; then
  editor="$VISUAL"
elif [ "$EDITOR" != "" ]; then
  editor="$EDITOR"
else
  editor=vi
fi

delta=$($genpatch | \
    grep '\(^-\|^+\)[^-+]' | \
    wc -l)

size="A lice-sized"
if [ "$delta" -gt 50 ]; then
  size="A cockroach-sized"
fi
if [ "$delta" -gt 100 ]; then
  size="A rat-sized"
fi
if [ "$delta" -gt 150 ]; then
  size="A snake-sized"
fi
if [ "$delta" -gt 250 ]; then
  size="A hog-sized"
fi
if [ "$delta" -gt 400 ]; then
  size="A kangaroo-sized"
fi
if [ "$delta" -gt 650 ]; then
  size="An elephant-sized"
fi
if [ "$delta" -gt 1050 ]; then
  size="A whale-sized"
fi
if [ "$delta" -gt 1700 ]; then
  size="An unknown-size"
fi

subject="$size code review ($USER `date +'%Y-%m-%d %H:%M:%S'`)"

# Append default host name to receiptors without host name
m=`echo $m | sed -e "s/ *\(,\|$\)/@$default_host\1/g;s/\(@[^@,]*\)@[^@,]*/\1/g"`
# Generate the mail.
tempfile=`mktemp /tmp/gitmail.XXXXXXX`
cat<<EOF > "$tempfile"
From: $from
To: $m
Cc: $cc
Bcc: $from
Subject: $subject

Hello `echo $m | sed -e 's/@[^,]*//g' -e 's/,/, /g'`,

EOF

cat<<EOF >> "$tempfile"
I'd like you to do a code review. Please review the following patch:

EOF

$genlog >> "$tempfile"
echo >> "$tempfile"
$genpatch >> "$tempfile"

cat<<EOF >> "$tempfile"

This is a semiautomated message from "gitmail".  Complaints or suggestions?
Mail edyfox@gmail.com.
EOF

cont="yes"
while [ "$cont" = "yes" ];
do
  oldtime=`$stat $tempfile`
  $editor $tempfile
  newtime=`$stat $tempfile`
  if [ "$oldtime" = "$newtime" ]; then
cat <<EOF
Log message unchanged or not specified"
a)bort, c)ontinue, e)dit
EOF
    read choice
    case $choice in
    a )
      cont="no"
      rm -f $tempfile
      exit 1
      ;;
    c )
      cont="no"
      ;;
    * )
      cont="yes"
      ;;
    esac
  else
    cont="no"
  fi
done

if [ "$sign" != "" ]; then
  sed '/^$/,$d' < $tempfile > $tempfile.signed
  echo >> $tempfile.signed
  sed '0,/^$/d' < $tempfile | $sign >> $tempfile.signed
  $sendmail < $tempfile.signed
  rm $tempfile.signed
else
  $sendmail < $tempfile
fi
rm -f $tempfile
