#!/bin/bash

export GIT_DIR=$(git rev-parse --git-dir)
export SEQUENCER_VERSION=1.3

USE_COLOR=0
if [ -t 1 ]; then
	USE_COLOR=1
fi

usage()
{
	local errCode=$1
	echo -e "Usage: $(basename $0) [OPTS]"
	echo -e "\t--[no-]color     Force color to be enabled/disabled"
	echo -e "\t-v,--version     Diplay version information"
	echo -e "\t-h,--help        Diplay usage"
	exit $errCode
}


while [ $# -gt 0 ]; do
	ARG=$1
	shift
	case "$ARG" in
		--color)
			USE_COLOR=1
			;;
		--no-color)
			USE_COLOR=0
			;;
		-v|--version)
			echo "git-sequencer-status $SEQUENCER_VERSION"
			exit 0
			;;
		-h|--help)
			usage 0
			;;
		*)
			echo "ERROR: Invalid option $ARG" >&2
			usage 1
			;;
	esac
done

if [ $USE_COLOR -eq 1 ]; then
	export YELLOW_NODIM='\033[00;33m'
	export RED_NODIM='\033[00;31m'
	export RED_DIM='\033[02;31m'
	export CYAN_BOLD='\033[01;36m'
	export WHITE='\033[00m'
	export COLOR_OPT="--color"
else
	export COLOR_OPT="--no-color"
fi

__git_log()
{
	git --no-pager log $COLOR_OPT "$@"
}

___colorize()
{
   local C0=$1
   local C1=$2
   local C2=$3

   awk  -vC0=$C0 -vC1=$C1 -vC2=$C2 \
        '
{
    if ($1 == "exec") {
        printf( C0 "%-7s " C2, $1);
        for (i = 2; i < NF; i++) {
            printf("%s ", $i);
        };
        printf("%s\n", $NF);
    } else {
        printf( C0 "%-7s " C1 $2 " " C2, $1);
        for (i = 3; i < NF; i++) {
            printf("%s ", $i);
        };
        printf("%s\n", $NF);
    }
}'
}

__colorize_todo()
{
	___colorize $YELLOW_NODIM $RED_NODIM $WHITE
}

__git_log_todo()
{
	__git_log --format='%C(auto,yellow nodim)pick    %C(auto,red nodim)%h %C(auto,white)%s' $*
}
__colorize_current()
{
	___colorize $CYAN_BOLD $RED_NODIM $WHITE
}
__git_log_current_unmerged()
{
	__git_log --format='%C(auto,cyan bold)*pick   %C(auto,red nodim)%h %C(auto,white)%s'  $*
}
__git_log_current()
{
	__git_log --format='%C(auto,cyan bold)pick    %C(auto,red nodim)%h %C(auto,white)%s' $*
}

__colorize_done()
{
	___colorize $RED_DIM $RED_NODIM $WHITE
}
__git_log_done()
{
	__git_log --format='%C(auto,red dim)done    %C(auto,red nodim)%h %C(auto,white)%s' $*
}

__git_log_onto()
{
	__git_log -n 1 --format='%C(auto,red dim)onto    %C(auto,red nodim)%h %C(auto,white)%s' $*

}
__has_unmerged()
{
	git ls-files --unmerged | wc -l
}

__sha1_to_refname()
{
	local ONTO=$1

	if [ $# -gt 1 ]; then
		git name-rev --name-only --no-undefined ${ONTO} --refs $2 2> /dev/null
		if [ $? -eq 0 ]; then
			return
		fi
	fi
	git name-rev --name-only --no-undefined ${ONTO} --refs refs/heads/*
}

__sanitize()
{
	while read line; do
		ACTION=$(echo "$line" | awk '{ print $1}')
		if [ "$ACTION" != "exec" ]; then
			SHA1=$(echo "$line" | awk '{ print $2}')
			SHORT_SHA1=$(git log -n 1 ${SHA1} --format='%h')
			SUBJECT=$(echo "$line" | awk '{ for (i = 3; i <= NF; i++) { printf("%s ", $i);}; printf("\n");}')
			echo "${ACTION} ${SHORT_SHA1} ${SUBJECT}"
		else
			echo $line
		fi
	done
}


#
# Dump status for cherry-pick and revert series
#
__simple_sequence()
{
	local BASE=$(cat ${GIT_DIR}/sequencer/head)
	local BASE_NICE=$(__sha1_to_refname ${BASE})
	local N_LINES=$(wc -l ${GIT_DIR}/sequencer/todo | awk '{ print $1}')
	echo "# " $*

	tac ${GIT_DIR}/sequencer/todo | head -n $(( $N_LINES - 1 ))  | __sanitize | __colorize_todo

	if [ $(__has_unmerged) != "0" ]; then
		(echo -n '*'; head -n 1 ${GIT_DIR}/sequencer/todo) | __sanitize | __colorize_current
	else
		head -n 1 ${GIT_DIR}/sequencer/todo | __sanitize | __colorize_current
	fi

	__git_log_done HEAD ^${BASE}
	__git_log_onto ${BASE}
}

#
# Status for a single cherry-pick or revert
#
__simple_action()
{
	local HEADFILE=$1
	local ACTION=$2
	local BASE=$(git rev-parse HEAD)
	local COMMIT=$(cat ${GIT_DIR}/$HEADFILE)
	shift 2
	echo "# " $* " a single commit"
	echo "*$ACTION $(__git_log  --format='%h %s' -n 1 $COMMIT)" | __colorize_current
	__git_log_onto ${BASE}
}

__rebase_merge_sequence()
{
	local BASE=$(cat ${GIT_DIR}/rebase-merge/head-name)
	local ONTO=$(cat ${GIT_DIR}/rebase-merge/onto)
	local BASE_NICE=$(echo ${BASE} | sed -e 'sL^refs/heads/LL')
	local ONTO_NICE=$(__sha1_to_refname ${ONTO} ${BASE})
	local CURRENT=$(tail -n 1 ${GIT_DIR}/rebase-merge/done)

	echo "# Rebase: ${BASE_NICE} onto ${ONTO_NICE}"
	tac ${GIT_DIR}/rebase-merge/git-rebase-todo | egrep -v '^#' | \
		egrep -v '^$' | __sanitize |__colorize_todo

	if [ $(__has_unmerged) != "0" ]; then
		echo "*$CURRENT" |  __sanitize | __colorize_current
	else
		echo "$CURRENT" | __sanitize |  __colorize_current
	fi

	tac ${GIT_DIR}/rebase-merge/done | tail -n +2 | __sanitize | __colorize_done
	__git_log_onto ${ONTO}
}

__rebase_apply_sequence()
{
	local BASE=$(cat ${GIT_DIR}/rebase-apply/head-name)
	local ONTO=$(cat ${GIT_DIR}/rebase-apply/onto)
	local BASE_NICE=$(echo ${BASE} | sed -e 'sL^refs/heads/LL')
	local ONTO_NICE=$(__sha1_to_refname ${ONTO} ${BASE})
	local UNAPPLIED=1
	local NEXT=$(cat ${GIT_DIR}/rebase-apply/next)

	echo "# Rebase: ${BASE_NICE} onto ${ONTO_NICE}"

	for FILE in $(ls -r ${GIT_DIR}/rebase-apply/[0-9]*); do
		local NUM=$(basename $FILE | sed -e 's/^0*//')
		local SHA1=$(head -n 1 $FILE  | awk '{ print $2 }')

		if [ "$NUM"  == "$NEXT" ]; then
			UNAPPLIED=0
			if [ $(__has_unmerged) != "0" ]; then
				__git_log_current_unmerged -n 1 ${SHA1}
			else
				__git_log_current -n 1  ${SHA1}
			fi
		elif [ $UNAPPLIED -eq 0 ]; then
			__git_log_done -n 1 ${SHA1}
		else
			__git_log_todo -n 1 ${SHA1}
		fi
	done
	__git_log_onto $(cat ${GIT_DIR}/rebase-apply/abort-safety)
}
__am_apply_sequence()
{
	local BASE=$(cat ${GIT_DIR}/rebase-apply/abort-safety)
	local UNAPPLIED=1
	local NEXT=$(cat ${GIT_DIR}/rebase-apply/next)

	echo "# Applying patches"

	for FILE in $(ls -r ${GIT_DIR}/rebase-apply/[0-9]*); do
		local PATCH_ID=$(basename $FILE)
		local NUM=$(echo $PATCH_ID | sed -e 's/^0*//')
		local SUBJECT=$(egrep '^Subject:' $FILE | head -n 1 |\
					sed -e 's/Subject:[[:space:]]*\(\[[^]]*\][[:space:]]*\)*//')

		if [ "$NUM"  == "$NEXT" ]; then
			UNAPPLIED=0
			if [ $(__has_unmerged) != "0" ]; then
				echo "pick ${PATCH_ID} ${SUBJECT}" | __colorize_current
			else
				echo "done ${PATCH_ID} ${SUBJECT}" | __colorize_current
			fi
		elif [ $UNAPPLIED -eq 0 ]; then
			echo "done ${PATCH_ID} ${SUBJECT}" | __colorize_done
		else
			echo "pick ${PATCH_ID} ${SUBJECT}" | __colorize_todo
		fi
	done
	__git_log_onto ${BASE}
}

if [ "$LESS" == "" ]; then
	export LESS="FRX"
fi
if [ "$LV" == "" ]; then
	export LV="-c"
fi

if [ "$GIT_PAGER" != "" ]; then
	PAGER=$GIT_PAGER
else
	GIT_CONFIG_PAGER=$(git config core.pager)
	if [ $? -eq 0 ]; then
		PAGER=$GIT_CONFIG_PAGER
	else
		if [ "$PAGER" == "" ]; then
			PAGER="less"
		else
			# Keep pager at its current value
			true
		fi
	fi
fi

(
if [ -d ${GIT_DIR}/rebase-merge ]; then
	__rebase_merge_sequence
elif [ -f ${GIT_DIR}/CHERRY_PICK_HEAD ]; then
	if [ -d ${GIT_DIR}/sequencer ]; then
		__simple_sequence "Cherry picking"
	else
		__simple_action CHERRY_PICK_HEAD pick "Cherry picking"
	fi
elif  [ -d ${GIT_DIR}/rebase-apply ]; then
	if [ -f ${GIT_DIR}/rebase-apply/applying ]; then
		__am_apply_sequence
	else
		__rebase_apply_sequence
	fi
elif [ -f ${GIT_DIR}/REVERT_HEAD ]; then
	if [ -d ${GIT_DIR}/sequencer ]; then
		__simple_sequence "Reverting"
	else
		__simple_action REVERT_HEAD revert "Reverting"
	fi
fi) | ${PAGER}
