#!/bin/sh

display_usage() {
	<< EOF >&2 cat
Usage: ${0##*/} [-b bdep] [-c category] [-m maintainer] [-n name pattern] [-g regexp]
       ${0##*/} [-d name pattern ]
       ${0##*/} [-g regexp] [-s master category/port]
       ${0##*/} [-N package name ]
       ${0##*/} -h

    -b - port needing certain build dependency
    -c - port category
    -d - search deleted ports
    -g - find ports with Makefile containing grep pattern
    -h - show this help
    -m - port maintainer
    -n - ports name matching pattern
    -N - find port with exact package name
    -s - find slave ports

EOF
	exit 1
}

grep_files() {
	find . -name $1 -depth $2 -exec grep -l "$3" {} \; \
		2>/dev/null | sed 's|^.\/||'
}

pkgname_exact_match() {
	local flavor flavors pkgbase portdir

	for portdir in $*; do
		cd "$portdir"
		flavors=$(make -V FLAVORS)
		if [ "$flavors" ]; then
			for flavor in $flavors; do
				pkgbase=$(make FLAVOR=$flavor -V PKGBASE)
				if [ "$exact_match" = "$pkgbase" ]; then
					echo "$portdir@$flavor" | sed "s|$PORTSDIR/||"
					exit 0
				fi
			done
		else
			pkgbase=$(make -V PKGBASE)
			if [ "$exact_match" = "$pkgbase" ]; then
				echo "$portdir" | sed "s|$PORTSDIR/||"
				exit 0
			fi
		fi
	done
	exit 1
}

while getopts "b:c:d:g:hm:n:N:s:" option; do
	case $option in
	b)
		bdeps="$OPTARG" ;;
	c)
		category="$OPTARG" ;;
	d)
		deleted="$OPTARG" ;;
	g)
		string="$OPTARG" ;;
	m)
		maintainer="$OPTARG" ;;
	n)
		name="$OPTARG" ;;
	N)
		exact_match="$OPTARG" ;;
	s)
		master="$OPTARG" ;;
	*)
		display_usage
	esac
done

if [ "$exact_match" ]; then
	[ "$bdeps" -o "$category" -o "$maintainer" -o "$master" -o "$name" \
		-o "$string" -o "$deleted" ] && display_usage
	search_args="name=$exact_match-"
elif [ "$deleted" ]; then
	[ "$bdeps" -o "$category" -o "$maintainer" -o "$master" -o "$name" \
		-o "$string" ] && display_usage
else
	[ ! "$bdeps" -a ! "$category" -a ! "$maintainer" -a ! "$name" \
		-a ! "$string" -a ! "$master" ] && display_usage
fi

readonly PORTSDIR=${PORTSDIR:-/usr/ports}
if [ ! -d "$PORTSDIR" ]; then
	echo "===> Ports directory not found: $PORTSDIR" >&2
	echo "===> Try setting PORTSDIR environment variable" >&2
	exit 1
fi

if [ "$category" -a ! -d "$PORTSDIR/$category" ]; then
	echo "===> No such category: $category" >&2
	exit 1
fi

if [ "$master" -a ! -d "$PORTSDIR/$master" ]; then
	echo "===> No such port: $PORTSDIR/$master" >&2
	exit 1
fi

[ ! "$bdeps" ] || search_args="bdeps=$bdeps"
[ ! "$category" ] || search_args="$search_args path=$category/"
[ ! "$maintainer" ] || search_args="$search_args maint=$maintainer"
[ ! "$name" ] || search_args="$search_args name=$name"
[ "$master" -a "$search_args" ] && display_usage

cd "$PORTSDIR"
indexfile=$(make -V INDEXFILE)
if [ ! -f "$indexfile" ]; then
	if [ $(id -u) -ne 0 ]; then
		if ! which sudo >/dev/null; then
			echo "===> sudo not found" >&2
			echo "===> root privileges or properly configured sudo required for fetching ports INDEX file." >&2
			exit 1
		fi
		SUDO="sudo"
	fi
	echo "===> Fetching missing index file..."
	if ! $SUDO make fetchindex; then
		echo "===> Could not fetch index file" >&2
		exit 1
	fi
fi

if [ "$deleted" ]; then
	awk -F '|' -v query="$deleted" '{
		if (match($1, query)) {
			if ($2 != "")
				print $1 " MOVED TO " $2 " ON " $3 " REASON: " $4;
			else
				print $1 " REMOVED ON " $3 " REASON: " $4;
		}
	}' "$PORTSDIR/MOVED"
	exit
fi

if [ ! "$search_args" -a ! "$master" ]; then
	grep_files Makefile 3 "$string" | sed 's|\/Makefile$||' | sort
	exit
fi

if [ "$master" ]; then
	portdir=$(realpath "$PORTSDIR/$master")
	portdirs=$(for candidate in \
		$(grep -E "($master|$(make -C "$master" -V PKGNAME))" "$indexfile" |
			cut -d'|' -f2 | sed 's,/usr/ports/,,')
	do
		masterdir=$(realpath "$(make -C "$candidate" -V MASTERDIR)")
		[ "$portdir" = "$masterdir" ] &&
			[ "$master" != "$candidate" ] && \
			echo "$PORTSDIR/$candidate"
	done)
else
	portdirs=$(make quicksearch $search_args | awk '/^Path:/ { print $2 }' | uniq)
	[ "$exact_match" ] && pkgname_exact_match $portdirs
fi

for portdir in $portdirs; do
	if [ "$string" ]; then
		[ -e "$portdir/Makefile" ] || continue
		grep -q "$string" "$portdir/Makefile"  || continue
	fi
	port=${portdir#$PORTSDIR/}
	pkg info -e $port 2>/dev/null &&
		installed="INSTALLED => $(pkg query %n $port | tr '\n' ' ')" || installed=""
	printf "%-40s %s\n" $port "$installed"
done
