#!/bin/bash
LF='
'
die () {
    echo >&2 "$*"
    exit 1
}
cat-UU-conflict() {
	leftContent=
	rightContent=
	reading="base"

	while read l ; do
		[[ $l == \<\<\<\<\<\<\<* ]] && reading="left" && continue
		[[ $l == \=\=\=\=\=\=\=* ]] && reading="right" && continue
		[[ $l == \>\>\>\>\>\>\>* ]] && reading="base" && continue

		case $reading in
			"base")
			;;
			"left")
				leftContent+="$l$LF"
			;;
			"right")
				rightContent+="$l$LF"
			;;
		esac
	done < "$1"

	conflictContent=
	if ! $ordered && [ "$leftContent" \< "$rightContent" ] ; then
		conflictContent="$leftContent$LF$rightContent"
	else
		conflictContent="$rightContent$LF$leftContent"
	fi

	echo "$conflictContent"
}

hash-conflict () {
	#	-o         Make the order between left and right side matters.
	#	-i <file>  Read <file> instead of conflicting paths in the index  
	ordered=false
	file=
	while getopts "oi:h" opt; do
		case "$opt" in
		h)
			usage
			return 0
		;;
		o)
			ordered=true
		;;
		i)
			file=$OPTARG
		;;
		*)
			usage
			return 1
		;;
		esac
	done

	conflictContent=

	while read status ; do
		state=$(echo $status | awk '{print $1;}')
		path=$(echo $status | awk '{print $2;}')
		case $state in
		    "UU")
				conflictContent+="$(cat-UU-conflict $path)$LF"
			;;
	    esac
	done <<< "$(if [ -z "$file" ] ; then echo "$(git status --porcelain | grep "^U.\|^.U\|^AA\|^DD" | awk -v cdup="$(git rev-parse --show-cdup)" '{print $1" "cdup$2;}')" ; else echo "UU $file" ; fi)"

	echo "$conflictContent" | shasum | cut -f 1 -d " "
}
#Resolve conflicts marked in the index. Files in conflict must have been merged already with git-merge-index
usage() {
cat <<EOF
usage: git apply-conflict-resolution
   or: git apply-conflict-resolution <conflictName>
EOF
exit
}

[ "$1" == "-h" ] && usage

conflictName=

if [ "$1" ] ; then
	git show-ref -q --verify "refs/conflicts/$1" || die "Ref not found: refs/conflicts/$1"
	conflictName=$1 
else
	#Reading from the index
	conflictName=$(hash-conflict)

	git show-ref -q --verify "refs/conflicts/$conflictName" || exit 1
fi

echo "Applying conflict resolution $conflictName"

resolutionCommit=$(git rev-parse "refs/conflicts/$conflictName")
leftParent=$(git rev-parse ${resolutionCommit}^1)
rightParent=$(git rev-parse ${resolutionCommit}^2)
commonAncestor=$(git merge-base $leftParent $rightParent)

cdup="$(git rev-parse --show-cdup)"

SUCCESS=true

while read status ; do
	state=$(echo $status | awk '{print $1;}')
	path=$(echo $status | awk '{print $2;}')
	path="$cdup$path"
	case $state in
	    "UU")
			# Clean conflict markers
			perl -pi -e "s/<<<<<<<.*/<<<<<<< /g" $path
			perl -pi -e "s/>>>>>>>.*/>>>>>>> /g" $path

			# Store the current preimage
			current_preimage="$cdup$(git unpack-file $(git hash-object -w $path))"

			# Compute the preimage as it was when the resolution was recorded
			leftFile="$cdup$(git unpack-file $(git ls-tree $leftParent $path | awk '{print $3;}'))"
			rightFile="$cdup$(git unpack-file $(git ls-tree $rightParent $path | awk '{print $3;}'))"
			ancestorFile="$cdup$(git unpack-file $(git ls-tree $commonAncestor $path | awk '{print $3;}'))"
			
			# TODO mettre dans un tmp
			recorded_preimage="$cdup$(git unpack-file $(git merge-file -L "" -L "" -L "" --stdout $leftFile $ancestorFile $rightFile | git hash-object --stdin -w))"

			if [ "$(hash-conflict -o -i $current_preimage)" != "$(hash-conflict -o -i $recorded_preimage)" ] ; then
				rm $recorded_preimage
				recorded_preimage="$cdup$(git unpack-file $(git merge-file -L "" -L "" -L "" --stdout $rightFile $ancestorFile $leftFile | git hash-object --stdin -w))"
			fi

			# Do the final merge between the initial conflict, the current conflict and the resolution
			# This is based on what is done in rerere.c
			resolutonFile="$cdup$(git unpack-file $(git ls-tree $resolutionCommit $path | awk '{print $3;}'))"

			git merge-file --stdout $current_preimage $recorded_preimage $resolutonFile > $path \
				&& git update-index --add $path \
				|| SUCCESS=false

			rm $current_preimage $leftFile $rightFile $ancestorFile $recorded_preimage $resolutonFile

		;;
    esac
done <<< "$(git status --porcelain | grep "^U.\|^.U\|^AA\|^DD")"

if ! $SUCCESS ; then die "Conflict not resolved" ; fi
