#!/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 " "
}
usage() {
cat <<EOF
usage: git conflict <commit>
   or: git conflict --continue | --abort
   or: git conflict -l
EOF
exit
}

gitDir=$(git rev-parse --git-dir)
conflictName="${gitDir}/CONFLICT_NAME"
mergeHead="${gitDir}/MERGE_HEAD"

cleanup () {
	rm $conflictName $mergeHead &> /dev/null
}

case "$1" in
    --continue)
		[ ! -f $conflictName ] && die "There is no resolution ongoing."

		[ -z "$(git ls-files --unmerged)" ]  || die "All conflicts must be resolved"
		# if all conflicts are resolved ...
		tree=$(git write-tree)
		commit=$(git commit-tree $tree -m "resolution between $(git symbolic-ref -q HEAD || git rev-parse HEAD) and $(cat $mergeHead)" -p HEAD -p $(cat $mergeHead))
		conflictRef="refs/conflicts/$(cat $conflictName)"
		git update-ref "$conflictRef" "$commit" "" &> /dev/null || 
			die "Resolution $conflictRef already exists. "\
			"If you want to override it, delete it first :${LF}git update-ref -d $conflictRef"
		echo "Conflict resolution created: $conflictRef" 
		cleanup
		git reset -q --hard
    ;;
    --abort)
		git reset --merge
		cleanup
		exit 0
    ;;
    -*)
    	while getopts "lh" opt; do
	  		case "$opt" in
	    		l)
	      			git ls-remote . refs/conflicts/*
	      		;;
	    		h)
					usage
				;;
				\?)
					exit 1
				;;
			esac
		done
    ;;
    *)
		remote=$1
		git show-ref -q "$remote" || die "Ref not found : $remote"

		[ -f $conflictName ] && die "You are in the middle of a resolution"

		[[ -n $(git diff-index HEAD) ]] && die "The repository has to be clean"

	    echo $(git rev-parse $remote) > $mergeHead

	    common=$(git merge-base --all $remote HEAD)

	    git read-tree -u -m --aggressive $common HEAD $remote
	    
	    git-merge-index -o git-merge-one-file -a 2> /dev/null

	    if test $? -eq 0 ; then
			git reset -q --hard
			echo "No conflict with $remote"
			cleanup
			exit 0
		fi

	    hash-conflict > $conflictName
	;;
esac