#!/bin/sh
#
# Copyright (C) 2013, 2016, 2017, 2019  Etersoft
# Copyright (C) 2013, 2016, 2017, 2019  Vitaly Lipatov <lav@etersoft.ru>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

load_helper epm-query
load_helper epm-repofix

confirm_info()
{
	info "$*"
	if [ -z "$non_interactive" ] ; then
		confirm "Are you sure? [y/N]" || fatal "Exiting"
	fi

}

__replace_text_in_alt_repo()
{
	local i
	for i in /etc/apt/sources.list /etc/apt/sources.list.d/*.list ; do
		[ -s "$i" ] || continue
		regexp_subst "$1" "$i"
	done
}

__wcount()
{
	echo "$*" | wc -w
}

__detect_alt_release_by_repo()
{
	local BRD=$(cat /etc/apt/sources.list /etc/apt/sources.list.d/*.list \
		| grep -v "^#" \
		| egrep "[tpc][5-9]\.?[0-9]?/branch/" \
		| sed -e "s|.*\([tpc][5-9]\.\?[0-9]\?\)/branch.*|\1|g" \
		| sort -u )
	if [ "$(__wcount $BRD)" = "1" ] ; then
		echo "$BRD"
		return
	fi

	local BRD=$(cat /etc/apt/sources.list /etc/apt/sources.list.d/*.list \
		| grep -v "^#" \
		| grep "Sisyphus/" \
		| sed -e "s|.*\(Sisyphus\).*|\1|g" \
		| sort -u )
	if [ "$(__wcount $BRD)" = "1" ] ; then
		echo "$BRD"
		return
	fi

	return 1
}

__replace_alt_version_in_repo()
{
	local i
	assure_exists apt-repo
	#echo "Upgrading $DISTRNAME from $1 to $2 ..."
	docmd apt-repo list | sed -e "s|\($1\)|{\1}->{$2}|g" | grep -E --color -- "$1"
	# ask and replace only we will have changes
	if a='' apt-repo list | grep -E -q -- "$1" ; then
		__replace_text_in_alt_repo "/^ *#/! s!$1!$2!g"
	fi
	docmd apt-repo list
}

__alt_repofix()
{
	local TO="$1"
	epm --quiet repo fix >/dev/null
	# TODO: switch it in repo code
	TO="$(__repofix_filter_vendor "$TO")"

	# replace sign name
	if [ -n "$TO" ] ; then
		__replace_text_in_alt_repo "/^ *#/! s!\[alt\]![$TO]!g"
		__replace_text_in_alt_repo "/^ *#/! s!\[sisyphus\]![$TO]!g"
		__replace_text_in_alt_repo "/^ *#/! s!\[updates\]![$TO]!g"
		__replace_text_in_alt_repo "/^ *#/! s!\[[tpc][6-9]\.?[0-9]?\]![$TO]!g"
	fi
}

__get_conflict_release_pkg()
{
	epm qf --quiet --short /etc/fedora-release | head -n1
}

get_fix_release_pkg()
{
	local TOINSTALL=''

	local FORCE=''
	if [ "$1" == "--force" ] ; then
		FORCE="$1"
		shift
	fi

	local TO="$1"

	if [ "$TO" = "Sisyphus" ] ; then
		TO="sisyphus"
		echo "apt-conf-$TO"
	else
# will it update /etc/altlinux-release
		echo "apt-conf-branch"
	fi

	if [ "$FORCE" == "--force" ] ; then
		# assure we have set needed release
		TOINSTALL="altlinux-release-$TO"
	else
		# just assure we have /etc/altlinux-release and switched from sisyphus
		if [ ! -s /etc/altlinux-release ] || epm qf /etc/altlinux-release | grep -q sisyphus ; then
			TOINSTALL="altlinux-release-$TO"
		fi
	fi

	#local AR="$(epm --short qf /etc/altlinux-release)"
	#if [ -n "$AR" ] && [ "$AR" != "$TOINSTALL" ] ; then
	#	echo "$AR-"
	#fi

	# TODO: add bug?
	# workaround against obsoleted altlinux-release-sisyphus package from 2008 year
	[ "$TOINSTALL" = "altlinux-release-sisyphus" ] && TOINSTALL="branding-alt-sisyphus-release"

	# update if installed (just print package name here to include in the install list)
	epm --quiet --short -q alt-gpgkeys 2>/dev/null
	if epm --quiet --short -q etersoft-gpgkeys 2>/dev/null >/dev/null ; then
		# leave etersoft-gpgkeys only we have LINUX@Etersoft repo
		epm rl | grep -q "LINUX@Etersoft" && echo etersoft-gpgkeys || echo alt-gpgkeys
	fi

	if [ -n "$TOINSTALL" ] ; then
		echo "$TOINSTALL"

		# workaround against
		#    file /etc/fedora-release from install of altlinux-release-p8-20160414-alt1 conflicts with file from package branding-simply-linux-release-8.2.0-alt1
		# problem
		local AR="$(__get_conflict_release_pkg)"
		if [ -n "$AR" ] && [ "$TOINSTALL" != "$AR" ] ; then
			echo $AR-
		fi
	fi
}

__switch_repo_to()
{
	local TO="$1"
	__replace_alt_version_in_repo "Sisyphus/" "$TO/branch/"
	__replace_alt_version_in_repo "[tpc][5-9]\.?[0-9]?/branch/" "$TO/branch/"
	__alt_repofix $TO
}

__check_system()
{
	# sure we have systemd if systemd is running
	if is_installed systemd && is_active_systemd systemd ; then
		docmd epm install systemd || fatal
	fi
}

get_next_release()
{
	local FROM="$1"
	case "$FROM" in
	"p6")
		echo "p7" ;;
	"p7")
		echo "p8" ;;
	"p8")
		echo "p9" ;;
	"c6")
		echo "c7" ;;
	"c7")
		echo "c8" ;;
	"c8")
		echo "c8.1" ;;
	"c8.1")
		echo "c8.2" ;;
	"c8.2")
		echo "c9" ;;
	*)
		echo "$FROM" ;;
	esac
}

# TODO: install new conf without signs?
__switch_alt_to_distro()
{
	local TO="$2"
	local FROM="$1"
	info
	[ -n "$TO" ] || TO="$(get_next_release $FROM)"
	case "$*" in
		"p6"|"p6 p7"|"t6 p7"|"c6 c7")
			confirm_info "Upgrade $DISTRNAME from $FROM to $TO ..."
			docmd epm install rpm apt "$(get_fix_release_pkg "$FROM")" || fatal
			__switch_repo_to $TO
			docmd epm update || fatal
			docmd epm install rpm apt "$(get_fix_release_pkg --force "$TO")" || fatal "Check an error and run epm release-upgrade again"
			docmd epm upgrade || fatal "Check an error and run epm release-upgrade again"
			docmd epm update-kernel
			info "Done."
			info "Run epm release-upgrade again for update to p8"
			;;
		"p7"|"p7 p8"|"t7 p8"|"c7 c8")
			confirm_info "Upgrade $DISTRNAME from $FROM to $TO ..."
			docmd epm install rpm apt "$(get_fix_release_pkg "$FROM")" || fatal
			__switch_repo_to $TO
			docmd epm update || fatal
			docmd epm install rpm apt "$(get_fix_release_pkg --force "$TO")" || fatal "Check an error and run epm release-upgrade again"
			__check_system
			docmd epm upgrade || fatal "Check an error and run epm release-upgrade again"
			docmd epm update-kernel || fatal
			info "Done."
			;;
		"c8"|"c8.1"|"c8.2"|"c8 c8.1"|"c8.1 c8.2"|"c8 c8.2")
			confirm_info "Upgrade $DISTRNAME from $FROM to $TO ..."
			docmd epm install rpm apt "$(get_fix_release_pkg "$FROM")" || fatal
			__switch_repo_to $TO
			docmd epm update || fatal
			docmd epm install rpm apt "$(get_fix_release_pkg --force "$TO")" || fatal "Check an error and run epm release-upgrade again"
			__check_system
			docmd epm upgrade || fatal "Check an error and run epm release-upgrade again"
			docmd epm update-kernel || fatal
			info "Done."
			;;
		"p8 c8"|"p8 c8.1"|"p8 c8.2")
			confirm_info "Upgrade $DISTRNAME from $FROM to $TO ..."
			docmd epm install rpm apt "$(get_fix_release_pkg "$FROM")" || fatal
			__switch_repo_to $TO
			docmd epm update || fatal
			docmd epm install rpm apt "$(get_fix_release_pkg --force "$TO")" || fatal "Check an error and run epm release-upgrade again"
			__check_system
			if epm installed libcrypt >/dev/null ; then
				# glibc-core coflicts libcrypt
				docmd epm downgrade apt pam pam0_passwdqc glibc-core libcrypt- || fatal
			fi
			docmd epm downgrade
			docmd epm upgrade || fatal "Check an error and run epm release-upgrade again"
			docmd epm update-kernel || fatal
			info "Done."
			;;
		"p8"|"p8 p9"|"t8 p9"|"c8 c9"|"c8 p9"|"c8.1 p9"|"c8.2 p9"|"p9 p9")
			confirm_info "Upgrade $DISTRNAME from $FROM to $TO ..."
			docmd epm install rpm apt "$(get_fix_release_pkg "$FROM")" || fatal
			__switch_repo_to $TO
			docmd epm update || fatal
			__check_system
			docmd epm upgrade || fatal "Check an error and run epm release-upgrade again"
			docmd epm install rpm apt "$(get_fix_release_pkg --force "$TO")" || fatal "Check an error and run epm release-upgrade again"
			docmd epm update-kernel || fatal
			info "Done."
			;;
		"p9 p8"|"c8.1 c8"|"c8.1 p8"|"p8 p8")
			confirm_info "Downgrade $DISTRNAME from $FROM to $TO ..."
			docmd epm install "$(get_fix_release_pkg "$FROM")" || fatal
			__switch_repo_to $TO
			docmd epm update || fatal
			docmd epm downgrade rpm apt "$(get_fix_release_pkg --force "$TO")" || fatal "Check an error and run epm release-upgrade again"
			__check_system
			if epm installed libcrypt >/dev/null ; then
				# glibc-core coflicts libcrypt
				docmd epm downgrade apt rpm pam pam0_passwdqc glibc-core libcrypt- || fatal
			fi
			docmd epm downgrade
			docmd epm upgrade || fatal
			info "Done."
			;;
		"p9 c8"|"p9 c8.1"|"p9 c8.2")
			confirm_info "Downgrade $DISTRNAME from $FROM to $TO ..."
			docmd epm install "$(get_fix_release_pkg "$FROM")" || fatal
			__switch_repo_to $TO
			docmd epm update || fatal
			docmd epm downgrade rpm apt "$(get_fix_release_pkg --force "$TO")" || fatal "Check an error and run epm release-upgrade again"
			__check_system
			#if epm installed libcrypt >/dev/null ; then
			#	# glibc-core coflicts libcrypt
			#	docmd epm downgrade apt rpm pam pam0_passwdqc glibc-core libcrypt- || fatal
			#fi
			docmd epm downgrade
			docmd epm upgrade || fatal
			info "Done."
			;;
		"Sisyphus p8"|"Sisyphus p9"|"Sisyphus c8"|"Sisyphus c8.1")
			confirm_info "Downgrade $DISTRNAME from $FROM to $TO ..."
			docmd epm install "$(get_fix_release_pkg "$FROM")" || fatal
			__switch_repo_to $TO
			docmd epm update || fatal
			docmd epm install rpm apt "$(get_fix_release_pkg --force "$TO")" || fatal "Check an error and run epm release-upgrade again"
			__check_system
			docmd epm downgrade
			docmd epm upgrade || fatal
			info "Done."
			;;
		"p8 Sisyphus"|"p9 Sisyphus"|"Sisyphus Sisyphus")
			confirm_info "Upgrade $DISTRNAME from $FROM to $TO ..."
			docmd epm install rpm apt "$(get_fix_release_pkg "$FROM")" || fatal
			docmd epm upgrade || fatal
			__replace_alt_version_in_repo "$FROM/branch/" "$TO/"
			__alt_repofix "sisyphus"
			docmd epm update || fatal
			docmd epm install rpm apt "$(get_fix_release_pkg --force "$TO")" || fatal "Check an error and run epm release-upgrade again"
			#local ADDPKG
			#ADDPKG=$(epm -q --short make-initrd sssd-ad 2>/dev/null)
			#docmd epm install librpm7 librpm rpm apt $ADDPKG "$(get_fix_release_pkg --force "$TO")" ConsoleKit2- || fatal "Check an error and run again"
			docmd epm upgrade || fatal "Check an error and run epm release-upgrade or just epm upgrade again"
			__check_system
			docmd epm update-kernel || fatal
			info "Done."
			;;
		*)
			if [ "$FROM" = "$TO" ] ; then
				info "It seems your system is already updated to newest $DISTRNAME $TO"
			else
				warning "Have no idea how to switch from $DISTRNAME $FROM to $DISTRNAME $TO."
			fi
			info "Try run f.i. # epm release-upgrade p8 or # epm release-upgrade Sisyphus"
			info "Also possible you need install altlinux-release-p? package for correct distro version detecting"
			return 1
	esac
}

epm_release_upgrade()
{
	assure_root
	info "Starting upgrade/switch whole system to other release"
	info "Check also http://wiki.etersoft.ru/Admin/UpdateLinux"

	cd /tmp || fatal
	# TODO: it is possible eatmydata does not do his work
	export EPMNOEATMYDATA=1

	case $DISTRNAME in
	ALTLinux)
		docmd epm update || fatal

		# try to detect current release by repo
		if [ "$DISTRVERSION" = "Sisyphus" ] || [ -z "$DISTRVERSION" ] ; then
			local dv
			dv="$(__detect_alt_release_by_repo)"
			if [ -n "$dv" ] && [ "$dv" != "$DISTRVERSION" ] ; then
				DISTRVERSION="$dv"
				info "Detected running $DISTRNAME $DISTRVERSION (according to using repos)"
			fi
		fi

		TARGET=""
		[ -n "$3" ] && fatal "Too many args: $*"
		if [ -n "$2" ] ; then
			DISTRVERSION="$1"
			info "Force current distro version as $DISTRVERSION"
			TARGET="$2"
		elif [ -n "$1" ] ; then
			TARGET="$1"
		fi

		__alt_repofix

		# TODO: ask before upgrade
		__switch_alt_to_distro $DISTRVERSION $TARGET
		return
		;;
	*)
		;;
	esac

	case $PMTYPE in
	apt-rpm)
		#docmd epm update
		info "Have no idea how to upgrade $DISTRNAME"
		;;
	*-dpkg)
		assure_exists do-release-upgrade update-manager-core
		sudocmd do-release-upgrade
		;;
	packagekit)
		docmd pkcon upgrade-system $pkg_filenames
		;;
	yum-rpm)
		docmd epm install rpm yum
		sudocmd yum clean all
		# TODO
		showcmd rpm -Uvh http://mirror.yandex.ru/fedora/linux/releases/16/Fedora/x86_64/os/Packages/fedora-release-16-1.noarch.rpm
		showcmd epm Upgrade
		;;
	dnf-rpm)
		info "Check https://fedoraproject.org/wiki/DNF_system_upgrade for an additional info"
		docmd epm install dnf
		#docmd epm install epel-release yum-utils
		sudocmd dnf --refresh upgrade
		sudocmd dnf clean all
		assure_exists dnf-plugin-system-upgrade
		sudocmd dnf upgrade --refresh
		local RELEASEVER="$pkg_filenames"
		[ -n "$RELEASEVER" ] || RELEASEVER=$(($DISTRVERSION + 1))
		#[ -n "$RELEASEVER" ] || fatal "Run me with new version"
		confirm_info "Upgrade to $DISTRNAME/$RELEASEVER"
		sudocmd dnf system-upgrade download --refresh --releasever=$RELEASEVER
		# TODO: from docs:
		# dnf system-upgrade reboot
		# FIXME: download all packages again
		sudocmd dnf distro-sync --releasever=$RELEASEVER
		info "Run epm autoorphans to remove orphaned packages"
		;;
	urpm-rpm)
		sudocmd urpmi.removemedia -av
		# TODO
		showcmd urpmi.addmedia --distrib http://mirror.yandex.ru/mandriva/devel/2010.2/i586/
		sudocmd urpmi --auto-update --replacefiles
		;;
	zypper-rpm)
		docmd epm repolist
		# TODO
		# sudocmd zypper rr <номер_репозитория>
		showcmd rr N
		showcmd epm ar http://mirror.yandex.ru/opensuse/distribution/11.1/repo/oss 11.1oss
		showcmd zypper ref
		docmd epm update
		docmd epm install rpm zypper
		docmd epm upgrade
		;;
	pacman)
		epm Upgrade
		;;
	conary)
		epm Upgrade
		;;
	emerge)
		epm Upgrade
		;;
	guix)
		sudocmd guix pull --verbose
		;;
	*)
		fatal "Have no suitable command for $PMTYPE"
		;;
	esac

}