#!/bin/bash
###########################################################################
# reverts changesets for a set of tickets from a branch
###########################################################################
# $1    = name of branch
# $2    = ticket prefix
# $3    = message suffix
# $4... = ticket ids whose changesets are to be moved
###########################################################################
# the mapping of branch names to file system paths is done in
# ~/.fli4l/repo-info
###########################################################################

rootdir=${0%/*}
allowed_options="-q --no-merge-details"
# if non-empty, a clean target branch is required
clean_before_merge=1
# by default, provide details for merge commits
mergedetails=1

if [ "$(type -t usage)" != "function" ]
then
	usage()
	{
		echo "Usage: $(basename $0) [-q] <branch-name> <ticket-prefix> <message-suffix> <ticket-id>+"
		exit 1
	}
fi

. "$rootdir/include/config.inc"
. "$rootdir/include/options.inc"
. "$rootdir/include/display.inc"
. "$rootdir/include/utility.inc"
. "$rootdir/include/cleanup.inc"
. "$rootdir/include/svn.inc"
. "$rootdir/include/repo-info.inc"
. "$rootdir/include/branching.inc"
. "$rootdir/include/ticket.inc"

case $1 in
-*)
	warning "Unknown option: $1"
	usage
	;;
esac

has_option "--continue-merge" && clean_before_merge=
has_option "--no-merge-details" && mergedetails=

if [ $# -lt 4 ]
then
	usage
fi

[ -n "$1" ] || error "Branch name is missing"
[ -n "$2" ] || error "Ticket prefix is missing"

branch="$1"
prefix="$2"
msgsfx="$3"
shift 3

message "Loading repository information" standout
load_repo_info

message "Initializing local branch" standout
init_local_branch "$branch" $clean_before_merge

allrevs=$(get_revs "$branch")

revmin=$(($(echo "$allrevs" | tail -n 1)+1))
[ -n "$revmin" ] || error "Computing minimum revision of $branch failed"

revmax=$(get_head_rev "$branch")
[ -n "$revmax" ] || error "Computing maximum revision of $branch failed"

round=1
revs=
tickets="$(prepend_prefix "$(mask_for_regex "$@")" "$prefix")"
old_tickets=""

while [ -n "$tickets" -a "$(sort_list "$old_tickets")" != "$(sort_list "$tickets")" ]
do
	message "Determining changesets to be unmerged (round $round)" standout
	old_tickets="$tickets"
	stop_tickets="$tickets"
	tickets=""

	while [ -n "$stop_tickets" ] && read rev
	do
		msg=$(get_log_message "$branch" $rev | head -n 1)
		ok=
		for ticket in $stop_tickets
		do
			if echo "$msg" | grep -q "^MERGE .*\<$ticket\>"
			then
				for t in $(extract_tickets "$msg" "$prefix")
				do
					echo "$tickets" | grep -q "\<$t\>" ||
						tickets+="$t "
				done
				ok=1
				break
			elif echo "$msg" | grep -q "^UNMERGE .*\<$ticket\>"
			then
				for t in $(extract_tickets "$msg" "$prefix")
				do
					stop_tickets=$(remove_ticket "$stop_tickets" $t)
				done
				break
			fi
		done
		if [ -n "$ok" ]
		then
			if ! echo "$revs" | grep -q "\<$rev\>"
			then
				revs+="$rev "
				print_log_messages "$branch" $rev $mergedetails
			fi
		fi
	done <<< "$allrevs"

	round=$((round+1))
	tickets="${tickets% }"
done

revs=$(echo "-$revs" | $SED -e 's/[[:space:]]*$//;s/[[:space:]]\+/,-/g')

if [ -n "$tickets" ]
then
	message "Tickets to be considered:" standout
	for t in $tickets
	do
		message "  $t: " -n
		message "$(get_ticket_title "$t")" yellow
	done

	message "Please review and press Ctrl+C to abort or RETURN to continue..." -n standout
	read

	message "Unmerging changesets for $tickets from $branch" standout
	push_cleanup clean_branch_if_enabled "$branch"
	if ! do_svn_quiet merge --diff3-cmd /usr/bin/diff3 -c $revs --accept postpone \
		"$remote_root/$branch" "$local_root/$branch"
	then
		error "Error encountered while unmerging${part_message} -- possibly a text/binary diff conflict!"
	fi

	conflicts=$(get_merge_conflicts "$branch")
	if [ -n "$conflicts" ]
	then
		analyse_conflicts "$branch" "$branch" "$conflicts" "$allrevs" "$(echo "$revs" | $SED 's/[-,]/ /g')" min_rev -lt "$prefix"
		error "Conflict(s) encountered while merging"
	fi

	message "Building commit message" standout
	msg="UNMERGE $tickets${msgsfx:+ $msgsfx}
  (from /$branch)"
	for rev in ${revs//,/ }
	do
		msg+="
$(print_log_messages "$branch" ${rev#-} 1 nocolor)"
	done

	message "Committing unmerge result into $branch" standout
	do_svn_quiet commit -m "$msg" "$local_root/$branch" ||
		svn_error "Committing unmerge result into $branch failed"

	do_message "Success: $tickets unmerged from $branch, commit [$(_get_head_rev "$remote_root/$branch")]" green
	pop_cleanup
else
	message "No changesets for specified tickets found" green
fi