#!/bin/bash
# 2008-2015 Etersoft http://etersoft.ru
# Author: Vitaly Lipatov <lav@etersoft.ru>
# Public domain

# convert pkg names to Debian style
filter_deb_pkgnames()
{
	sed -e "s|_|-|g" -e "s|^ *\(.*\)-devel *\$|\1-dev|g" | tr "[A-Z]" "[a-z]"
}

build32on64()
{
	# FIXME: wine hack, use external replacement package list
	#[ "$BUILDARCH" = "x86_64" ] && rhas "$BUILDNAME" wine
	[ "$TARGETARCH" = "i586" ] && [ "$BUILDARCH" = "x86_64" ]
}

# Hack for improve requires for 32-bit build on 64-bit system
# See rpmbph also
fix_arch_requires()
{
	assert_var DISTRNAME TARGETARCH BUILDARCH BUILDNAME DISTRVERSION

	[ -z "$1" ] && return
	[ -z "$2" ] && return

	local GREP="$1"
	shift

	if build32on64 ; then
		if [ "$DISTRNAME" = "Fedora" ] || [ "$DISTRNAME" = "Scientific" ] || [ "$DISTRNAME" = "GosLinux" ] || [ "$DISTRNAME" = "RedOS" ] || [ "$DISTRNAME" = "CentOS" -a "$DISTRVERSION" != 5 ]; then
			# http://www.rpm.org/wiki/PackagerDocs/ArchDependencies
			# add (x86-32) to all -devel packages
			for i in $* ; do
				# FIXME: why not in repl file?
				rhas "$i" "^libtool$" && continue
				rhas "$i" "^lib.*-utils$" && continue
				rhas "$GREP" "-devel$" && ! rhas "$i" "\(x86-32\)$" && ! rhas "$i" "\(x86-64\)$" && echo "$i(x86-32)" && continue
				rhas "$GREP" "^lib" && ! rhas "$i" "\(x86-32\)$" && ! rhas "$i" "\(x86-64\)$" && echo "$i(x86-32)" && continue
				echo "$i"
			done | xargs -n 1000 echo
		# TODO
		elif [ "$DISTRNAME" = "Debian" ] && version_more_version $DISTRVERSION 7 ; then
			# i386 on Debian/Ubuntu: # add :i386 to all -dev packages
			for i in $* ; do
				rhas "$i" "^libtool$" && continue
				rhas "$i" "^lib.*-utils$" && continue
				rhas "$GREP" "^lib" && ! rhas "$i" ":i386$" && ! rhas "$i" ":amd64$" && echo "$i:i386" && continue
				rhas "$GREP" "-devel$" && ! rhas "$i" ":i386$" && ! rhas "$i" ":amd64$" && echo "$i:i386" && continue
				echo "$i"
			done | xargs -n 1000 echo
		elif [ "$DISTRNAME" = "OSNovaLinux" ] ; then
			# i386 on Debian/Ubuntu: # add :i386 to all -dev packages
			for i in $* ; do
				rhas "$i" "^libtool$" && continue
				rhas "$i" "^lib.*-utils$" && continue
				rhas "$GREP" "^lib" && ! rhas "$i" "-i386$" && ! rhas "$i" ":i386$" && ! rhas "$i" ":amd64$" && echo "$i:i386" && continue
				rhas "$GREP" "-devel$" && ! rhas "$i" "-i386$" && ! rhas "$i" ":i386$" && ! rhas "$i" ":amd64$" && echo "$i:i386" && continue
				echo "$i"
			done | xargs -n 1000 echo
		elif [ "$DISTRNAME" = "AstraLinux" ] ||[ "$DISTRNAME" = "AstraLinuxCE" ] || [ "$DISTRNAME" = "AstraLinuxSE" ]  ; then
			for i in $* ; do
				rhas "$i" "^ia32-libs$" && continue
				rhas "$i" "^libtool$" && continue
				# AstraLinux have no :i386 devel packages (see https://bugs.etersoft.ru/show_bug.cgi?id=12955)
				rhas "$i" "-dev$" && echo "$i" && continue
				rhas "$i" "^lib" && ! rhas "$i" ":i386$" && ! rhas "$i" ":amd64$" && echo "$i:i386" && continue
				# AstraLinux have no :i386 packages (see https://bugs.etersoft.ru/show_bug.cgi?id=12955)
				#rhas "$i" "-devel$" && ! rhas "$i" ":i386$" && ! rhas "$i" ":amd64$" && echo "$i:i386" && continue
				echo "$i"
			done | xargs -n 1000 echo
		# TODO
		elif [ "$DISTRNAME" = "Ubuntu" ] && version_more_version $DISTRVERSION 12.04 ; then
			# i386 on Debian/Ubuntu: # add :i386 to all -dev packages
			for i in $* ; do
				rhas "$i" "^libtool$" && continue
				rhas "$i" "^lib.*-utils$" && continue
				rhas "$GREP" "^lib" && ! rhas "$i" ":i386$" && ! rhas "$i" ":amd64$" && echo "$i:i386" && continue
				rhas "$GREP" "-devel$" && ! rhas "$i" ":i386$" && ! rhas "$i" ":amd64$" && echo "$i:i386" && continue
				echo "$i"
			done | xargs -n 1000 echo
		elif [ "$DISTRNAME" = "ArchLinux" ] ; then
			# i386 on ArchLinux: add lib32- to all lib packages
			for i in $* ; do
				rhas "$GREP" "^lib" && ! rhas "$i" "^lib32-" && echo "lib32-$i" && continue
				echo "$i"
			done | xargs -n 1000 echo
		elif [ "$DISTRNAME" = "SUSE" ] || [ "$DISTRNAME" = "SLED" ] || [ "$DISTRNAME" = "SLES" ]; then
                        if version_more_version $DISTRVERSION 15 && [ $DISTRVERSION != "42" ] ; then
				# i386 on SUSE or SLED : # add -32bit to all lib packages exclude -devel
				for i in $* ; do
					rhas "$GREP" "^lib" && ! rhas "$i" "-devel$" && ! rhas "$i" "-32bit$" && echo "$i-32bit" && continue
					echo "$i"
				done | xargs -n 1000 echo
                        else
				# i386 on SUSE or SLED : # add -32bit to all lib packages
				for i in $* ; do
					rhas "$GREP" "^lib" && ! rhas "$i" "-32bit$" && echo "$i-32bit" && continue
					echo "$i"
				done | xargs -n 1000 echo
			fi
		else
			echo "$@"
		fi
	else
		case "$DISTRNAME" in
			"Mandriva"|"ROSA"|"ROSAFresh"|"Mageia")
				if [ $TARGETARCH = "x86_64" ] ; then
					for i in $* ; do
						rhas "$GREP" "^libtool$" && echo "$i" && continue
						rhas "$GREP" "^lib.*-utils$" && continue
						echo "$i" | sed -e "s|^lib\([^6]\)|lib64\1|g"
					done  | xargs -n 1000 echo
					return
				fi
				;;
		esac
		echo "$@"
	fi
}

# Part of local hack
hack_distr_requires()
{
	local GREP="$1"

	case "$PKGFORMAT" in
		"deb")
			echo "$GREP" | filter_deb_pkgnames | sed -e "s|python3-module-|python3-|g"
			return
			;;
	esac

	case "$DISTRNAME" in
		"Mandriva"|"ROSA"|"ROSAFresh"|"Mageia")
			if [ $TARGETARCH = "x86_64" ] ; then
				rhas "$GREP" "^libtool$" && echo "$GREP" && return
				echo "$GREP" | sed -e "s|^lib\([^6]\)|lib64\1|g"
				return
			fi
			;;
		"ArchLinux")
			echo "$GREP" | sed -e "s|^ *\(.*\)-devel *\$|\1|g" | tr "[A-Z]" "[a-z]"
			return
			;;
		"FreeBSD")
			echo "$GREP" | sed -e "s|^ *\(.*\)-devel *\$|\1|g"
			return
			;;
		"Slackware"|"Gentoo")
			echo "$GREP" | sed -e "s|^ *\(.*\)-devel *\$|\1|g"
			return
			;;
	esac

	echo "$GREP"
}

# Get replacement rule for ALT package to local in $1 (scan for files in $@)
# sets ALTPKGNAME, TARGETPKGNAME variable
# used for hack: PKGFORMAT, DISTRNAME, BUILDARCH
# BUILDNAME used in add_32bit_requires for hack
tolocal_anyrepl()
{
	assert_var PKGFORMAT DISTRNAME BUILDNAME
	local i REPLRULE WARULES
	local GREP="$1"
	shift
	rhas "$GREP" "^[0-9]" && FIXNEWRESULT="$GREP" && return 1
	# TODO: fix space removing
	WARULES="s/^ *//g 
		s/ *\$//g 
		s/ *|/|/g 
		s/| */|/g"
	USEDPKGREPL='scripted rules'
	for i in $@ ; do
		REPLRULE=`grep -v "^#" "$i" 2>/dev/null | sed -e 's|^ *||' -e 's/ *| */|/' |  grep -- "^$GREP|" | sed -e "$WARULES" | head -n1`
		# For broken rule
		rhas "$REPLRULE" "|" || REPLRULE=""
		#REPLRULE=`echo $REPLRULE | sed -r -e 's,|,!,g'`
		ALTPKGNAME=`echo $REPLRULE | cut -d"|" -f1 | sed -e "s|\+|\\\\\+|g"`
		TARGETPKGNAME=`echo $REPLRULE | cut -d"|" -f2 | sed -e "s|\+|\\\\\+|g"`
		test -n "$REPLRULE" && TARGETPKGNAME=$(fix_arch_requires "$GREP" "$TARGETPKGNAME") && USEDPKGREPL="$(basename $i)" && return 0
	done

	# if missed in repl files try transform by default

	local NEWRESULT=$(hack_distr_requires "$GREP")

	FIXNEWRESULT=$(fix_arch_requires "$GREP" "$NEWRESULT")

	ALTPKGNAME="$GREP"
	TARGETPKGNAME="$FIXNEWRESULT"

	# return if no chance to replace
	[ "$FIXNEWRESULT" = "$GREP" ] && return 1
	# HACK: return if we get complex result
	[ "$FIXNEWRESULT" != "$NEWRESULT" ] && return 0

	# this recursive needs to be argumented
	# try to resolve recursive
	#tolocal_anyrepl "$FIXNEWRESULT" $@
	return 0
}

tolocal_anyrepl_group()
{
	assert_var PKGFORMAT DISTRNAME BUILDNAME
	local i REPLRULE WARULES
	local GREP="$1"
	shift
	# TODO: fix space removing
	WARULES="s/^ *//g 
		s/ *\$//g 
		s/ *|/|/g 
		s/| */|/g"
	USEDPKGREPL='scripted rules'
	for i in $@ ; do
		REPLRULE=`grep -v "^#" "$i" 2>/dev/null | grep -- "^ *$GREP *|" | sed -e "$WARULES" | head -n1`
		# For broken rule
		rhas "$REPLRULE" "|" || REPLRULE=""
		#REPLRULE=`echo $REPLRULE | sed -r -e 's,|,!,g'`
		ALTPKGNAME=`echo $REPLRULE | cut -d"|" -f1 | sed -e "s|\+|\\\\\+|g"`
		TARGETPKGNAME=`echo $REPLRULE | cut -d"|" -f2 | sed -e "s|\+|\\\\\+|g"`
		#test -n "$REPLRULE" && TARGETPKGNAME=$(add_32bit_requires "$GREP" "$TARGETPKGNAME") && USEDPKGREPL="$(basename $i)" && return 0
	done

	FIXNEWRESULT="$GREP"

	ALTPKGNAME="$GREP"
	TARGETPKGNAME="$FIXNEWRESULT"

	# return if no chance to replace
	[ "$FIXNEWRESULT" = "$GREP" ] && return 1
	# HACK: return if we get complex result
	[ "$FIXNEWRESULT" != "$NEWRESULT" ] && return 0

	# this recursive needs to be argumented
	# try to resolve recursive
	#tolocal_anyrepl "$FIXNEWRESULT" $@
	return 0
}

# Clean require names from various stuffs
clean_pkgreq()
{
	local i VAR
	VAR=`cat | sort -u`
	for i in $VAR ; do
		#echo "$i" | grep -E "^gcc[0-9]|^cpp[0-9]|^gcc-c++[0-9]" >/dev/null && continue
		#echo "$i" | grep -E "gcc\$|cpp\$|gcc-c++\$" >/dev/null && continue
		echo "$i" | grep "^%" >/dev/null && continue
		echo "$i" | grep "[<=>]" >/dev/null && continue
		echo "$i" | grep "^ *[0-9]\.[0-9]" >/dev/null && continue
		echo -n "$i " | sed -e "s|[,}]| |g"
	done | estrlist filter_strip_spaces
}

# Print list of all build requires in ALT notation
print_buildreq()
{
	eval_spec ${1} | grep "^Build.*Req" | sed -e "s|^.*:||g" | clean_pkgreq
}

# Print list of all pkg requires
print_pkgreq()
{
	eval_spec ${1} | grep "^Requires" | sed -e "s|^.*:||g" | clean_pkgreq
}

# Print list of all groups
print_grpreq()
{
	eval_spec ${1} | grep "^Group" | sed -e "s|^.*:||g" | sort -u | estrlist filter_strip_spaces
}

# FIXME: need improvement
# use tests/test_repl_find.sh for test it
internal_repl_list()
{
	# need be defined in detect_target_env()
	assert_var PKGVENDOR PKGFORMAT DISTRVERSION
	local REPLBASE="$1"
	local ARCHEXT="$2"
	local FINDPKG=$REPLBASE.$PKGVENDOR.$DISTRVERSION$ARCHEXT
	local FINDPKGVERS=''
	local FINDPKGGREP=$REPLBASE.$PKGVENDOR.$DISTRVERSION
	# 7.3 -> 7, 20.04 -> 20
	local BASEDISTRVERSION=${DISTRVERSION/\.*/}
	if [ "$DISTRVERSION" != "$BASEDISTRVERSION" ] ;then
		FINDPKGVERS="$REPLBASE.$PKGVENDOR.$BASEDISTRVERSION$ARCHEXT"
		#FINDPKGGREP="$FINDPKGVERS"
	fi

	echo $REPLBASE.$DISTRNAME$ARCHEXT
	echo $REPLBASE.$DISTRNAME.$DISTRVERSION$ARCHEXT

	if [ -n "$ARCHEXT" ] ; then
	(
		# sure we use our version firstly
		echo $FINDPKG
		echo $FINDPKGGREP
		ls -1 $REPLBASE.$PKGVENDOR*$ARCHEXT 2>/dev/null | grep -v "$PKGVENDOR$ARCHEXT\$"
	) | grep -v "^\$" | sed -e "s|$ARCHEXT\$||" | \
		sort -u | sort -r -t . -n -k 3 | grep "^$FINDPKGGREP\$" -A1000 | sed -e "s|$|$ARCHEXT|"
	else
	(
		# sure we use our version firstly
		echo $FINDPKG
		echo $FINDPKGGREP
		# skip all arches
		ls -1 $REPLBASE.$PKGVENDOR* 2>/dev/null | grep -v "\.x86_64\$" | grep -v "\.aarch64\$" | grep -v "\.x86_64-i586\$" | grep -v "\.i586\$"
	) | grep -v "^\$" | \
		sort -u | sort -r -t . -n -k 3 | grep "^$FINDPKGGREP\$" -A1000
	fi
	echo $REPLBASE.$PKGVENDOR$ARCHEXT
	[ "$PKGVENDOR" = "alt" ] || echo "$REPLBASE.$PKGFORMAT$ARCHEXT "
}

# internal
print_replbased_list()
{
	local REPLBASE="$1"
	if [ "$BUILDARCH" = "x86_64" ] ; then
		if build32on64 ; then
			internal_repl_list $REPLBASE .x86_64-i586 | uniq
		else
			internal_repl_list $REPLBASE .x86_64 | uniq
		fi
	elif [ "$BUILDARCH" = "i586" ] ; then
		internal_repl_list $REPLBASE .i586 | uniq
	elif [ "$BUILDARCH" = "aarch64" ] ; then
		internal_repl_list $REPLBASE .aarch64 | uniq
	fi

        # general rules listing
	internal_repl_list $REPLBASE "" | uniq
}

PKGREPLBASE=$ETERBUILDDIR/pkgrepl

# TODO: list in  alph. order and use if <= then our version
print_pkgrepl_list()
{
	print_replbased_list $PKGREPLBASE/pkgrepl
}

print_grprepl_list()
{
	print_replbased_list $(realpath $PKGREPLBASE/../grprepl/grprepl)
}


# Converts ALT Linux Sisyphus dependencies to target notation
# and print out result dependencies
# call with package list
convert_pkgreqs_to_target()
{
	assert_var DISTRVENDOR BUILDARCH TARGETARCH PKGFORMAT
	local repl_list
	repl_list=$(print_pkgrepl_list)
	LISTUSEDPKGREPL=''

	local j
	for j in "$@" ; do
		tolocal_anyrepl $j $repl_list && estrlist list "$TARGETPKGNAME" && LISTUSEDPKGREPL="$LISTUSEDPKGREPL\nUSEDPKGREPL" || echo $j
	done | sort -u | sed -e "s|\\\\+|\+|g"
}

# Prints out buildreqs in target notation for SPEC (1st arg)
print_target_buildreq()
{
	local listdep=$(print_buildreq ${1})
	echo $(BUILDNAME="$1" convert_pkgreqs_to_target $listdep)
}

