#!/usr/bin/env bash

. lib.bash || exit
. libks.bash || exit

# create file list from directory
list_create() {
	local dir="$1"
	find "$dir" -printf '%Y %m ./%P\n'
}

# remove files according to list
list_remove() {
	local list="$1"
	local ftype mode path

	tac "$list" | while read -r ftype mode path; do
		path="$PREFIX/${path#./}"
		case $ftype in
		d) test -d "$path" && rmdir --ignore-fail-on-non-empty "$path";;
		?) rm -f "$path";;
		esac
	done
}

# display statistics of file list
list_stats() {
	local list="$1"
	local ndirs=0 nfiles=0
	local ftype mode path

	while read -r ftype mode path; do
		case $ftype in
		d) (( ++ndirs ));;
		?) (( ++nfiles ));;
		esac
	done < "$list"

	echo "$ndirs directories, $nfiles files"
}

dist_configure() {
	if test -e configure.ac; then
		if test ! -e configure || test configure.ac -nt configure; then
			info "'configure' is older than 'configure.ac'"
			if test -x autogen.sh; then
				lib:log "Updating configure through ./autogen.sh"
				NOCONFIGURE=1 ./autogen.sh
			else
				lib:log "Updating configure through autoreconf"
				autoreconf -i -f
			fi
		fi
	fi

	lib:log "Configuring for $PREFIX"
	./configure --prefix="$PREFIX" "$@"
}

dist_install() {
	local dest="${1%/}/" args=("${@:2}")

	rm -rf "$dest"
	mkdir -p "$dest"

	make DESTDIR="$dest" "${args[@]}" install
}

dir_copy() {
	(cd "$1" && find | bsdcpio --quiet -o) |
	pv -c -b -p |
	(cd "$2" && bsdcpio --quiet -i)

	rm -rf "$1"
}

for tool in bsdcpio find make pv tac; do
	have $tool || err "'$tool' not installed"
done

(( !errors )) || exit

if ! [[ $PREFIX ]]; then
	warn "\$PREFIX not set, assuming ~/.local"
	PREFIX="$HOME/.local"
fi

DBDIR="$path_data/pkg"
CACHEDIR="$path_cache/pkg"

mkdir -p "$DBDIR"
mkdir -p "$CACHEDIR/install"

while getopts ":P:" OPT; do
	case $OPT in
	P) pkgname=$OPTARG;;
	esac
done; shift $((OPTIND-1))

if [[ ! $pkgname ]]; then
	pkgname=$(basename "$PWD")
fi

export pkgname

cmd=$1; shift
case $cmd in
    configure)
	dist_configure "$@"
	;;
    install)
	filelist="$DBDIR/$pkgname.files"
	tempdest="$CACHEDIR/install/$pkgname"

	dist_install "$tempdest" "$@"

	if test -e "$filelist"; then
		lib:log "Uninstalling old version"
		pkg remove
	fi

	lib:log "Installing to file system"
	list_create "$tempdest/$PREFIX" > "$filelist"
	dir_copy "$tempdest/$PREFIX" "$PREFIX"
	list_stats "$filelist"
	;;
    uninstall|remove)
	filelist="$DBDIR/$pkgname.files"

	if ! test -e "$filelist"; then
		die "filelist $filelist not found"
	fi

	list_stats "$filelist"
	list_remove "$filelist"

	mv "$filelist" "$filelist-old"
	;;
    ls)
	if (( $# )); then
		for pkgname; do
			filelist="$DBDIR/$pkgname.files"

			if ! test -e "$filelist"; then
				err "filelist $filelist not found"
				continue
			fi

			cat "$filelist"
		done
	else
		for f in "$DBDIR"/*.files; do
			basename "$f" .files
		done
	fi
	;;
    files)
	(( $# )) || set -- "$pkgname"

	for pkgname; do
		filelist="$DBDIR/$pkgname.files"

		if ! test -e "$filelist"; then
			die "filelist $filelist not found"
		fi

		cat "$filelist"
	done
	;;
    stats)
	(( $# )) || set -- "$pkgname"

	for pkgname; do
		filelist="$DBDIR/$pkgname.files"

		if ! test -e "$filelist"; then
			die "filelist $filelist not found"
		fi

		list_stats "$filelist"
	done
	;;
    eval)
	eval "${@:2}"
	;;
    '')
	die "missing command"
	;;
    *)
	die "unknown command '$cmd'"
	;;
esac

(( !errors ))
