#!/bin/sh -fu
#
# Copyright (C) 2023 Evgeny Sinelnikov <sin@altlinux.org>
#
# This file 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.
#
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
#

. shell-args
. shell-error
. shell-getopt

verbose=

show_help() {
	cat <<-EOF
		Usage: $PROG [options] <command>

		Commands:
		  check-install           check packages list on installation and installation status
		  check-reinstall         check packages list on reinstallation
		  check-remove		  check packages list on removal
		  check-dist-upgrade	  check packages list on removal and installation for upgrade
		  fetch			  download packages archives without installation
		  fetch-dist-upgrade	  download packages archives without installation for dist-upgrade
		  dist-upgrade		  upgrade for each installed packages
		  clean			  erase downloaded archives
		  depends		  show dependencies of package
		  inversely-depends	  show inversed dependencies of package
		  listall                 list all available packages
		  search <pattern>        search through all packages
		  show			  show information about package

		Options:
		  -V, --version           print program version and exit;
		  -h, --help              show this text and exit.

		Report bugs to http://bugzilla.altlinux.org/

	EOF
	exit
}

print_version() {
	echo "@VERSION@"
	exit
}

get_last_log_entry() {
	if [ ! -f "$1" ]; then
		echo "Error: unable to get last update date, $1 not found" 1>&2
		exit 1
	fi
	tail -n 1 "$1"
}

check_install() {
	reply="$(apt-get install --just-print -q ${@})"
	local -i exit_code=${?}
	if [[ ${exit_code} -ne 0 ]]; then
		echo "${reply}" 1>&2
		exit ${exit_code}
	fi

	echo "${reply}" | awk '/Inst/ { print $2 }'
	echo "${reply}" | awk '/Remv/ { print $2 }' 1>&2
}

check_reinstall() {
	reply="$(apt-get reinstall -s -q ${@})"
	local -i exit_code=${?}
	if [[ ${exit_code} -ne 0 ]]; then
		echo "${reply}" 1>&2
		exit ${exit_code}
	fi

        echo "${reply}" | awk '/Inst/ { print $2 }'
        echo "${reply}" | awk '/Remv/ { print $2 }' 1>&2
}

check_remove() {
	reply="$(apt-get remove -s -q ${@})"
	local -i exit_code=${?}
	if [[ ${exit_code} -ne 0 ]]; then
		echo "${reply}" 1>&2
		exit ${exit_code}
	fi

	echo "${reply}" | awk '/Inst/ { print $2 }'
	echo "${reply}" | awk '/Remv/ { print $2 }' 1>&2
}

fetch() {
	reply="$(apt-get install --download-only --assume-yes -q ${@})"
	local -i exit_code=${?}
	if [[ ${exit_code} -ne 0 ]]; then
		echo "${reply}" 1>&2
		exit ${exit_code}
	fi
}

clean() {
	reply="$(apt-get clean)"
	local -i exit_code=${?}
	if [[ ${exit_code} -ne 0 ]]; then
		echo "${reply}" 1>&2
		exit ${exit_code}
	fi
}

depends() {
	reply="$(apt-cache depends ${@})"
	local -i exit_code=${?}
	if [[ ${exit_code} -ne 0 ]]; then
		echo "${reply}" 1>&2
		exit ${exit_code}
	fi

	echo "${reply}" | awk '/Depends/ { print $2 " " $3 " "  $4 " " $5 }'
}

inversely_depends() {
	reply="$(apt-cache rdepends ${@})"
	local -i exit_code=${?}
	if [[ ${exit_code} -ne 0 ]]; then
		echo "${reply}" 1>&2
		exit ${exit_code}
	fi

	echo "${reply}" | awk '/  / { print $1 }'
}

check_dist_upgrade() {
	reply="$(apt-get dist-upgrade -s -q)"
	local -i exit_code=${?}
	if [[ ${exit_code} -ne 0 ]]; then
		echo "${reply}" 1>&2
		exit ${exit_code}
	fi

	echo "${reply}" | awk '/Inst/ { print $2 }'
	echo "${reply}" | awk '/Remv/ { print $2 }' 1>&2
}

fetch_dist_upgrade() {
	reply="$(apt-get dist-upgrade --download-only --assume-yes -q)"
	local -i exit_code=${?}
	if [[ ${exit_code} -ne 0 ]]; then
		echo "${reply}" 1>&2
		exit ${exit_code}
	fi
}

dist_upgrade() {
	reply="$(apt-get dist-upgrade --assume-yes -q)"
	local -i exit_code=${?}
	if [[ ${exit_code} -ne 0 ]]; then
		echo "${reply}" 1>&2
		exit ${exit_code}
	fi
}

show() {
	local package_name="${1}"
	reply="$(apt-cache show ${package_name})"
	local -i exit_code=${?}
	if [[ ${exit_code} -ne 0 ]]; then
		echo "${reply}" 1>&2
		exit ${exit_code}
	fi

	echo "${reply}"
}

status() {
	local -i status_not_installed=0
	local -i status_installed=1
	local -i status_outdated=2
	local -i status_missing=3

	local pkg_name="${1}"

	rpm -q ${pkg_name} 2>/dev/null 1>/dev/null
	if [[ ${?} -ne 0 ]]; then
		apt-cache show "${pkg_name}" 2>/dev/null 1>/dev/null
		if [[ ${?} -ne 0 ]]; then
			exit ${status_missing}
		fi

		exit ${status_not_installed}
	fi
	local reply="$(check_dist_upgrade)"
	local -i exit_code=${?}
	if [[ ${exit_code} -ne 0 ]]; then
		exit ${status_installed}
	fi

	echo "${reply}" | grep "${pkg_name}" 1>/dev/null 2>/dev/null
	local -i exit_code=${?}
	if [[ ${exit_code} -eq 0 ]]; then
		exit ${status_outdated}
	fi

	exit ${status_installed}
}



TEMP=$(getopt -n $PROG -o $getopt_common_opts -l $getopt_common_longopts -- "$@") ||
	show_usage
eval set -- "$TEMP"

while :; do
	case "$1" in
	--)
		shift
		break
		;;
	*)
		parse_common_option "$1"
		;;
	esac
	shift
done

[ "$#" -gt 0 ] ||
	show_usage

case "$1" in
listall)
	apt-cache search . --names-only | awk '{ print $1 }'
	;;
search)
	[ "$#" -gt 1 ] ||
		show_usage
	apt-cache search "$2" | awk '{ print $1 }'
	;;
lastupdate)
	get_last_log_entry "/var/log/alterator/apt/updates.log"
	;;
lastdistupgrade)
	get_last_log_entry "/var/log/alterator/apt/dist-upgrades.log"
	;;
check-install)
	check_install "${@:2}"
	;;
check-reinstall)
	check_reinstall "${@:2}"
	;;
check-remove)
	check_remove "${@:2}"
	;;
fetch)
	fetch "${@:2}"
	;;
clean)
	clean
	;;
depends)
	depends "${@:2}"
	;;
inversely-depends)
	inversely_depends "${@:2}"
	;;
check-dist-upgrade)
	check_dist_upgrade
	;;
fetch-dist-upgrade)
	fetch_dist_upgrade
	;;
dist-upgrade)
	dist_upgrade
	;;
show)
	show "$2"
	;;
status)
	status "$2"
	;;
esac
