# Functions for parsing dependency field values
#
# Copyright (C) 2012-2014  Patrick McDermott
#
# This file is part of the ProteanOS Development Kit.
#
# The ProteanOS Development Kit is free software: you can redistribute
# it and/or modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# The ProteanOS Development Kit is distributed in the hope that it
# will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with the ProteanOS Development Kit.  If not, see
# <http://www.gnu.org/licenses/>.

resolve_deps()
{
	local new_pkgs="${1}"
	local deps="${2}"
	shift 2
	local all_deps=
	local new_deps=
	local pkg=

	all_deps=''
	new_pkgs="${new_pkgs} "
	while [ "x${new_pkgs}" != 'x' ]; do
		all_deps="${all_deps}${new_pkgs}"
		new_deps=''
		for pkg in ${new_pkgs}; do
			case "${pkg}" in
				*[!a-z0-9+.-]*) continue;;
			esac
			new_deps="${new_deps} $(printf '%s' "${deps}" | \
				sed -n "s/^${pkg}: *//p")"
		done
		new_deps="$(printf '%s\n' ${new_deps} | sort -u)"
		new_pkgs=''
		for pkg in ${new_deps}; do
			if [ "x${all_deps# ${pkg} }" = "x${all_deps}" ]; then
				new_pkgs="${new_pkgs}${pkg} "
			fi
		done
	done

	printf '%s\n' "${all_deps% }"
}

parse_dep()
{
	local dep="${1}"
	local host_arch="${2}"
	local host_plat="${3}"
	shift 3
	local pkgarchqual=
	local pkg=
	local archqual=
	local relver=
	local rel=
	local ver=
	local arches=
	local plats=

	dep="$(printf '%s\n' "${dep}" | sed -n '
		H;                        # Store each input line in hold space.
		${                        # On the last line:
		  g;                      # Restore everything to pattern space.
		  s/[\t\n]/ /g;           # Replace tabs & newlines with spaces.
		  s/ *\([(\[<]\) */ \1/g; # One space before "(", "[", and "<".
		  s/ *\([)\]>]\) */\1 /g; # One space after "(", "[", and "<".
		  s/ *\(<[<=]\) */\1 /g;  # One space after "<<" and "<=".
		  s/ *\(>[>=]\) */\1 /g;  # One space after ">>" and ">=".
		  s/ *\(=\) */\1 /g;      # One space after "=".
		  s/^ *//;                # Remove leading spaces.
		  s/ *$//;                # Remove trailing spaces.
		  s/  */ /g;              # Remove duplicate spaces.
		  p;                      # Print the pattern space.
		};                        # End.
		')"

	# dep is now of the form:
	# pkg[:archqual] [(rel ver)] [\[arches\]] [<plats>]

	pkgarchqual="${dep%% *}"
	dep=" ${dep#* }"
	pkg="${pkgarchqual%:*}"
	if [ "x${pkg}" != "x${pkgarchqual}" ]; then
		archqual="${pkgarchqual##*:}"
	fi

	if [ "x${dep# (*)}" != "x${dep}" ]; then
		relver="${dep# (}"
		relver="${relver%%)*}"
		dep="${dep# (*)}"
		rel="${relver% *}"
		ver="${relver##* }"
	fi

	if [ "x${dep# \[*\]}" != "x${dep}" ]; then
		arches="${dep# \[}"
		arches="${arches%%\]*}"
		dep="${dep# \[*\]}"
	fi

	if [ "x${dep# <*>}" != "x${dep}" ]; then
		plats="${dep# <}"
		plats="${plats%%>*}"
		dep="${dep# <*>}"
	fi

	if [ "x${host_arch}" != 'x' ] && ! arch_is_concerned \
			"${host_arch}" "${arches}"; then
		return 0
	fi
	if [ "x${host_plat}" != 'x' ] && ! plat_is_concerned \
			"${host_plat}" "${plats}"; then
		return 0
	fi

	printf '%s' "${pkg}"
	[ "x${archqual}" != 'x' ] && printf ':%s' "${archqual}"
	[ "x${ver}" != 'x' ] && printf ' (%s %s)' "${rel}" "${ver}"
	[ "x${host_arch}" = 'x' ] && [ "x${arches}" != 'x' ] && \
		printf ' [%s]' "${arches}"
	[ "x${host_plat}" = 'x' ] && [ "x${plats}" != 'x' ] && \
		printf ' <%s>' "${plats}"
	printf '\n'

	return 0
}

reduce_deps()
{
	local deps="${1}"
	local union="${2}"
	local host_arch="${3}"
	local host_plat="${4}"
	shift 4
	local dep_and=
	local dep_or=
	local dep_list=
	local dep_or_list=
	local dep=

	dep_list=''
	IFS=','
	for dep_and in ${deps}; do
		unset IFS
		if ! ${union}; then
			dep_or_list=''
			IFS='|'
			for dep_or in ${dep_and}; do
				unset IFS
				dep="$(parse_dep "${dep_or}" \
					"${host_arch}" "${host_plat}")"
				if [ "x${dep}" != 'x' ]; then
					if [ "x${dep_or_list}" != 'x' ]; then
						dep_or_list="${dep_or_list} | "
					fi
					dep_or_list="${dep_or_list}${dep}"
				fi
			done
			unset IFS
			if [ "x${dep_or_list}" != 'x' ]; then
				if [ "x${dep_list}" != 'x' ]; then
					dep_list="${dep_list}, "
				fi
				dep_list="${dep_list}${dep_or_list}"
			fi
		else
			dep="$(parse_dep "${dep_and}" \
				"${host_arch}" "${host_plat}")"
			if [ "x${dep}" != 'x' ]; then
				if [ "x${dep_list}" != 'x' ]; then
					dep_list="${dep_list}, "
				fi
				dep_list="${dep_list}${dep}"
			fi
		fi
	done
	unset IFS

	printf '%s\n' "${dep_list}"

	return 0
}