#!/usr/bin/env bash
# Author: Jack L. Frost <fbt@fleshless.org>
# Licensed under the Internet Software Consortium (ISC) license.
# See LICENSE for its text.

_self="${0##*/}"

cfg_workdir="/tmp/$USER/zpac"
cfg_aur_url='https://aur.archlinux.org'
cfg_aur_api="${cfg_aur_url}/rpc.php"

echo() { printf '%s\n' "$*"; }
err() { echo "$*" >&2; }

usage() {
	while read; do echo "$REPLY"; done <<- EOF
		Usage: $_self [flags] <package>
		Flags:
		        -h        Show this message.
		        -s        Search for <package>.
		        -d        Get the package sources (default).
				-D        If used with -d, makes $_self download the dependencies from AUR too.
	EOF
}

aur.search() {
	local aur_api_search_data aur_search_result_num pkg

	aur_api_search_data=$( curl -skL "${cfg_aur_api}?type=search&arg=${1}" )
	aur_search_result_num=$( jshon -e resultcount -u <<< "$aur_api_search_data" )

	if (( aur_search_result_num )); then
		aur_search_results=( $( jshon -e results -a -e Name -u <<< "$aur_api_search_data" ) )

		for i in "${!aur_search_results[@]}"; do
			printf 'aur/%s\n    %s\n' "${aur_search_results[${i}]}" "$( jshon -e results -e $i -e Description -u <<< "$aur_api_search_data" )"
		done
	else
		return 1
	fi
}

aur.info() {
	local pkg_aur_info=$( curl -skL "${cfg_aur_api}?type=info&arg=${1}" 2>/dev/null )
	local aur_query_result=$( jshon -e resultcount -u <<< "$pkg_aur_info" )

	if (( aur_query_result )); then
		echo "$pkg_aur_info"
	else
		return 1
	fi
}

aur.get() {
	local dep_name aur_api_multireq aur_deps_api_data aur_deps_count aur_deps pkg_aur_info pkg_base tarball_path
	
	read pkg_aur_info

	pkg_base=$( jshon -e results -e PackageBase -u <<< "$pkg_aur_info" )
	tarball_path=$( jshon -e results -e URLPath -u <<< "$pkg_aur_info" )

	cd "$cfg_workdir"

	echo "Downloading ${cfg_aur_url}${tarball_path}"
	{ curl -skL "${cfg_aur_url}${tarball_path}" | gzip -d | tar x; } || {
		err "Fail!"
		return 1
	}

	echo ": ${cfg_workdir}/${pkg_base}"

	if (( flag_get_deps )); then
		unset depends makedepends

		cd "${cfg_workdir}/${pkg_base}"
		source PKGBUILD

		for i in "${depends[@]}" "${makedepends[@]}"; do
			dep_name="${i/[<>=]*}"
			aur_api_multireq+="&arg\[\]=$dep_name"
		done
		
		aur_deps_api_data=$( curl -skL "${cfg_aur_api}?type=multiinfo${aur_api_multireq}" )
		aur_deps_count=$( jshon -e resultcount <<< "$aur_deps_api_data" )

		if (( aur_deps_count )); then
			aur_deps=$( jshon -e results -a -e Name -u <<< "$aur_deps_api_data" )

			for i in "${aur_deps[@]}"; do
				aur.get < <(aur.info "$i") || {
					return "$?"
				}
			done
		fi
	fi
}

abs.get() {
	local pkg_repo svn_repo

	pkg_repo="$2"

	case "$pkg_repo" in
		(community|multilib)
			svn_repo='community';;
		(*)
			svn_repo='packages';;
	esac

	svn checkout "svn://svn.archlinux.org/${svn_repo}/${1}/trunk" "${cfg_workdir}/${1}"
}

main() {
	while (( $# )); do
		case "$1" in
			--help|-h) usage; return 0;;

			-s) action='search';;
			-d) action='get';;
			-D) flag_get_deps=1;;

			--) shift; break;;
			-*)
				err "Unknown key: $1"
				usage
				return 1
			;;

			*) break;;
		esac
		shift
	done

	action=${action:-"get"}

	if [[ "$1" ]]; then
		package="$1"
	else
		usage
		return 1
	fi

	case "$action" in
		(get)
			[[ -d "$cfg_workdir" ]] || {
				mkdir -p "$cfg_workdir" || {
					err "Can't create workdir: ${cfg_workdir}."
					return 1
				}
			}

			pkg_aur_info=$( aur.info "$package" )

			if (( ! "$?" )); then
				repo='aur'
			else
				while read; do
					if [[ "$REPLY" =~ ^Repository ]]; then
						repo="${REPLY##* }"
					fi
				done < <( pacman -Si "$package" )

				[[ "$repo" ]] || {
					err "Can't find package ${package}"
					return 1
				}
			fi

			echo "Found ${package} in ${repo}."

			case "$repo" in
				(aur)
					aur.get <<< "$pkg_aur_info";;

				(core|extra|community|multilib)
					abs.get "$package" "$repo";;

				(*)
					err "Repository $repo not supported."
					return 1;;
			esac
		;;

		(search)
			if type -P package-query &>/dev/null; then
				package-query -ASs "$package"
			else
				aur.search "$package" || { flag_aur_search_fail=1; }
				pacman -Ss "$package" 2>/dev/null || { flag_pacman_search_fail=1; }

				if (( flag_aur_search_fail && flag_pacman_search_fail )); then
					err "No packages found."
					return 1
				fi
			fi
		;;
	esac
}

main "$@"