#
# HubFlow - a fork of the git-flow tools to apply Vincent Driessen's
# branching model to working with GitHub
#
# Original blog post presenting this model is found at:
#    http://nvie.com/git-model
#
# The HubFlow documentation is found at:
#    http://datasift.github.com/gitflow/
#
# Feel free to contribute to this project at:
#    http://github.com/datasift/gitflow
#
# Copyright 2010 Vincent Driessen. All rights reserved.
# Copyright 2012 MediaSift Ltd. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#    1. Redistributions of source code must retain the above copyright notice,
#       this list of conditions and the following disclaimer.
#
#    2. Redistributions in binary form must reproduce the above copyright
#       notice, this list of conditions and the following disclaimer in the
#       documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY VINCENT DRIESSEN ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
# EVENT SHALL VINCENT DRIESSEN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and documentation are
# those of the authors and should not be interpreted as representing official
# policies, either expressed or implied, of Vincent Driessen.
#

usage() {
	echo "usage: git hf init [-af]"
}

parse_args() {
	# parse options
	FLAGS "$@" || exit $?
	eval set -- "${FLAGS_ARGV}"
}

# Default entry when no SUBACTION is given
cmd_default() {
	DEFINE_boolean force false 'force setting of hubflow branches, even if already configured' f
	DEFINE_boolean ask false 'ask for branch naming conventions' a
	parse_args "$@"

	if ! git rev-parse --git-dir >/dev/null 2>&1; then
		git init
	else
		# assure that we are not working in a repo with local changes
		git_repo_is_headless || require_clean_working_tree
	fi

	# running git hf init on an already initialized repo is fine
	if hubflow_is_initialized && ! flag force; then
		warn "Already initialized for hubflow."
		warn "To force reinitialization, use: git hf init -f"
		exit 0
	fi

	local branch_count
	local answer

    if noflag ask; then
        warn "Using default branch names."
    fi

	# add a master branch if no such branch exists yet
	local master_branch
	if hubflow_has_master_configured && ! flag force; then
		master_branch=$(git config --get hubflow.branch.master)
	else
		# Two cases are distinguished:
		# 1. A fresh git repo (without any branches)
		#    We will create a new master/develop branch for the user
		# 2. Some branches do already exist
		#    We will disallow creation of new master/develop branches and
		#    rather allow to use existing branches for hubflow.
		local default_suggestion
		local should_check_existence
		branch_count=$(git_local_branches | wc -l)
		if [ "$branch_count" -eq 0 ]; then
			echo "No branches exist yet. Base branches must be created now."
			should_check_existence=NO
			default_suggestion=$(git config --get hubflow.branch.master || echo master)
		else
			echo
			echo "Which branch should be used for tracking production releases?"
			git_local_branches | sed 's/^.*$/   - &/g'

			should_check_existence=YES
			default_suggestion=
			for guess in $(git config --get hubflow.branch.master) \
			             'production' 'main' 'master'; do
				if git_local_branch_exists "$guess"; then
					default_suggestion="$guess"
					break
				fi
			done

			if [ -z "$default_suggestion" ] ; then
				for guess in $(git config --get hubflow.branch.master) \
				             'production' 'main' 'master'; do
					if git_remote_branch_exists "origin/$guess"; then
						default_suggestion="$guess"
						break
					fi
				done
			fi

			# if we have no default at this point, use 'master'
			if [ -z "$default_suggestion" ] ; then
				default_suggestion="master"
				should_check_existence="NO"
			fi
		fi

		printf "Branch name for production releases: [$default_suggestion] "
		if flag ask; then
			read answer
		else
			printf "\n"
		fi
		master_branch=${answer:-$default_suggestion}

		# check existence in case of an already existing repo
		if [ "$should_check_existence" = "YES" ]; then
			# if no local branch exists and a remote branch of the same
			# name exists, checkout that branch and use it for master
			if ! git_local_branch_exists "$master_branch" && \
				git_remote_branch_exists "origin/$master_branch"; then
				git branch "$master_branch" "origin/$master_branch" >/dev/null 2>&1
			elif ! git_local_branch_exists "$master_branch"; then
				die "Local branch '$master_branch' does not exist."
			fi
		fi

		# store the name of the master branch
		git config hubflow.branch.master "$master_branch"
	fi

	# add a develop branch if no such branch exists yet
	local develop_branch
	if hubflow_has_develop_configured && ! flag force; then
		develop_branch=$(git config --get hubflow.branch.develop)
	else
		# Again, the same two cases as with the master selection are
		# considered (fresh repo or repo that contains branches)
		local default_suggestion
		local should_check_existence
		branch_count=$(git_local_branches | grep -v "^${master_branch}\$" | wc -l)
		if [ "$branch_count" -eq 0 ]; then
			should_check_existence=NO
			default_suggestion=$(git config --get hubflow.branch.develop || echo develop)
		else
			echo
			echo "Which branch should be used for integration of the \"next release\"?"
			git_local_branches | grep -v "^${master_branch}\$" | sed 's/^.*$/   - &/g'

			should_check_existence=YES
			default_suggestion=
			for guess in $(git config --get hubflow.branch.develop) \
			             'develop' 'int' 'integration' 'master'; do
				if git_local_branch_exists "$guess"; then
					default_suggestion="$guess"
					break
				fi
			done

			if [ -z "$default_suggestion" ]; then
				for guess in $(git config --get hubflow.branch.develop) \
				             'develop' 'int' 'integration' 'master'; do
					if git_remote_branch_exists "origin/$guess"; then
						default_suggestion="$guess"
						break
					fi
				done
			fi
		fi

		printf "Branch name for \"next release\" development: [$default_suggestion] "
		if flag ask; then
			read answer
		else
			printf "\n"
		fi
		develop_branch=${answer:-$default_suggestion}

		if [ "$master_branch" = "$develop_branch" ]; then
			die "Production and integration branches should differ."
		fi

		# check existence in case of an already existing repo
		if [ "$should_check_existence" = "YES" ]; then
			git_local_branch_exists "$develop_branch" || \
				die "Local branch '$develop_branch' does not exist."
		fi

		# store the name of the develop branch
		git config hubflow.branch.develop "$develop_branch"
	fi

	# Creation of HEAD
	# ----------------
	# We create a HEAD now, if it does not exist yet (in a fresh repo). We need
	# it to be able to create new branches.
	local created_hubflow_branch=0
	if ! git rev-parse --quiet --verify HEAD >/dev/null 2>&1; then
		git symbolic-ref HEAD "refs/heads/$master_branch"
		git commit --allow-empty --quiet -m "Initial commit"
		created_hubflow_branch=1
	fi

	# Creation of master
	# ------------------
	# We cannot safely assume that the master branch actually exists. It will
	# exist nearly all of the time, but this deals with those rare occaisons
	# when the master branch needs setting up
	if ! git_local_branch_exists "$master_branch"; then
		if git_remote_branch_exists "origin/$master_branch"; then
			git branch "$develop_branch" "origin/$master_branch" >/dev/null 2>&1
		else
			git branch --no-track "$master_branch"
		fi
		created_hubflow_branch=1
	fi

	# Creation of develop
	# -------------------
	# The develop branch possibly does not exist yet.  This is the case when,
	# in a git init'ed repo with one or more commits, master was picked as the
	# default production branch and develop was "created".  We should create
	# the develop branch now in that case (we base it on master, of course)
	if ! git_local_branch_exists "$develop_branch"; then
		if git_remote_branch_exists "origin/$develop_branch"; then
			git branch "$develop_branch" "origin/$develop_branch" >/dev/null 2>&1
		else
			git branch --no-track "$develop_branch" "$master_branch"
		fi
		created_hubflow_branch=1
	fi

	# assert the hubflow repo has been correctly initialized
	hubflow_is_initialized

	# switch to develop branch if its newly created
	if [ $created_hubflow_branch -eq 1 ]; then
		git checkout -q "$develop_branch"
	fi

	# finally, ask the user for naming conventions (branch and tag prefixes)
	if flag force || \
	   ! git config --get hubflow.prefix.feature >/dev/null 2>&1 ||
	   ! git config --get hubflow.prefix.release >/dev/null 2>&1 ||
	   ! git config --get hubflow.prefix.hotfix >/dev/null 2>&1 ||
	   ! git config --get hubflow.prefix.support >/dev/null 2>&1 ||
	   ! git config --get hubflow.prefix.versiontag >/dev/null 2>&1; then
		echo
		echo "How to name your supporting branch prefixes?"
	fi

	local prefix

	# Feature branches
	if ! git config --get hubflow.prefix.feature >/dev/null 2>&1 || flag force; then
		default_suggestion=$(git config --get hubflow.prefix.feature || echo feature/)
		printf "Feature branches? [$default_suggestion] "
		if flag ask; then
			read answer
		else
			printf "\n"
		fi
		[ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion}
		git config hubflow.prefix.feature "$prefix"
	fi

	# Release branches
	if ! git config --get hubflow.prefix.release >/dev/null 2>&1 || flag force; then
		default_suggestion=$(git config --get hubflow.prefix.release || echo release/)
		printf "Release branches? [$default_suggestion] "
		if flag ask; then
			read answer
		else
			printf "\n"
		fi
		[ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion}
		git config hubflow.prefix.release "$prefix"
	fi


	# Hotfix branches
	if ! git config --get hubflow.prefix.hotfix >/dev/null 2>&1 || flag force; then
		default_suggestion=$(git config --get hubflow.prefix.hotfix || echo hotfix/)
		printf "Hotfix branches? [$default_suggestion] "
		if flag ask; then
			read answer
		else
			printf "\n"
		fi
		[ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion}
		git config hubflow.prefix.hotfix "$prefix"
	fi


	# Support branches
	if ! git config --get hubflow.prefix.support >/dev/null 2>&1 || flag force; then
		default_suggestion=$(git config --get hubflow.prefix.support || echo support/)
		printf "Support branches? [$default_suggestion] "
		if flag ask; then
			read answer
		else
			printf "\n"
		fi
		[ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion}
		git config hubflow.prefix.support "$prefix"
	fi


	# Version tag prefix
	if ! git config --get hubflow.prefix.versiontag >/dev/null 2>&1 || flag force; then
		default_suggestion=$(git config --get hubflow.prefix.versiontag || echo "")
		printf "Version tag prefix? [$default_suggestion] "
		if flag ask; then
			read answer
		else
			printf "\n"
		fi
		[ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion}
		git config hubflow.prefix.versiontag "$prefix"
	fi

	# at this point, we should be on the develop branch, which may or
	# may not exist at origin
	#
        # Load the settings that were just written so that $ORIGIN,
	# etc. are properly defined
        hubflow_load_settings
	# push up to origin, in case this branch does not exist there (yet)
	hubflow_push_latest_changes_to_origin
}

cmd_help() {
	usage
	exit 0
}
