#!/bin/sh
# Forked from eselect opengl Gentoo module - this is reaaaaaaaaaally faster
# this is used only at Live time, to avoid the use of Portage
# Copyright 2006-2008 Fabio Erculiani

# Our data
ENV_FILE="/etc/env.d/03opengl"
PREFIX="/usr"
DST_PREFIX="/usr"
USE_PROFILE_HEADERS="no"
ES_VALID_MULTILIB_DIRS="lib lib32 lib64"

# list_libdirs PUBLIC
# Returns a space separated list of libdirs available on this machine
list_libdirs() {
    local dir libdirs
    libdirs=""
    for dir in ${ES_VALID_MULTILIB_DIRS} ; do
        if grep -q "^/${dir}\(\|/\)$" /etc/ld.so.conf &> /dev/null ; then
            libdirs=( ${libdirs[@]} ${dir} )
        fi
    done
    if [[ -z ${libdirs[@]} ]] ; then
    	# Broken or non-existing ld.so.conf
    	libdirs=( /lib* )
	libdirs=( ${libdirs[@]/\/lib/lib} )
    fi
    echo "${libdirs[@]}"
}

# has test list
# Return true if list contains test
has() {
    local test=${1} item
    shift
    for item in $@ ; do
        [[ ${item} == ${test} ]] && return 0
    done
    return 1
}

# is_function function PUBLIC
# Test whether function exists
is_function() {
    [[ $(type -t "${1}" ) == "function" ]]
}

# is_number PUBLIC
# Returns true if and only if $1 is a positive whole number
is_number() {
    [[ -n ${1} ]] && [[ -z ${1//[[:digit:]]} ]]
}

get_current_implementation() {
	local ret
	local ldpath=$(cat ${ENV_FILE} | grep LDPATH | cut -d'"' -f 2)
	
	local opengl_profile=$(cat ${ENV_FILE} | grep OPENGL_PROFILE | cut -d'"' -f 2)
        
	if [[ -n ${opengl_profile} ]] ; then
		ret="${opengl_profile}"
	elif [[ -n ${ldpath} ]] ; then
		ret="${ldpath%%:*}"
		ret="${ret##*opengl/}"
		ret="${ret%/lib*}"
	fi

	echo ${ret}
}

get_implementations() {
	local ret dir
	for x in $(list_libdirs) ; do
		for dir in "${PREFIX}/${x}"/opengl/* ; do
			[[ -d ${dir} && $(basename "${dir}") != "global" ]] || continue
			has $(basename "${dir}") ${ret} && continue
			ret=${ret:+${ret} }$(basename "${dir}")
		done
	done

	echo ${ret}
}

setup_lib_symlinks() {
	local profile_libdir=${1}
	local libdir=${2}
	local file
	local rootfile

	mkdir -p "${libdir}" || echo "Failed to create ${libdir}"

	pushd "${libdir}" &> /dev/null
		# First remove old symlinks
		for file in libGL{,core}.{a,so,la} ; do
			rm -f "${file}" || echo -q "Failed to delete ${file}"
		done

		# Note that we don't do .so*, just .so on purpose.  The
		# loader knows to look in the profile dir, and the
		# linked just needs the .so
		for file in ${profile_libdir}/libGL{,core}.{so,a,la}; do
			rootfile="${file}"
			[[ -f ${file} ]] || continue
			if [[ -f $(basename "${file}") ]] ; then
				rm -f "$(basename "${file}")" || echo -q "Failed to delete ${libdir}/$(basename "${file}")"
			fi

			# Fix libtool archives (#48297)
			if [[ ${file%.la} != ${file} ]] ; then
				sed "s:${profile_libdir}:${libdir}:g" "${file}" > "$(basename "${file}")" || echo "Failed to create ${libdir}/$(basename "${file}")"
			else
				ln -s "${rootfile}" || echo "Failed to create ${libdir}/$(basename "${file}")"
			fi
		done
	popd &> /dev/null
}

set_new_implementation() {
	local gl_implem=${1}
	local avail_implems=$(get_implementations)

	# Set a sane umask... bug #83115
	umask 022

	if ! has ${gl_implem} ${avail_implems}; then
		echo "Invalid profile selected."
		exit 1
	fi

	echo -n "Switching to ${gl_implem} OpenGL interface..."

		local libdir
		for libdir in $(list_libdirs); do
			[[ ${ROOT} != / ]] && libdir=${libdir//${ROOT}}

			# First make sure we have an opengl directory and this is a real lib dir, not a symlink
			[[ -d ${PREFIX}/${libdir}/opengl && ! -h ${PREFIX}/${libdir} ]] || continue

			# Fallback on xorg-x11 if we don't have this implementation for this libdir.
			local gl_local
			if [[ ! -d ${PREFIX}/${libdir}/opengl/"${gl_implem}" ]] ; then
				gl_local="xorg-x11"
			else
				gl_local="${gl_implem}"
			fi

			setup_lib_symlinks "${PREFIX}/${libdir}/opengl/${gl_local}/lib" "${DST_PREFIX}/${libdir}"
		
			if [[ -e ${PREFIX}/${libdir}/opengl/${gl_local}/lib/tls ]] ; then
				setup_lib_symlinks "${PREFIX}/${libdir}/opengl/${gl_local}/lib/tls" "${DST_PREFIX}/${libdir}/tls"
			fi

			local moduledir
			if [[ -e ${DST_PREFIX}/${libdir}/xorg/modules ]] ; then
				moduledir="xorg/modules"
			else
				moduledir="modules"
			fi

			if [[ -e ${PREFIX}/${libdir}/opengl/${gl_local}/extensions ]] ; then
				mkdir -p "${DST_PREFIX}/${libdir}/${moduledir}/extensions" || echo "Failed to create ${DST_PREFIX}/${libdir}/${moduledir}/extensions"
				pushd "${DST_PREFIX}/${libdir}/${moduledir}/extensions" &> /dev/null
					# First remove old symlinks
					for file in lib{wfb,glx,dri,dri2}.{a,so,la}; do
						rm -f "${file}" || echo "Failed to delete ${DST_PREFIX}/${libdir}/${moduledir}/extensions/${file}"
					done

					for file in ${PREFIX}/${libdir}/opengl/${gl_local}/extensions/*.{so,a,la}; do
						[[ -f ${file} ]] || continue
						if [[ -f $(basename "${file}") ]] ; then
							rm -f "$(basename "${file}")" || echo "Failed to delete ${DST_PREFIX}/${libdir}/${moduledir}/extensions/$(basename "${file}")"
						fi

						# Fix libtool archives (#48297)
						if [[ ${file%.la} != ${file} ]] ; then
							sed "s:${PREFIX}/[^/]*/opengl/[^/]*/lib:${DST_PREFIX}/${libdir}:g" "${file}" > "$(basename "${file}")" || echo "Failed to create ${DST_PREFIX}/${libdir}/${moduledir}/extensions/$(basename "${file}")"
						else
							ln -s "${file}" || echo "Failed to create ${libdir}/$(basename "${file}")"
						fi
					done
				popd &> /dev/null
			fi

			# Setup the includes
			mkdir -p "${DST_PREFIX}/include/GL" || echo "Failed to create ${DST_PREFIX}/include/GL"
			pushd "${DST_PREFIX}/include/GL" &> /dev/null
				for file in gl.h glx.h glxtokens.h glext.h glxext.h glxmd.h glxproto.h; do
					# IMPORTANT
					# It is preferable currently to use the standard glext.h file
					# however if an OpenGL provider must use a self produced glext.h
					# then it should be installed to ${gl_implem}/include and the user
					# can add the --impl-headers option to select it.

					if [[ "${USE_PROFILE_HEADERS}" == "yes" ]] ; then
						# Check the profile first.
						if [[ -e ${PREFIX}/${libdir}/opengl/${gl_implem}/include/${file} ]] ; then
							if [[ -f ${file} || ( -L ${file} && ! -e ${file} ) ]] ; then
								rm -f "${file}" || echo "Failed to delete ${DST_PREFIX}/include/GL/$(basename "${file}")"
							fi

							ln -s ${PREFIX}/${libdir}/opengl/${gl_implem}/include/${file} || echo "Failed to create ${DST_PREFIX}/include/GL/$(basename "${file}")"
							continue
						fi
					fi

					if [[ -e ${PREFIX}/${libdir}/opengl/global/include/${file} ]] ; then
						if [[ -f ${file} || ( -L ${file} && ! -e ${file} ) ]] ; then
							rm -f "${file}" || echo "Failed to delete ${DST_PREFIX}/include/GL/$(basename "${file}")"
						fi

						ln -s ${PREFIX}/${libdir}/opengl/global/include/${file} || echo "Failed to create ${DST_PREFIX}/include/GL/$(basename "${file}")"
					elif [[ -e ${PREFIX}/${libdir}/opengl/${gl_implem}/include/${file} ]] ; then
						if [[ -f ${file} || ( -L ${file} && ! -e ${file} ) ]] ; then
							rm -f "${file}" || echo "Failed to delete ${DST_PREFIX}/include/GL/$(basename "${file}")"
						fi

						ln -s ${PREFIX}/${libdir}/opengl/${gl_implem}/include/${file} || echo "Failed to create ${DST_PREFIX}/include/GL/$(basename "${file}")"
					elif [[ -e ${PREFIX}/${libdir}/opengl/xorg-x11/include/${file} ]] ; then
						if [[ -f ${file} || ( -L ${file} && ! -e ${file} ) ]] ; then
							rm -f "${file}" || echo "Failed to delete ${DST_PREFIX}/include/GL/$(basename "${file}")"
						fi

						ln -s ${PREFIX}/${libdir}/opengl/xorg-x11/include/${file} || echo "Failed to create ${DST_PREFIX}/include/GL/$(basename "${file}")"
					fi
				done
			popd &> /dev/null

			# Setup the $LDPATH
			ldpath="${ldpath:+${ldpath}:}${PREFIX}/${libdir}/opengl/${gl_local}/lib"

		done

		sed -i '/LDPATH=.*/d' ${ENV_FILE}
		echo "LDPATH=\"${ldpath}\"" >> ${ENV_FILE}
		oldldpath=$(cat /etc/profile.env|grep LDPATH | cut -d"'" -f2)

		sed -i '/export LDPATH=.*/d' /etc/profile.env
		sed -i '/setenv LDPATH=.*/d' /etc/csh.env
		sed -i '/export LD_LIBRARY_PATH=.*/d' /etc/profile.env
		sed -i '/setenv LD_LIBRARY_PATH=.*/d' /etc/csh.env
		sed -i "s/OPENGL_PROFILE=.*/OPENGL_PROFILE='${gl_implem}'/"  /etc/profile.env
		sed -i "s/OPENGL_PROFILE=.*/OPENGL_PROFILE='${gl_implem}'/"  /etc/csh.env
		sed -i '/LD_LIBRARY_PATH=.*/d' ${ENV_FILE}
		sed -i "s/OPENGL_PROFILE=.*/OPENGL_PROFILE=\"${gl_implem}\"/"  ${ENV_FILE}

		echo "export LDPATH='"${ldpath}":"${oldldpath}"'" >> /etc/profile.env
		echo "setenv LDPATH='"${ldpath}":"${oldldpath}"'" >> /etc/csh.env
		echo "export LD_LIBRARY_PATH='"${ldpath}"'" >> /etc/profile.env
		echo "setenv LD_LIBRARY_PATH='"${ldpath}"'" >> /etc/csh.env
		echo 'LD_LIBRARY_PATH="'${ldpath}'"' >> ${ENV_FILE}


		source /etc/profile &> /dev/null
	echo " done"
}

do_set() {
	local action="error"
	local current=$(get_current_implementation)
	local available=$(get_implementations)
	local new

	while [[ ${#@} -gt 0 ]] ; do
		local opt=${1}
		shift
		case ${opt} in
			*)
				action="set-implementation"
				if has ${opt} ${available}; then
					new="${opt}"
				else
					echo "Unrecognized option: ${opt}"
				fi
			;;
		esac
	done

	case ${action} in
		set-implementation)
			if [[ -n ${new} ]] ; then
				set_new_implementation ${new}
                                rc=$?
				sed -i "s/opengl\/xorg-x11\//opengl\/${new}\//" /etc/ld.so.conf
				sed -i "s/opengl\/ati\//opengl\/${new}\//" /etc/ld.so.conf
				sed -i "s/opengl\/nvidia\//opengl\/${new}\//" /etc/ld.so.conf
				ldconfig -X &> /dev/null
				return ${rc}
			else
				echo "Please specify an implementation to set"
			fi
		;;
		*)
			echo "Invalid usage of set action."
		;;
	esac

}

do_show() {
	local current=$(get_current_implementation)
	echo ${current}
}

is_live=$(cat /proc/cmdline | grep cdroot)

if [ -n "$is_live" ]; then
	if [ "$1" == "show" ]; then
		do_show
	else
		do_set $@
	fi
else
	if [ "$1" == "show" ]; then
		eselect opengl show
	else
		eselect opengl set $@
	fi
fi