#!/usr/bin/env bash

set -eu
set -o pipefail 2> /dev/null || true

variety=""
args=""
pre_command=""
post_command=""
sep="%"
stdin_pipe=""

function usage
{
	retval="$1"
	echo "$0: --variety var --args args --pre-command cmd --separator % --stdin-pipe cmd" 1>&2
	exit "$retval"
}

while [ "$#" -ge 1 ]
do
	case "$1" in
		--separator)
			sep="$2"
			shift
			;;
		--variety)
			variety="$2"
			shift
			;;
		--args)
			shift
			args="$@"
			break
			;;
		--stdin-pipe)
			stdin_pipe="$2"
			shift
			;;
		--pre-command)
			pre_command="$2"
			shift
			;;
		--post-command)
			post_command="$2"
			shift
			;;
		*)
			echo "$0: Illegal option: $1" 1>&2
			usage 1
			;;
	esac
	shift
done

# About IronPython:
# 		IronPython 2.6 Beta 2 doesn't work with backshift.  It's possible FePy
# 		would - it's supposed to have a patched standard library to facilitate
# 		compatibility with the python standard library.
#
# 		ipy (IronPython), at least on Ubuntu 11.04, seems to just use the
# 		system's CPython standard library, which results in tracebacks.
#
# 		I see no FePy package for Ubuntu, although there was an IronPython
# 		package for Ubuntu 11.04.

function list_interpreter
{
	report_any=False
	report_all=False
	interpreters=""
	expected_major=""
	require_rcpyxm=False

	while [ "$#" -ge 1 ]
	do
		case "$1" in
			--require-rcpyxm)
				require_rcm=True
				;;
			--any)
				report_any=True
				;;
			--all)
				report_all=True
				;;
			--major)
				expected_major="$2"
				shift
				;;
			--interpreters)
				shift
				interpreters="$@"
				# And eat the arguments still in argv
				while [ "$#" -ge 1 ]
				do
					shift
				done
				;;
			*)
				echo "$0: list_interprer: Valid options include --any, --all, --interpreters, but not $1" 1>&2
				exit 1
				;;
		esac
		shift
	done

	if [ "$report_any" = True ]
	then
		if [ "$report_all" = True ]
		then
			echo "$0: list_interprer: --any and -all are mutually exclusive" 1>&2
			exit 1
		elif [ "$report_all" = False ]
		then
			: Good
		else
			echo "$0: list_interprer: report_any is True, but report_all is $report_all" 1>&2
			exit 1
		fi
	elif [ "$report_any" = False ]
	then
		if [ "$report_all" = True ]
		then
			: Good
		elif [ "$report_all" = False ]
		then
			echo "$0: list_interprer: You must give exactly one of --any and -all" 1>&2
			exit 1
		else
			echo "$0: list_interprer: report_any is False, but report_all is $report_all" 1>&2
			exit 1
		fi
	else
		echo "$0: list_interprer: report_any should be True or False, but is $report_any" 1>&2
		exit 1
	fi

	if [ "$interpreters" = "" ]
	then
		echo "$0: list_interprer: --interpreters is a required option" 1>&2
		exit 1
	fi

	if [ "$expected_major" = "" ]
	then
		echo "$0: list_interprer: --major is a required option" 1>&2
		exit 1
	fi

	at_least_one_found=False

	for record in $interpreters
	do
		basename=$(set -eu; echo "$record" | awk -F"$sep" ' { print $1 }')
		interp=$(set -eu; echo "$record" | awk -F"$sep" ' { print $2 }')
		if [ -e "$interp" ]
		then
			actual_major=$(set -eu; "$interp" -c "import sys; print(sys.version_info[0])")
			actual_minor=$(set -eu; "$interp" -c "import sys; print(sys.version_info[1])")
			case "$actual_major" in
				2)
					if [ "$actual_minor" -lt 5 ]
					then
						# We only support 2.5 and up.  2.4 is too old.
						continue
					fi
					;;
				3)
					;;
				*)
					# Could be too old, could be too new
					echo "$0: list_interprer: actual_major is not 2 or 3: $actual_major" 1>&2
					exit 1
					;;
			esac
			#echo "actual_major is $actual_major, expected_major is $expected_major" 1>&2
			if [ "$actual_major" != "$expected_major" ]
			then
				continue
			fi
			if [ "$require_rcpyxm" = True ]
			then
				if ! "$interp" -c 'import rolling_checksum_pyx_mod' > /dev/null 2>&1
				then
					continue
				fi
			fi
			echo "$basename""$sep""$interp"
			at_least_one_found=True
			if [ "$report_any" = True ]
			then
				return 0
			fi
		fi
	done

	if [ "$at_least_one_found" = True ]
	then
		return 0
	elif [ "$at_least_one_found" = False ]
	then
		return 1
	else
		echo "$0: list_interprer: at_least_one_found is neither True nor False: $at_least_one_found" 1>&2
		exit 1
	fi
}

function list_compiler
{
	report_any=False
	report_all=False
	compilers=""

	while [ "$#" -ge 1 ]
	do
		case "$1" in
			--any)
				report_any=True
				;;
			--all)
				report_all=True
				;;
			--compilers)
				shift
				compilers="$@"
				while [ "$#" -ge 1 ]
				do
					shift
				done
				break
				;;
			*)
				echo "$0: list_compiler: Unrecognized option: $1" 1>&2
				exit 1
				;;
		esac
		shift
	done
	if [ "$report_any" = True ] && [ "$report_all" = True ]
	then
		echo "$0: list_compiler: --any and --all are mutually exclusive" 1>&2
		exit 1
	fi
	if [ "$report_any" = False ] && [ "$report_all" = False ]
	then
		echo "$0: list_compiler: You must specify one of --any and --all" 1>&2
		exit 1
	fi
	if [ "$compilers" = "" ]
	then
		echo "$0: list_compiler: You must specify --compilers" 1>&2
		exit 1
	fi
	at_least_one_found=False
	for record in $compilers
	do
		basename=$(echo "$record" | awk -F"$sep" ' { print $1 }')
		file=$(echo "$record" | awk -F"$sep" ' { print $2 }')
		if [ -e "$file" ]
		then
			at_least_one_found=True
			echo "$basename$sep$file"
			if [ "$report_any" = True ]
			then
				break
			fi
		fi
	done
	if [ "$at_least_one_found" = True ]
	then
		return 0
	elif [ "$at_least_one_found" = False ]
	then
		return 1
	else
		echo "$0: list_compiler: \$at_least_one_found has a strange value: $at_least_one_found" 1>&2
		exit 1
	fi
}

function list_cython2
{
	if [ "$1" = --any ]
	then
		quantifier="--any"
	elif [ "$1" = --all ]
	then
		quantifier="--all"
	else
		echo "$0: list_cython2: \$1 is not --any or --all" 1>&2
		exit 1
	fi
	list_compiler "$quantifier" --compilers \
		cython2%/usr/local/cpython-2.7/bin/cython \
		cython2%/usr/local/cpython-2.6/bin/cython \
		cython2%/usr/local/cpython-2.5/bin/cython
}

function list_cython3
{
	if [ "$1" = --any ]
	then
		quantifier="--any"
	elif [ "$1" = --all ]
	then
		quantifier="--all"
	else
		echo "$0: list_cython3: \$1 is not --any or --all" 1>&2
		exit 1
	fi
	list_compiler "$quantifier" --compilers \
		cython3%/usr/local/cpython-3.2/bin/cython \
		cython3%/usr/local/cpython-3.1/bin/cython \
		cython3%/usr/local/cpython-3.0/bin/cython
}

function list_pypy2
{
	if [ "$1" = --any ]
	then
		quantifier="--any"
	elif [ "$1" = --all ]
	then
		quantifier="--all"
	else
		echo "$0: list_pypy2: \$1 is not --any or --all" 1>&2
		exit 1
	fi
	list_interpreter "$quantifier" --major 2 --interpreters \
		pypy-trunk-2011-06-26"$sep"/usr/local/pypy-trunk-2011-06-26/bin/pypy \
		pypy-1.5"$sep"/usr/local/pypy-1.5/bin/pypy \
		pypy-1.4.1"$sep"/usr/local/pypy-1.4.1/bin/pypy \
		pypy-1.4"$sep"/usr/local/pypy-1.4/bin/pypy \
		pypy-1.3"$sep"/usr/local/pypy-1.3/bin/pypy
}

function list_cpython2
{
	if [ "$1" = --any ]
	then
		quantifier="--any"
	elif [ "$1" = --all ]
	then
		quantifier="--all"
	else
		echo "$0: list_cpython2: \$1 is not --any or --all" 1>&2
		exit 1
	fi
	list_interpreter "$quantifier" --major 2 --interpreters \
		cpython-2.7"$sep"/usr/local/cpython-2.7/bin/python \
		usr-local-bin-python2.7"$sep"/usr/local/bin/python2.7 \
		cpython-2.6"$sep"/usr/local/cpython-2.6/bin/python \
		usr-local-bin-python2.6"$sep"/usr/local/bin/python2.6 \
		cpython-2.5"$sep"/usr/local/cpython-2.5/bin/python \
		usr-local-bin-python2.5"$sep"/usr/local/bin/python2.5 \
		usr-local-bin-python2"$sep"/usr/local/bin/python2 \
		usr-local-bin-python"$sep"/usr/local/bin/python \
		usr-bin-python"$sep"/usr/bin/python \
		usr-bin-python2"$sep"/usr/bin/python2 \
		boot-common-bin-python"$sep"/boot/common/bin/python
}

function list_cpython3
{
	if [ "$1" = --any ]
	then
		quantifier="--any"
	elif [ "$1" = --all ]
	then
		quantifier="--all"
	else
		echo "$0: list_cpython3: \$1 is not --any or --all" 1>&2
		exit 1
	fi
	list_interpreter "$quantifier" --major 3 --interpreters \
		cpython-3.2"$sep"/usr/local/cpython-3.2/bin/python3 \
		usr-local-bin-python3.2"$sep"/usr/local/bin/python3.2 \
		cpython-3.1"$sep"/usr/local/cpython-3.1/bin/python3 \
		usr-local-bin-python3.1"$sep"/usr/local/bin/python3.1 \
		cpython-3.0"$sep"/usr/local/cpython-3.0/bin/python3 \
		usr-local-bin-python3.0"$sep"/usr/local/bin/python3.0 \
		usr-local-bin-python3"$sep"/usr/local/bin/python3 \
		usr-local-bin-python"$sep"/usr/local/bin/python \
		usr-bin-python"$sep"/usr/bin/python \
		usr-bin-python3"$sep"/usr/bin/python3 \
		boot-common-bin-python"$sep"/boot/common/bin/python
}

function list_jython2
{
	if [ "$1" = --any ]
	then
		quantifier="--any"
	elif [ "$1" = --all ]
	then
		quantifier="--all"
	else
		echo "$0: list_jython2: \$1 is not --any or --all" 1>&2
		exit 1
	fi
	list_interpreter "$quantifier" --major 2 --interpreters \
		jython"$sep"/usr/local/jython-2.5.2-r7288/bin/jython
}

function list_relevant
{
	case "$variety" in
		all)
			list_pypy2 --all
			list_cpython2 --all
			list_cpython3 --all
			list_jython2 --all
			;;
		fast)
			# Each of these has a side effect of outputting the interpreter path when something is found
			if list_pypy2 --any
			then
				# PyPy's always the fastest, at least until we get the Cython code tuned better
				:
			elif list_cpython3 --any --require-rcpyxm
			then
				# CPython 3 with Cython is next best
				:
			elif list_cpython2 --any --require-rcpyxm
			then
				# CPython 2 with Cython is next best
				:
			elif list_jython2 --any
			then
				# Jython is next best - but only if appropriately patched, of course
				:
			elif list_cpython2 --any
			then
				# CPython 2 is next best
				:
			elif list_cpython3 --any
			then
				# CPython 3 is next best
				:
			else
				echo "$0: Wow, no python?" 1>&2
				exit 1
			fi
			;;
		minimal-a)
			if list_cpython2 --any
			then
				:
			elif list_pypy2 --any
			then
				:
			elif list_jython2 --any
			then
				:
			elif list_cpython3 --any
			then
				:
			else
				echo "$0: no minimal-a?" 1>&2
				exit 1
			fi
			;;
		minimal-b)
			if list_cpython3 --any
			then
				:
			elif list_jython2 --any
			then
				:
			elif list_pypy2 --any
			then
				:
			elif list_cpython2 --any
			then
				:
			else
				echo "$0: no minimal-b" 1>&2
				exit 1
			fi
			;;
		just-a-cython)
			if list_cython2 --any
			then
				:
			elif list_cython3 --any
			then
				:
			else
				echo "$0: No cytthon's found" 1>&2
				exit 1
			fi
			;;
		*)
			echo "$0: unrecognized variety: $variety" 1>&2
			exit 1
			;;
	esac
}

if [ "$args" = "" ]
then
	# just list the possibilities
	list_relevant || true
else
	# Execute
	relevant=$(set -eu; list_relevant || true)
	if [ "$relevant" = "" ]
	then
		echo "$0: No relevant interpreters found" 1>&2
		exit 1
	else
		for record in $relevant
		do
			export basename=$(set -eu; echo "$record" | awk -F"$sep" ' { print $1 }')
			interp=$(set -eu; echo "$record" | awk -F"$sep" ' { print $2 }')
			if [ "$pre_command" != "" ]
			then
				eval "$pre_command"
			fi
			if [ "$stdin_pipe" = "" ]
			then
				eval "$interp" $(set -eu; eval echo "$args")
			else
				eval $(echo "$stdin_pipe") | eval "$interp" $(set -eu; eval echo "$args")
			fi
			if [ "$post_command" != "" ]
			then
				eval "$post_command"
			fi
		done
	fi
fi