#!/usr/bin/bash
git status >/dev/null || (echo "The current directory does not seem to be valid git repo" && exit 1)
type whiptail &>/dev/null || (echo "Missing 'whiptail' dependency" && exit 1)

BORDER=5
WIDTH=$(( $COLUMNS - $BORDER))
HEIGHT=$(( $LINES - $BORDER))
WHEIGHT=$(( $LINES - $BORDER - 8))
WIDTH_MENU=78
HEIGHT_MENU=18
WHEIGHT_MENU=$(( $HEIGHT_MENU - 8))
SMALL_WIDTH=60
SMALL_HEIGHT=8

delete_action_selection() {
	# construct the checkbox command
	CHECKBOX_CMD=""
	for b in $BRANCH_LIST; do
		[[ -z "${STATE[$b]}" ]] && STATE[$b]=0
		CHECKBOX_CMD+="$b ${STATE[$b]} "
	done

  # open the checkbox list
  TO_BE_DELETED=()
  for b in $(whiptail --title "The git xcleaner - branch selection" \
	  --separate-output --noitem \
	  --checklist  "Select branches to be deleted and be careful:" \
	  $HEIGHT $WIDTH $WHEIGHT $CHECKBOX_CMD 3>&1 1>&2 2>&3); do
	    TO_BE_DELETED+=($b)
    done

    CONFIRMED=0
    if [ ${#TO_BE_DELETED[@]} -ne 0 ]; then
	    # explicitly confirm the action
	    if (whiptail --title "The git xcleaner - delete confirmation" \
		    --yesno "Are you sure to delete selected branches (${#TO_BE_DELETED[@]})?" $SMALL_HEIGHT $SMALL_WIDTH) then
				CONFIRMED=1
	    fi
    fi
}

delete_action() {
	if [ $CONFIRMED -eq 1 ]; then
		PERCENT=$(( 100 / ${#TO_BE_DELETED[@]} ))
		GAUGE=0
		{
			for b in "${TO_BE_DELETED[@]}"; do
				eval $1 1>&2
				echo $GAUGE
				GAUGE=$(( $GAUGE + $PERCENT ))
			done
			echo 100
		} | whiptail --title "The git xcleaner - working" \
			--gauge "Deleting selected branches..." $SMALL_HEIGHT $WIDTH 0
	fi
}

action_local() {
	git branch -D $b &>>$HOME/.git-xcleaner.log
}

action_remote() {
	git push $REMOTE :${b/$REMOTE\//} &>>$HOME/.git-xcleaner.log
}

while true; do

	ACTIVE_BRANCH=$(git rev-parse --abbrev-ref HEAD)

  # hash with preselect state (0/1)
  BRANCH_LIST=$(git branch | sed -E 's/^\*?\s*//' | sort)
  declare -A STATE; STATE=()

  # load all branch names
  for b in $BRANCH_LIST; do
	  STATE[$b]=0
  done

  ACTION=$(whiptail --title "The git xcleaner - main menu" --cancel-button "Help" --default-item "Exit" \
	  --menu "Select action. This is safe, review on the next screen." $HEIGHT_MENU $WIDTH_MENU $WHEIGHT_MENU \
	  "Merged" "Delete merged branches (--merged)" \
	  "Messages" "Delete (rebased) branches with the same commit messages" \
	  "Pruned" "Delete pruned branches (deleted tracking branches)" \
	  "Manual" "Interactive manual deletion" \
	  "Exit" "Return to shell" \
	  "Help" "Show help" \
	  3>&1 1>&2 2>&3)
	    #"Prune" "Delete stale remote-tracking branches" \

	    case $ACTION in
		    Manual)
			    delete_action_selection
			    delete_action action_local
			    ;;

		    Merged)
			    # checkout base branch
			    BASE=$(whiptail --title "The git xcleaner - branch to search" \
				    --inputbox "Base branch:" $HEIGHT $WIDTH master 3>&1 1>&2 2>&3)

      # preselect merged branch names
      for b in $(git branch --merged $BASE | sed -E 's/^\*?\s*//' | sort); do
	      [ "x$b" != "x$BASE" ] && STATE[$b]=1
      done

      delete_action_selection
      delete_action action_local
      ;;

Pruned)
	# preselect pruned branches (must do git fetch --prune prior this)
	for b in $(git for-each-ref --format '%(refname:short) %(upstream:track)' refs/heads | grep '\[gone\]' | awk '{ print $1 }' | sort); do
		[ "x$b" != "x$ACTIVE_BRANCH" ] && STATE[$b]=1
	done

	delete_action_selection
	delete_action action_local
	;;

Messages)
	# checkout base branch
	BASE=$(whiptail --title "The git xcleaner - branch to search" \
		--inputbox "Base branch:" $HEIGHT $WIDTH master 3>&1 1>&2 2>&3)
			git checkout $BASE &>/dev/null || exit 1

      # search commit messages and preselect branches
      for b in "${!STATE[@]}"; do
	      last_commit_msg="$(git log --oneline --format=%f -1 $b)"
	      if [[ "$(git log --oneline --format=%f | grep "$last_commit_msg" | wc -l)" -eq 1 ]]; then
		      [ "x$b" != "x$ACTIVE_BRANCH" ] && STATE[$b]=1
	      fi
      done

      delete_action_selection
      delete_action action_local
      ;;

Exit)
	exit 0
	;;
*)
	HELP_TEXT=/usr/share/doc/git-xcleaner/git-xcleaner.1.txt
	if [ -f $HELP_TEXT ]; then
		whiptail --title "The git xcleaner - help" --textbox $HELP_TEXT $HEIGHT $WIDTH
	else
		whiptail --title "The git xcleaner - help" --infobox "Help not available - use packaged version" $HEIGHT $WIDTH
	fi
	;;
esac
done
