# -*-eselect-*-  vim: ft=eselect
# Copyright 2019 Gentoo Foundation
# Distributed under the terms of the GNU GPL version 2 or later

inherit config tests multilib skel

MODULE="BLAS/CBLAS"
IFACE="blas"
DESCRIPTION="Manage installed alternatives of $MODULE shared objects"
MAINTAINER="lumin@debian.org"
VERSION="20190621"

### helper utility to find all available BLAS/CBLAS implementations
find_targets_in() {
	[[ $# -eq 1 ]] || die -q "in which libdir?"

	local cand
	for cand in ${EROOT}/etc/env.d/blas/$1/*; do
		[[ "config" = $(basename ${cand}) ]] && continue
		[[ -r ${cand} ]] && basename ${cand}
	done
}

### helper utility to validate a BLAS/CBLAS library directory
validate_blaslibdir() {
	[[ -d $1 ]] || return 2  # dir doesn't exist
	[[ -r "${1}/libblas.so.3" ]] && [[ -r "${1}/libblas.so" ]] \
	&& [[ -r "${1}/libcblas.so.3" ]] && [[ -r "${1}/libcblas.so" ]] \
	|| return 1
}

### show action
do_show() {
	# do_show -- show both lib64 and lib32 selection
	# do_show libxx -- show libxx selection
	local libdir cur libdirs=( $(list_libdirs) )

	# if manually specified libdirs
	if [[ ! $# -eq 0 ]]; then
		for libdir in $@; do
			has $libdir ${libdirs[@]} || die -q "invalid libdir '$libdir'!"
		done
		libdirs=( $@ )
	fi

	for libdir in ${libdirs[@]}; do
		[[ ! -d ${EROOT}/usr/$libdir ]] && continue
		[[ ! -r ${EROOT}/etc/env.d/blas/${libdir}/config ]] && continue
		cur=$(load_config ${EROOT}/etc/env.d/blas/${libdir}/config CURRENT)
		echo ${libdir}: $cur
	done
}

### list action
do_list() {
	local i cur targets
	local libdir libdirs=( $(list_libdirs) )

	# if manually specified libdirs
	if [[ ! $# -eq 0 ]]; then
		for libdir in $@; do
			has $libdir ${libdirs[@]} || die -q "invalid libdir '$libdir'!"
		done
		libdirs=( $@ )
	fi
	
	for libdir in ${libdirs[@]}; do
		[[ ! -d ${EROOT}/usr/$libdir ]] || [[ -L ${EROOT}/usr/$libdir ]] && continue
		targets=( $(find_targets_in $libdir) )
		cur=$(load_config ${EROOT}/etc/env.d/blas/${libdir}/config CURRENT)

		write_list_start "Available BLAS/CBLAS ($libdir) candidates:"
		for (( i = 0; i < ${#targets[@]}; i++ )); do
			[[ ${targets[i]} = $cur ]] \
			&& targets[i]=$(highlight_marker "${targets[i]}")
		done
		write_numbered_list -m "(none found)" "${targets[@]}"
	done
}

### validate action
describe_validate() {
	echo "validate candidates and remove invalid ones"
}

do_validate() {
	local i ldpath targets target candidate
	local libdir libdirs=( $(list_libdirs) )
	for libdir in ${libdirs[@]}; do
		[[ ! -d ${EROOT}/usr/$libdir ]] || [[ -L ${EROOT}/usr/$libdir ]] && continue
		targets=( $(find_targets_in $libdir) )
		for target in ${targets[@]}; do
			candidate=${EROOT}/etc/env.d/blas/${libdir}/${target}
			ldpath=$(load_config $candidate LDPATH)
			if ! validate_blaslibdir $ldpath; then
				echo "Removing invalid BLAS/CBLAS candidate ($candidate) ..."
				rm -v $candidate
			fi
		done
	done
}

### set action

describe_set() {
        echo "Activate one of the installed $MODULE implementations"
}

describe_set_parameters() {
        echo "[<libdir>] <implementation>"
}

describe_set_options() {
	echo "libdir: lib64 or lib32. Will use the native one when omitted."
        echo "implementation : implementation name or number (from 'list' action)"
}

do_set() {
	local libdirs=( $(list_libdirs) )
	local targets libdir ldconf libpath impl

	# check argument existence
	[[ $# -eq 1 ]] || [[ $# -eq 2 ]] || \
		die -q "Please specify [<libdir>] <impl> to activate!"
	# read argumenets
	if [[ $# -eq 2 ]]; then libdir="$1"; else libdir="$(get_libdir)"; fi
	if [[ $# -eq 2 ]]; then impl="$2"; else impl="$1"; fi
	# validate arguments
	has "$libdir" "${libdirs[@]}" || die -q "Invalid libdir ($libdir) !"
	targets=( $(find_targets_in $libdir) )
	if ! has "$impl" "${targets[@]}"; then
		if [[ ${impl} -gt 0 ]] && [[ ${impl} -le ${#targets[@]} ]]; then
			impl=${targets[(${impl} - 1)]}
		else
			die -q "Invalid impl ($impl) !"
		fi
	fi
	# store the configuration to env.d
	store_config ${EROOT}/etc/env.d/blas/${libdir}/config CURRENT "${impl}"
	# generate ld.so.conf file
	ldconf="${EROOT}/etc/ld.so.conf.d/81-blas-${libdir}.conf"
	libpath=$(load_config ${EROOT}/etc/env.d/blas/${libdir}/${impl} LDPATH)
	truncate -s0 $ldconf
	echo "# Auto-generated by eselect::blas. DON'T EDIT." >> $ldconf
	echo "$libpath" >> $ldconf

	# refresh cache. env-update will call ldconfig (see
	# portage::env_update.py) so we don't need to call it explicitly.
	env-update
}

### add action
describe_add_parameters() {
	echo "<libdir> <dir> <impl>"
}

describe_add_options() {
	echo "libdir : library directory where $MODULE implementation is installed (lib, lib64, etc.)"
	echo "dir : directory containing lib{,c}blas.so{.3}"
	echo "impl : name of the $MODULE implementation"
}

do_add() {
	[[ $# -eq 3 ]] \
		|| die -q "Please specify <libdir> <dir> <impl> to activate!"
	validate_blaslibdir $2 || die -q "invalid blas libdir!"
	store_config ${EROOT}/etc/env.d/blas/$1/$3 LDPATH $2
}
