#!/bin/bash -e

BS_SUPPORTED="autotools cmake"
BS_CONFFILE_autotools="configure.ac"
BS_CONFFILE_cmake="CMakeLists.txt"

autoDetectBS()
{
	local bs
	for bs in ${BS_SUPPORTED}; do
		local conffile="BS_CONFFILE_${bs}"
		if [ -e "${!conffile}" ]; then
			echo -n "${bs}"
			return 0
		fi
	done
	return 1
}

# Options
PATH="${PATH}:$(dirname $0):/usr/local/share/ui-auto:/usr/share/ui-auto"
. ui-libopt.sh

ui_opt_init "Unified build system tool for ui-auto tasks." "\
This tool autodetects the used build system and unifies a
selection of common tasks needed by ui-auto tools."
ui_opt_add "s"  "Only print the autodetected build system id."
ui_opt_add "S:" "Set Build System id arbitrarily. Supported: ${BS_SUPPORTED}." "$(autoDetectBS)"
ui_opt_addPos CMD "UBS command." "" "\
* check_installation : Check whether the build system tools are installed.
* strap [c|C]        : Strap the build system; c=clean, C=only clean.
* configure [OPTIONS]: Configure the build system.
   Example: $ ui-auto-ubs configure '--with-foo --disable-bar'
* build              : Build.
* check              : Run checks/tests.
* dist               : Make a distribution.
* distcheck          : Make a distribution with checks.
* parse              : Parse package name and version.
* patch VERSION      : Patch package version."
ui_opt_addPos OPT "Option for UBS command."
ui_opt_parse "$@"


#
# Common Tools
#
tagalize()
{
	echo "${1}" | tr [:lower:] [:upper:] | tr - _
}

cmd_parse_print()
{
	local package="${1}"
	local version="${2}"

	cat <<EOF
package="${package}"
package_cap="$(tagalize ${package})"
package_version="${version}"
package_version_major="$(echo "${version}" | cut -d. -f1)"
package_version_minor="$(echo "${version}" | cut -d. -f2)"
package_version_patch="$(echo "${version}" | cut -d. -f3-)"
EOF
}


#
# AUTOTOOLS
#
autotools_cmd_check_installation()
{
	ui_check_installed "autoconf --version"
	ui_check_installed "automake --version"
}

autotools_cmd_strap()
{
	clean()
	{
		# run distclean if available
		make distclean 2>/dev/null || true

		# Delete these files if they are symlinks
		for f in ui-auto missing install-sh mkinstalldirs config.guess config.sub depcomp ltmain.sh; do
			if [ -L "${f}" ]; then
				rm -f -v "${f}"
			fi
		done

		# Always delete these files
		rm -f -v *~ configure config.h.in config.h stamp-h.in stamp-h1 config.cache config.log config.status aclocal.m4 libtool
		rm -r -f -v autom4te.cache

		echo "Cleaned: $(pwd)"
	}
	strap()
	{
		if autoreconf --force --install --symlink; then
			echo "Strapped: $(pwd)"
		fi
	}
	# Get optional option
	local o=$(! ui_opt_givenPos 1 || ui_opt_getPos 1)
	# Run clean if called with c or C (clean)
	[ "${o}" != "C" -a "${o}" != "c" ] || clean
	# Return now if called with C (only clean)
	[ "${o}" != "C" ] || return 0
	# Strap
	strap
}

autotools_cmd_configure()
{
	./configure $(! ui_opt_givenPos 1 || ui_opt_getPos 1)
}

autotools_cmd_build()
{
	make
}

autotools_cmd_check()
{
	make check
}

autotools_cmd_dist()
{
	make dist
}

autotools_cmd_distcheck()
{
	make distcheck
}

autotools_cmd_parse()
{
	local package=$(grep ^AC_INIT ${BS_CONFFILE} | sed -e 's/[^(]*([[ ]*//' -e 's/[] ,].*//')
	local version=$(grep ^AC_INIT ${BS_CONFFILE} | sed -e 's/[^,]*,[[ ]*//' -e 's/[] ,)].*//')
	cmd_parse_print "${package}" "${version}"
}

autotools_cmd_patch()
{
	local v=$(ui_opt_getPos 1)

	cmd_patch_backup

	# Use cmd_parse_print here to get all varaibles we need; all generated vars MUST be local before.
	local package package_cap package_version package_version_major package_version_minor package_version_patch
	# Get $package
	eval $(autotools_cmd_parse)

	sed -i "s/AC_INIT\(.*\)/AC_INIT\([${package}]\,\ [${v}]\)/" "${BS_CONFFILE}"
}

#
# CMAKE
#
cmake_cmd_check_installation()
{
	ui_check_installed "cmake --version"
}

cmake_cmd_strap()
{
	clean()
	{
		# run clean if available
		make clean 2>/dev/null || true

		# Always delete these files
		rm -f -v CMakeCache.txt
		rm -r -f -v CMakeFiles/

		echo "Cleaned: $(pwd)"
	}
	strap()
	{
		# No strap for cmake
		return 0
	}
	# See autotools
	local o=$(! ui_opt_givenPos 1 || ui_opt_getPos 1)
	[ "${o}" != "C" -a "${o}" != "c" ] || clean
	[ "${o}" != "C" ] || return 0
	strap
}

cmake_cmd_configure()
{
	cmake .
}

cmake_cmd_build()
{
	make
}

cmake_cmd_check()
{
	# When defined, use target test (CTest).
	if make -n test >/dev/null 2>&1; then
		make test
	fi
}

cmake_cmd_dist()
{
	make package_source
}

cmake_cmd_distcheck()
{
	cmake_cmd_build
	cmake_cmd_check
	cmake_cmd_dist
}

cmake_cmd_parse()
{
	local package=$(grep -i ^PROJECT ${BS_CONFFILE} | sed -r -e 's/.*\(\s*([^ )]+).*/\1/' | tr [:upper:] [:lower:] | tr _ -)
	local package_cap=$(tagalize ${package})

	# @todo Below not nice, and will only work if you dont use extra spaces.
	local major=$(grep -i "^SET(${package_cap}_VERSION_MAJOR" ${BS_CONFFILE} | cut -d " " -f 2 | cut -d ')' -f 1)
	local minor=$(grep -i "^SET(${package_cap}_VERSION_MINOR" ${BS_CONFFILE} | cut -d " " -f 2 | cut -d ')' -f 1)
	local patch=$(grep -i "^SET(${package_cap}_VERSION_PATCH" ${BS_CONFFILE} | cut -d " " -f 2 | cut -d ')' -f 1)

	cmd_parse_print "${package}" "${major}.${minor}.${patch}"
}

# Helper tool: Copy conffile and create code to restore
cmd_patch_backup()
{
	local copy
	copy=$(mktemp -t ui-auto-ubs-XXXXXXXX) || exit 9
	local orig="$(pwd)/${BS_CONFFILE}"
	cp -a "${orig}" "${copy}"
	echo "mv \"${copy}\" \"${orig}\""
}

# Patch the build system's version (for snapshot generation).
cmake_cmd_patch()
{
	local v=$(ui_opt_getPos 1)

	cmd_patch_backup

	# Use cmd_parse_print here to get all varaibles we need; all generated vars MUST be local before.
	local package package_cap package_version package_version_major package_version_minor package_version_patch
	# Get $package_cap
	eval $(cmake_cmd_parse)
	# Parse major/minor/patch
	eval $(cmd_parse_print "${package}" "${v}")

	# Patch it
	sed -i \
		-e "s/^SET(${package_cap}_VERSION_MAJOR.*)/SET(${package_cap}_VERSION_MAJOR ${package_version_major})/i" \
		-e "s/^SET(${package_cap}_VERSION_MINOR.*)/SET(${package_cap}_VERSION_MINOR ${package_version_minor})/i" \
		-e "s/^SET(${package_cap}_VERSION_PATCH.*)/SET(${package_cap}_VERSION_PATCH ${package_version_patch})/i" \
		"${BS_CONFFILE}"
}

#
# Start processing
#

# Set build system to use
BS=$(ui_opt_get S)
if [ -z "${BS}" ]; then
	ui_opt_error "Are you in a project directory? No supported build system found"
fi
BS_CONFFILE_="BS_CONFFILE_${BS}"
BS_CONFFILE=${!BS_CONFFILE_}

# Handle special options
if ui_opt_given s; then
	# Print build system id only
	echo -n "${BS}"
	exit 0
fi

# Command processing
${BS}_cmd_$(ui_opt_getPos 0)

exit 0
