#!/bin/bash
#
# Copyright (c) 2016 Nest Labs, Inc.
# All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ---------------------------------------------------------------------------
#
# AUTOANDR v0.1
# =============
#
# Autoandr is a tool for easily generating `Android.mk` files for
# autotools-based projects.
#


# todo: add support for  LOCAL_COPY_HEADERS_TO and LOCAL_COPY_HEADERS

# -- CONSTANTS --------------------------------------------------------------

AUTOANDR_VERSION=0.00.01

AUTOANDR_CFLAGS_SUFFIX=.andr_cflags
AUTOANDR_CXX_FEATURES_SUFFIX=.andr_cxxfeatures
AUTOANDR_INCLUDEPATH_SUFFIX=.andr_includes
AUTOANDR_SOURCE_SUFFIX=.andr_source
AUTOANDR_AIDL_SUFFIX=.andr_aidl

AUTOANDR_MAKE_FLAGS=

if [ -t 1 ]
then
	export ESC_BOLD=${ESC_BOLD-`printf '\033[0;1m'`} # '
	export ESC_NORMAL=${ESC_NORMAL-`printf '\033[0m'`} # '
fi

export AUTOANDR_DIR=${AUTOANDR_DIR-`cd "$(dirname $0)" && pwd`}
export SOURCE_DIR=${SOURCE_DIR-`pwd`}
export BUILD_DIR=${BUILD_DIR-${SOURCE_DIR}/etc/android}
export DESTDIR=${DESTDIR-${BUILD_DIR}/root}

export V=${V-0}

# -- FUNCS AND UTILS --------------------------------------------------------

die() {
	echo " *** ${ESC_BOLD}Fatal Error${ESC_NORMAL} $*" > /dev/stderr
	exit 1
}

show_version() {
	echo "autoandr ${AUTOANDR_VERSION}"
}

announce_pass() {
	echo " *** ${ESC_BOLD}${*}${ESC_NORMAL}"
}

announce_tool() {
	local tool=$1
	shift
	echo " * ${ESC_BOLD}${tool}${ESC_NORMAL} $*"
}

announce_path() {
	echo " ** ${ESC_BOLD}path${ESC_NORMAL} $*"
}


source_pwd() {
	echo "${SOURCE_DIR}/$(proj_pwd)"
}

library_converter() {
	while [[ $# -ge 1 ]]
	do
		case $1 in
			dbus-1) echo dbus ;;
			util) ;;
			*) echo $1 ;;
		esac
		shift
	done
}

proj_path() {
	local tmp="$*"
	tmp="${tmp#$BUILD_DIR}"
	tmp="${tmp#$SOURCE_DIR}"
	echo "${tmp#/}"
}

proj_pwd() {
	proj_path `pwd`
}

full_real_path() {
	local dir_name=`dirname $1`
	local base_name=`basename $1`
	if test -d $dir_name
	then printf "%s/%s\n" "$(cd $dir_name && pwd)" "$base_name"
	else echo $1
	fi
}

adjust_include_path() {
	includedir=$(full_real_path "${1}")
	rel_includedir="$(rel_path ${includedir})"

	[ -z "${rel_includedir}" ] && continue
	if [ "${rel_includedir::1}" = "." ]
	then rel_includedir='$(LOCAL_PATH)/'"${rel_includedir}"
	fi

	if test "${includedir#$SOURCE_DIR}" == "${includedir}"
	then rel_includedir="${includedir#$ANDROID_BUILD_TOP/}"
	fi
	echo "${rel_includedir}"
}

rel_path() {
	local target=$(cd `dirname "${1}"` 2>/dev/null && pwd || dirname "${1}" )/`basename "${1}"`
	local common_part=`pwd`
	local result=""

	if [[ "${target:0:1}" == "/" ]]
	then
		while [[ "${target#$common_part}" == "${target}" ]]; do
			# no match, means that candidate common part is not correct
			# go up one level (reduce common part)
			common_part="$(dirname $common_part)"
			# and record that we went back, with correct / handling
			if [[ -z $result ]]; then
				result=".."
			else
				result="../$result"
			fi
		done

		if [[ $common_part == "/" ]]; then
			# special case for root (no common path)
			result="$result/"
		fi

		# since we now have identified the common part,
		# compute the non-common part
		forward_part="${target#$common_part}"

		# and now stick all parts together
		if [[ -n $result ]] && [[ -n $forward_part ]]; then
			result="$result$forward_part"
		elif [[ -n $forward_part ]]; then
			# extra slash removal
			result="${forward_part:1}"
		fi
	else
		result="${target}"
	fi

	echo $result
}

# This function checks the arguments that would be passed to a `cc`-like
# program to see if the output is going to be an executable or an object
# file. This is needed because autotools uses `cc` as a linker when making
# executables. This function allows us to quickly determine the intent.
is_ccld() {
	while [[ $# -ge 1 ]]
	do
		case $1 in
			-c)
				return 1 # false
				;;
		esac
		shift
	done

	return 0 # true
}

# ---------------------------------------------------------------------------

androidmake_prep() {
	local parentdir

	if ! [ -f Android.mk ]
	then
		(
			echo "# File automatically generated by $(show_version)"
			echo "# \"`proj_pwd`\""
			echo "#"
			echo
			echo 'LOCAL_PATH := $(call my-dir)'
		) > Android.mk

		localpath="$(pwd)"
		parentdir="$(cd .. && pwd)"

		if [[ "$(cd $BUILD_DIR/.. && pwd)" != "${parentdir}" ]] && [[ "${SOURCE_DIR}" != "${parentdir}" ]] && [[ "${SOURCE_DIR}" != "${localpath}" ]]
		then
			(cd .. && androidmake_prep)
			grep -q all-subdir-makefiles ../Android.mk || echo 'include $(call all-subdir-makefiles)' >> ../Android.mk
		fi
	fi
}

# Arguments: <object-name> <source-file>
androidmake_object_begin() {
	ANDROIDMAKE_OBJECT_NAME=$1
	ANDROIDMAKE_SOURCE_FILE=$2

	if [ -f "${ANDROIDMAKE_SOURCE_FILE}${AUTOANDR_AIDL_SUFFIX}" ]
	then
		announce_tool aidl-object `basename ${ANDROIDMAKE_OBJECT_NAME}`: $(basename $2)
		cp "${ANDROIDMAKE_SOURCE_FILE}${AUTOANDR_AIDL_SUFFIX}" "${ANDROIDMAKE_OBJECT_NAME}"${AUTOANDR_AIDL_SUFFIX}
		cp "${ANDROIDMAKE_SOURCE_FILE}${AUTOANDR_INCLUDEPATH_SUFFIX}" "${ANDROIDMAKE_OBJECT_NAME}"${AUTOANDR_INCLUDEPATH_SUFFIX}
	else
		announce_tool object `basename ${ANDROIDMAKE_OBJECT_NAME}`: $(basename $2)
		echo "$2" > "${ANDROIDMAKE_OBJECT_NAME}"${AUTOANDR_SOURCE_SUFFIX}
	fi
}

# Arguments: <c-flags>
androidmake_object_cflags() {
	[ "${ANDROIDMAKE_OBJECT_NAME}" != "" ] || die "Internal error"
	echo "$@" >> "${ANDROIDMAKE_OBJECT_NAME}"${AUTOANDR_CFLAGS_SUFFIX}
}

# Arguments: <c++-features>
androidmake_object_cxx_features() {
	[ "${ANDROIDMAKE_OBJECT_NAME}" != "" ] || die "Internal error"
	echo "$@" >> "${ANDROIDMAKE_OBJECT_NAME}"${AUTOANDR_CXX_FEATURES_SUFFIX}
}

# Arguments: <header-include-paths>
androidmake_object_include_paths() {
	[ "${ANDROIDMAKE_OBJECT_NAME}" != "" ] || die "Internal error"
	if ! [ -f "${ANDROIDMAKE_SOURCE_FILE}${AUTOANDR_AIDL_SUFFIX}" ]
	then echo "$@" >> "${ANDROIDMAKE_OBJECT_NAME}"${AUTOANDR_INCLUDEPATH_SUFFIX}
	fi
}

androidmake_object_end() {
	[ "${ANDROIDMAKE_OBJECT_NAME}" != "" ] || die "Internal error"
	unset ANDROIDMAKE_OBJECT_NAME
	unset ANDROIDMAKE_SOURCE_FILE
}



# Arguments: <source-name> <aidl-file>
androidmake_aidl_begin() {
	ANDROIDMAKE_AIDL_OUTPUT=$1
	ANDROIDMAKE_AIDL_INPUT=$2
	announce_tool aidl `basename ${ANDROIDMAKE_AIDL_INPUT}`

	mkdir -p `dirname ${ANDROIDMAKE_AIDL_OUTPUT}` || die "Unable to mkdir `dirname ${ANDROIDMAKE_AIDL_OUTPUT}`"
	echo "${ANDROIDMAKE_AIDL_INPUT}" > "${ANDROIDMAKE_AIDL_OUTPUT}"${AUTOANDR_AIDL_SUFFIX}
}

# Arguments: <header-dir>
androidmake_aidl_header_dir() {
	[ "${ANDROIDMAKE_AIDL_OUTPUT}" != "" ] || die "Internal error"
	[ "${ANDROIDMAKE_AIDL_INPUT}" != "" ] || die "Internal error"
	# Nothing to do here?
}

# Arguments: <aidl-include-paths>*
androidmake_aidl_include_paths() {
	[ "${ANDROIDMAKE_AIDL_INPUT}" != "" ] || die "Internal error"
	[ "${ANDROIDMAKE_AIDL_OUTPUT}" != "" ] || die "Internal error"
	echo $* >> "${ANDROIDMAKE_AIDL_OUTPUT}"${AUTOANDR_INCLUDEPATH_SUFFIX}
}

androidmake_aidl_end() {
	[ "${ANDROIDMAKE_AIDL_INPUT}" != "" ] || die "Internal error"
	[ "${ANDROIDMAKE_AIDL_OUTPUT}" != "" ] || die "Internal error"
	unset ANDROIDMAKE_AIDL_OUTPUT
	unset ANDROIDMAKE_AIDL_INPUT
}



# Arguments: <module-name>
androidmake_module_begin() {
	ANDROIDMAKE_MODULE_NAME=$1
	androidmake_prep
	(
		echo ''
		echo "#### BEGIN ${ANDROIDMAKE_MODULE_NAME} ####"
		echo 'include $(CLEAR_VARS)'
		echo "LOCAL_MODULE := ${ANDROIDMAKE_MODULE_NAME}"
	) >> $ANDROIDMAKE_MODULE_NAME.Android.mk
	rm -f $ANDROIDMAKE_MODULE_NAME.Android.mk.tmp || die
}

androidmake_module_tags() {
	[ "${ANDROIDMAKE_MODULE_NAME}" != "" ] || die "Internal error"
	(
		echo 'LOCAL_MODULE_TAGS +=' "$@"
	) >> $ANDROIDMAKE_MODULE_NAME.Android.mk.tmp
}

androidmake_module_dependency() {
	[ "${ANDROIDMAKE_MODULE_NAME}" != "" ] || die "Internal error"
	(
		echo "LOCAL_ADDITIONAL_DEPENDENCIES +=" $1
	) >> $ANDROIDMAKE_MODULE_NAME.Android.mk.tmp
}

androidmake_module_path_64() {
	[ "${ANDROIDMAKE_MODULE_NAME}" != "" ] || die "Internal error"
	(
		echo "LOCAL_MODULE_PATH_64 := \$(PRODUCT_OUT)$1"
	) >> $ANDROIDMAKE_MODULE_NAME.Android.mk
}

androidmake_module_link_shared_library() {
	[ "${ANDROIDMAKE_MODULE_NAME}" != "" ] || die "Internal error"
	(
		echo "LOCAL_SHARED_LIBRARIES +=" $1
	) >> $ANDROIDMAKE_MODULE_NAME.Android.mk.tmp
}

androidmake_module_link_static_library() {
	[ "${ANDROIDMAKE_MODULE_NAME}" != "" ] || die "Internal error"
	(
		echo "LOCAL_STATIC_LIBRARIES +=" $1
	) >> $ANDROIDMAKE_MODULE_NAME.Android.mk.tmp
}

# Arguments: <object-name>
androidmake_module_add_object() {
	[ "${ANDROIDMAKE_MODULE_NAME}" != "" ] || die "Internal error"
	object=$1
	if [ -f ${object}${AUTOANDR_AIDL_SUFFIX} ]
	then
		source_file=`rel_path $(cat ${object}${AUTOANDR_AIDL_SUFFIX})`
		(
			echo "LOCAL_SRC_FILES +=" ${source_file}
			for includedir in $(cat ${object}${AUTOANDR_INCLUDEPATH_SUFFIX})
			do
				echo "LOCAL_AIDL_INCLUDES += $(adjust_include_path "$includedir")"
			done
		) >> $ANDROIDMAKE_MODULE_NAME.Android.mk.tmp
	else
		source_file=`rel_path $(cat ${object}${AUTOANDR_SOURCE_SUFFIX})`
		(
			echo "LOCAL_SRC_FILES +=" ${source_file}
			if [ "${source_file%.cpp}" != "${source_file}" ]
			then # C++ File
				cat ${object}${AUTOANDR_CFLAGS_SUFFIX} | sed "s/\\\\\"/'\\\\\"'/g;" | xargs -n 1 echo "LOCAL_CPPFLAGS +="
			else # C file
				cat ${object}${AUTOANDR_CFLAGS_SUFFIX} | sed "s/\\\\\"/'\\\\\"'/g;" | xargs -n 1 echo "LOCAL_CFLAGS +="
			fi
			for includedir in $(cat ${object}${AUTOANDR_INCLUDEPATH_SUFFIX})
			do
				echo "LOCAL_C_INCLUDES += $(adjust_include_path "$includedir")"
			done
			cat ${object}${AUTOANDR_CXX_FEATURES_SUFFIX} | xargs -n 1 echo "LOCAL_CPP_FEATURES +="
		) >> $ANDROIDMAKE_MODULE_NAME.Android.mk.tmp
	fi
}

androidmake_module_allow_shlib_undefined() {
	[ "${ANDROIDMAKE_MODULE_NAME}" != "" ] || die "Internal error"
	(
		echo "LOCAL_ALLOW_UNDEFINED_SYMBOLS := true"
	) >> $ANDROIDMAKE_MODULE_NAME.Android.mk.tmp
}

androidmake_module_end_exec() {
	[ "${ANDROIDMAKE_MODULE_NAME}" != "" ] || die "Internal error"
	(
		grep LOCAL_STATIC_LIBRARIES $ANDROIDMAKE_MODULE_NAME.Android.mk.tmp
		sort -u $ANDROIDMAKE_MODULE_NAME.Android.mk.tmp | grep -v LOCAL_STATIC_LIBRARIES
		echo 'include $(BUILD_EXECUTABLE)'
		echo "#### END ${ANDROIDMAKE_MODULE_NAME} ####"
	) >> $ANDROIDMAKE_MODULE_NAME.Android.mk
	rm -f $ANDROIDMAKE_MODULE_NAME.Android.mk.tmp
	#lockfile -1 -r 3 Android.mk.lock || die Lock failure
	cat $ANDROIDMAKE_MODULE_NAME.Android.mk >> Android.mk
	#rm -fr Android.mk.lock
	rm -f $ANDROIDMAKE_MODULE_NAME.Android.mk
	unset ANDROIDMAKE_MODULE_NAME
}

androidmake_module_end_shared_lib() {
	[ "${ANDROIDMAKE_MODULE_NAME}" != "" ] || die "Internal error"
	(
		grep LOCAL_STATIC_LIBRARIES $ANDROIDMAKE_MODULE_NAME.Android.mk.tmp
		sort -u $ANDROIDMAKE_MODULE_NAME.Android.mk.tmp | grep -v LOCAL_STATIC_LIBRARIES
		echo 'include $(BUILD_SHARED_LIBRARY)'
		echo "#### END ${ANDROIDMAKE_MODULE_NAME} ####"
	) >> $ANDROIDMAKE_MODULE_NAME.Android.mk
	rm -f $ANDROIDMAKE_MODULE_NAME.Android.mk.tmp
	#lockfile -1 -r 3 Android.mk.lock || die Lock failure
	cat $ANDROIDMAKE_MODULE_NAME.Android.mk >> Android.mk
	#rm -fr Android.mk.lock
	rm -f $ANDROIDMAKE_MODULE_NAME.Android.mk
	unset ANDROIDMAKE_MODULE_NAME
}

androidmake_module_end_static_lib() {
	[ "${ANDROIDMAKE_MODULE_NAME}" != "" ] || die "Internal error"
	(
		grep LOCAL_STATIC_LIBRARIES $ANDROIDMAKE_MODULE_NAME.Android.mk.tmp
		sort -u $ANDROIDMAKE_MODULE_NAME.Android.mk.tmp | grep -v LOCAL_STATIC_LIBRARIES
		echo 'include $(BUILD_STATIC_LIBRARY)'
		echo "#### END ${ANDROIDMAKE_MODULE_NAME} ####"
	) >> $ANDROIDMAKE_MODULE_NAME.Android.mk
	rm -f $ANDROIDMAKE_MODULE_NAME.Android.mk.tmp
	#lockfile -1 -r 3 Android.mk.lock || die Lock failure
	cat $ANDROIDMAKE_MODULE_NAME.Android.mk >> Android.mk
	#rm -fr Android.mk.lock
	rm -f $ANDROIDMAKE_MODULE_NAME.Android.mk
	unset ANDROIDMAKE_MODULE_NAME
}

# -- ARGUMENT PARSERS  ------------------------------------------------------

handle_cc() {
	if [[ ${AUTOANDR_MODE} == "make" ]]
	then (

		INCLUDE_PATHS=
		SOURCES=
		CFLAGS=
		OUTPUT=
		CXX_FEATURES=
		DEPENDS="${AUTOANDR_DEPENDS}"

		while [[ $# -ge 1 ]]
		do
			case $1 in
				-include)
					CFLAGS="${CFLAGS} $1 $2"
					shift
					;;

				-I*|-i*)
					INCLUDE_PATHS="${INCLUDE_PATHS} ${1:2}"
					;;

				--AUTOANDR-DEPENDS,*|--AUTOANDR-DEPENDS=*)
					DEPENDS="${DEPENDS} ${1:19}"
					;;

				-frtti|-fexceptions)
					# For some reason, the LOCAL_CPP_FEATURES
					# variable doesn't seem to be working, so
					# we just pass these as normal CFLAGS.
					#CXX_FEATURES="${CXX_FEATURES} ${1:2}"
					CFLAGS="${CFLAGS} $(printf "%q" "$1")"
					;;

				-Werror)
					# Ignore -Werror, if present.
					;;

				-f*|-W*|-D*|-U*|-pthread|-std=*|-O[0-9]|-pedantic-*)
					CFLAGS="${CFLAGS} $(printf "%q" "$1")"
					;;

				-o)
					shift
					OUTPUT="$1"
					;;

				*.c|*.cpp)
					SOURCES="${SOURCES} $1"
					;;

				-g|-O[0-9]|-c)
					# Ignore these
					;;

				*)
					echo "    $# UNKNOWN \"$1\""
					;;
			esac
			shift
		done
		if [ -z "${OUTPUT}" ]
		then return 0
		fi

		touch "${OUTPUT}"

		androidmake_object_begin ${OUTPUT} ${SOURCES}
		androidmake_object_cflags "${CFLAGS}"
		androidmake_object_cxx_features "${CXX_FEATURES}"
		androidmake_object_include_paths "${INCLUDE_PATHS}"
		androidmake_object_end

	) >&3
	elif [[ ${AUTOANDR_MODE} == "install" ]]
	then true
	else false
	fi
}

handle_ccld() {
	if [[ ${AUTOANDR_MODE} == "make" ]]
	then (
		OBJECTS=
		OUTPUT=
		LIBRARIES=
		STATIC_LIBRARIES=
		CFLAGS=
		OUTPUT_SHARED_LIBRARY=0
		ALLOW_SHLIB_UNDEFINED=1
		DEPENDS="${AUTOANDR_DEPENDS}"
		TAGS=${AUTOANDR_MODULE_TAGS}
		while [[ $# -ge 1 ]]
		do
			case $1 in
				-o)
					shift
					OUTPUT="$1"
					;;
				-shared)
					OUTPUT_SHARED_LIBRARY=1
					;;
				-Wl,--allow-shlib-undefined)
					ALLOW_SHLIB_UNDEFINED=1
					;;
				-Wl*)
					# Linker stuff. Ignore for now.
					;;
				--AUTOANDR-MODULE-TAG=*)
					TAGS="${TAGS} ${1:25}"
					;;
				--AUTOANDR-DEPENDS,*|--AUTOANDR-DEPENDS=*)
					DEPENDS="${DEPENDS} ${1:19}"
					;;
				--AUTOANDR-MODULE-PATH-64=*)
					AUTOANDR_MODULE_PATH_64="${1:26}"
					;;
				--AUTOANDR,-l*)
					LIBRARIES="${LIBRARIES} ${1:13}"
					;;
				-l*)
					LIBRARIES="${LIBRARIES} ${1:2}"
					;;
				*.so|*.la)
					lib=${1:2}
					lib=$(basename ${lib%.so})
					lib=$(basename ${lib%.la})
					LIBRARIES="${LIBRARIES} $lib"
					;;
				-f*|-W*|-U*|-D*|-pthread|-pedantic-*)
					CFLAGS="${CFLAGS} ${1}"
					;;
				-L*|-I*)
					# Ignore library and header search paths
					;;
				*.a)
					STATIC_LIBRARIES="${STATIC_LIBRARIES} $1"
					;;
				*.o|*.lo)
					OBJECTS="${OBJECTS} $1"
					;;
				-g|-O[0-9]|-c|-std=*)
					# Ignore these
					;;
				-V)
					# Version query.
					return 0
					;;
				--AUTOANDR*)
					echo " >>> Unknown autoandr argument $1"
					;;
				*)
					echo "    $# UNKNOWN \"$1\""
					;;
			esac
			shift
		done

		if [ "${OUTPUT}" != "${OUTPUT%.so}" ] || [ "${OUTPUT}" != "${OUTPUT%.so.0.0.0}" ]
		then OUTPUT_SHARED_LIBRARY=1
		fi

		OUTPUT=${OUTPUT%.so.0.0.0}
		OUTPUT=${OUTPUT%.so}
		OUTPUT=$(basename $OUTPUT)

		announce_tool link "${OUTPUT}"

		androidmake_module_begin ${OUTPUT}
		if test "${AUTOANDR_MODULE_PATH_64}" != ""
		then androidmake_module_path_64 "${AUTOANDR_MODULE_PATH_64}"
		fi
		for tag in ${TAGS}
		do androidmake_module_tags ${tag}
		done
		for object in ${OBJECTS}
		do androidmake_module_add_object ${object}
		done
		for depend in $(library_converter ${DEPENDS})
		do androidmake_module_dependency ${depend}
		done
		for lib in $(library_converter ${LIBRARIES})
		do androidmake_module_link_shared_library lib${lib#lib}
		done
		for lib in ${STATIC_LIBRARIES}
		do androidmake_module_link_static_library $(basename ${lib%.a})
		done
		if [ "${OUTPUT_SHARED_LIBRARY}" = "1" ]
		then
			[ "${ALLOW_SHLIB_UNDEFINED}" = "1" ] && androidmake_module_allow_shlib_undefined
			androidmake_module_end_shared_lib
		else androidmake_module_end_exec
		fi

	) >&3
	elif [[ ${AUTOANDR_MODE} == "install" ]]
	then true
	else false
	fi
}

handle_libtool() {
	# We use this to extract library arguments when building static libraries.

	if [[ ${AUTOANDR_MODE} == "make" ]]
	then (
		COMMAND="${AUTOANDR_LIBTOOL} $@"
		export AUTOANDR_LIBTOOL_LIBS=
		export AUTOANDR_DEPENDS=
		export AUTOANDR_MODULE_PATH_64=
		while [[ $# -ge 1 ]]
		do
			case $1 in
				-l*)
					AUTOANDR_LIBTOOL_LIBS="${AUTOANDR_LIBTOOL_LDFLAGS} ${1:2}"
					COMMAND="${COMMAND} --AUTOANDR,$1"
					;;
				--AUTOANDR-DEPENDS,*|--AUTOANDR-DEPENDS=*)
					AUTOANDR_DEPENDS="${AUTOANDR_DEPENDS} ${1:19}"
					;;
				--AUTOANDR-MODULE-PATH-64=*)
					AUTOANDR_MODULE_PATH_64="${1:26}"
					;;
				--AUTOANDR*)
					echo " >>> Unknown autoandr argument $1"
					;;
				*)
					;;
			esac
			shift
		done

		${COMMAND} "$@" >&4

		true
	) 4>&1 >&3
	elif [[ ${AUTOANDR_MODE} == "install" ]]
	then true
	else false
	fi
}


handle_aidl_cpp() {
	if [[ ${AUTOANDR_MODE} == "make" ]]
	then (
		INPUT_FILE=
		HEADER_DIR=
		OUTPUT_FILE=
		INCLUDE_PATHS=

		while [[ $# -ge 1 ]]
		do
			case $1 in
				-I*|-i*)
					INCLUDE_PATHS="${INCLUDE_PATHS} ${1:2}"
					;;

				*.cxx|*.cpp)
					OUTPUT_FILE="$1"
					;;

				*.aidl)
					INPUT_FILE="$1"
					;;

				-g|-O[0-9]|-c)
					# Ignore these
					;;

				*)
					HEADER_DIR="$1"
					;;
			esac
			shift
		done

		[ -n "${OUTPUT_FILE}" ] || return 0
		[ -n "${INPUT_FILE}" ] || return 0
		[ -n "${HEADER_DIR}" ] || return 0

		mkdir -p `dirname ${OUTPUT_FILE}` || die "Unable to mkdir `dirname ${OUTPUT_FILE}`"
		touch "${OUTPUT_FILE}"

		androidmake_aidl_begin ${OUTPUT_FILE} ${INPUT_FILE}
		androidmake_aidl_header_dir ${HEADER_DIR}
		androidmake_aidl_include_paths ${INCLUDE_PATHS}
		androidmake_aidl_end

	) >&3
	elif [[ ${AUTOANDR_MODE} == "install" ]]
	then true
	else false
	fi
}

handle_ar() {
	if [[ ${AUTOANDR_MODE} == "make" ]]
	then (
		OUTPUT=
		LIBRARIES=${AUTOANDR_LIBTOOL_LIBS}
		STATIC_LIBRARIES=
		OBJECTS=

		shift
		OUTPUT=`basename $1`
		shift
		while [[ $# -ge 1 ]]
		do
			case $1 in
				*.a)
					STATIC_LIBRARIES="${STATIC_LIBRARIES} $1"
					;;
				*.o|*.lo)
					OBJECTS="${OBJECTS} $(rel_path $1)"
					;;
				*)
					echo "    $# UNKNOWN \"$1\""
					;;
			esac
			shift
		done
		if [ -z "${OUTPUT}" ]
		then return 0
		fi

		touch "${OUTPUT}"

		OUTPUT=${OUTPUT%.a}
		OUTPUT=$(basename $OUTPUT)

		announce_tool link-lib "${OUTPUT}"

		androidmake_module_begin ${OUTPUT}
		if test "${AUTOANDR_MODULE_PATH_64}" != ""
		then androidmake_module_path_64 "${AUTOANDR_MODULE_PATH_64}"
		fi
		for tag in ${AUTOANDR_MODULE_TAGS}
		do androidmake_module_tags ${tag}
		done
		for object in ${OBJECTS}
		do androidmake_module_add_object ${object}
		done
		for depend in $(library_converter ${AUTOANDR_DEPENDS})
		do androidmake_module_dependency ${depend}
		done
		for lib in $(library_converter ${LIBRARIES})
		do androidmake_module_link_shared_library lib${lib#lib}
		done
		for lib in ${STATIC_LIBRARIES}
		do androidmake_module_link_static_library $(basename ${lib%.a})
		done
		androidmake_module_end_static_lib

	) >&3
	elif [[ ${AUTOANDR_MODE} == "install" ]]
	then true
	else false
	fi
}

handle_make() {
	if [[ ${AUTOANDR_MODE} == "make" ]]
	then
		[[ $1 == "all" ]] && (
		announce_path "$(proj_pwd)"

	) >&3
	fi
}


# -- COMMANDS ---------------------------------------------------------

autoandr_cc() {
	[ -z ${AUTOANDR_MODE} ] && die "missing mode"

	if is_ccld "$@"
	then handle_ccld "$@" || ${AUTOANDR_CC} "$@"
	else handle_cc "$@" || ${AUTOANDR_CC} "$@"
	fi
}

autoandr_cxx() {
	[ -z ${AUTOANDR_MODE} ] && die "missing mode"

	if is_ccld "$@"
	then handle_ccld "$@" || ${AUTOANDR_CXX} "$@"
	else handle_cc "$@" || ${AUTOANDR_CXX} "$@"
	fi
}

autoandr_libtool() {
	[ -z ${AUTOANDR_MODE} ] && die "missing mode"

	handle_libtool "$@" || ${AUTOANDR_LIBTOOL} "$@"
}

autoandr_ccld() {

	[ -z ${AUTOANDR_MODE} ] && die "missing mode"

	handle_ccld "$@" ||

	${AUTOANDR_CCLD} "$@"
}

autoandr_aidl_cpp() {

	[ -z ${AUTOANDR_MODE} ] && die "missing mode"

	handle_aidl_cpp "$@" ||

	${AUTOANDR_AIDL_CPP} "$@"
}


autoandr_cxxld() {
	[ -z ${AUTOANDR_MODE} ] && die "missing mode"

	handle_ccld "$@" ||

	${AUTOANDR_CXXLD} "$@"
}

autoandr_ld() {
	[ -z ${AUTOANDR_MODE} ] && die "missing mode"

	if [[ ${AUTOANDR_MODE} == "make" ]]
	then
		echo " **" ld "$@" >&3
	fi

	${AUTOANDR_LD} "$@"
}

autoandr_cpp() {
	[ -z ${AUTOANDR_MODE} ] && die "missing mode"

	${AUTOANDR_CPP} "$@"
}

autoandr_ar() {
	[ -z ${AUTOANDR_MODE} ] && die "missing mode"

	handle_ar "$@" ||

	${AUTOANDR_AR} "$@"
}

autoandr_ranlib() {
	[ -z ${AUTOANDR_MODE} ] && die "missing mode"

	if [[ ${AUTOANDR_MODE} != "make" ]]
	then ${AUTOANDR_RANLIB} "$@"
	fi

	true
}

autoandr_make() {
	[ -z ${AUTOANDR_MODE} ] && die "missing mode"

	handle_make "$@"

	${AUTOANDR_MAKE} "$@"
}

autoandr_install() {
	[ -z ${AUTOANDR_MODE} ] && die "missing mode"

	if [[ ${AUTOANDR_MODE} == "install" ]]
	then
		announce_tool install "$*" >&3
	else
		${AUTOANDR_INSTALL} "$@"
	fi
}

# ---------------------------------------------------------------------------

autoandr_cleanup() {
	if [ "${AUTOANDR_SKIP_CLEANUP}" == 1 ]
	then
		announce_pass "SKIPPING CLEANING UP"
		return
	fi

	announce_pass "CLEANING UP"

	[ "${BUILD_DIR}" != "/" ] || die "Build directory is root"
	[ "${DESTDIR}" != "/" ] || die "DESTDIR is root"

	cd ${BUILD_DIR}

	find . "(" \
		-name Makefile \
		-o -name Makefile.in \
		-o -name config.status \
		-o -name .libs \
		-o -name '*.[oa]' \
		-o -name '*.[sl]o' \
		-o -name '*.la' \
		-o -name '*.dylib' \
		-o -name '.deps' \
		-o -name '.dirstamp' \
		-o -name 'stamp-h[0-9]' \
		-o -name 'config.log' \
		-o -name 'libtool' \
		-o -name 'I*.cpp' \
		-o -name '*'${AUTOANDR_CFLAGS_SUFFIX} \
		-o -name '*'${AUTOANDR_CXX_FEATURES_SUFFIX} \
		-o -name '*'${AUTOANDR_INCLUDEPATH_SUFFIX} \
		-o -name '*'${AUTOANDR_SOURCE_SUFFIX} \
		-o -name '*'${AUTOANDR_AIDL_SUFFIX} \
		")" -print0 \
	| xargs -0 rm -rf || die

	rm -fr ${DESTDIR}
}

first() {
	echo $1
}

autoandr_start() {
	# Set up our environment

	# Maybe the root was specified with the NDK environment variable.
	[ -z "${NDK_ROOT}" ] && NDK_ROOT="${NDK}"

	# Maybe the NDK is in the path. If so, grab it via `which`.
	[ -z "${NDK_ROOT}" ] && NDK_ROOT=$(dirname `which ndk-build 2>/dev/null`)

	[ -z "${NDK_ROOT}" ] && die "\$NDK_ROOT environment variable not set!"
	[ -d "${NDK_ROOT}" ] || die "NDK root doesn't seem to exist (\"$NDK_ROOT\")"

	export NDK_ROOT
	export NDK=${NDK-$NDK_ROOT}

	export SYSROOT=${SYSROOT-$NDK/platforms/android-21/arch-arm}

	export PKG_CONFIG_PATH=/dev/null
	export PKG_CONFIG_LIBDIR=/dev/null
	export PKG_CONFIG_DATADIR=/dev/null

	export PATH="${NDK_ROOT}:${PATH}"

	HOST=$(basename `ndk-which gcc`)
	HOST=${HOST%-gcc}

	echo NDK_ROOT=${NDK_ROOT}
	echo HOST=${HOST}

	export AUTOANDR_CC=${CC-$(ndk-which gcc) --sysroot=$SYSROOT}
	export AUTOANDR_CCLD=${CCLD-$AUTOANDR_CC}
	export AUTOANDR_AR=${AR-$(ndk-which ar)}
	export AUTOANDR_LD=${LD-$(ndk-which ld)}
	export AUTOANDR_CPP=${CPP-$(ndk-which cpp) --sysroot=$SYSROOT}
	export AUTOANDR_CXX=${CXX-$(ndk-which c++) --sysroot=$SYSROOT}
	export AUTOANDR_CXXLD=${CXXLD-$AUTOANDR_CXX}
	export AUTOANDR_MAKE=${MAKE-make}
	export AUTOANDR_INSTALL=${INSTALL-install}
	export AUTOANDR_RANLIB=${RANLIB-$(ndk-which ranlib)}
	export AUTOANDR_AIDL_CPP=${AIDL_CPP-$(ndk-which aidl-cpp)}
	export AUTOANDR_LIBTOOL=${LIBTOOL-${BUILD_DIR}/libtool}

	# Make sure the build directory exists
	mkdir -p "${BUILD_DIR}" || die "Unable to create \"${BUILD_DIR}\""

	# Make sure DESTDIR exists
	mkdir -p "${DESTDIR}" || die "Unable to create \"${DESTDIR}\""

	# Make sure BUILD_DIR is absolute.
	BUILD_DIR=$(cd "${BUILD_DIR}" && pwd) || die "Unable to normalize build directory path"

	# Make sure SOURCE_DIR is absolute.
	SOURCE_DIR=$(cd "${SOURCE_DIR}" && pwd) || die "Unable to normalize source directory path"

	# Make sure DESTDIR is absolute.
	DESTDIR=$(cd "${DESTDIR}" && pwd) || die "Unable to normalize DESTDIR"

	# Sanity checks
	[ "${SOURCE_DIR::1}" == "/" ] || die "SOURCE_DIR is not an absolute path"
	[ "${BUILD_DIR::1}" == "/" ] || die "BUILD_DIR is not an absolute path"
	[ "${DESTDIR::1}" == "/" ] || die "DESTDIR is not an absolute path"
	[ "${BUILD_DIR}" != "${SOURCE_DIR}" ] || die "Build directory same as source directory"
	[ "${BUILD_DIR}" != "/" ] || die "Build directory is root"
	[ "${DESTDIR}" != "/" ] || die "DESTDIR is root"

	# Clean up our build directory
	rm -fr "${BUILD_DIR}"
	mkdir -p "${BUILD_DIR}"

	# Make a root Android.mk file
	cd "${SOURCE_DIR}" || die
	rm -f Android.mk
	androidmake_prep
	echo 'include $(LOCAL_PATH)/'$(rel_path "${BUILD_DIR}")'/Android.mk' >> ${SOURCE_DIR}/Android.mk

	cd "${BUILD_DIR}" || die

	announce_pass "CONFIGURE PASS"
	export AUTOANDR_MODE=configure
	( "${SOURCE_DIR}/configure"                    \
		CC="${AUTOANDR_DIR}/autoandr cc"         \
		CCLD="${AUTOANDR_DIR}/autoandr ccld"         \
		LD="${AUTOANDR_DIR}/autoandr ld"         \
		CPP="${AUTOANDR_DIR}/autoandr cpp"       \
		AR="${AUTOANDR_DIR}/autoandr ar"      \
		CXX="${AUTOANDR_DIR}/autoandr cxx"    \
		CXXLD="${AUTOANDR_DIR}/autoandr cxxld"    \
		MAKE="${AUTOANDR_DIR}/autoandr make"    \
		INSTALL="${AUTOANDR_DIR}/autoandr install"    \
		RANLIB="${AUTOANDR_DIR}/autoandr ranlib"    \
		AIDL_CPP="${AUTOANDR_DIR}/autoandr aidl-cpp"    \
		--disable-dependency-tracking             \
		--with-gnu-ld \
		--host=${HOST} \
		ac_cv_func_getdtablesize=no \
		ac_cv_func_fgetln=no \
		ac_cv_header_util_h=no \
		${OTHER_CONFIGURE_FLAGS}                  \
		"$@"                                       \
	) 3>&1 1> "${AUTOANDR_STDOUT}" || die "Configure script failed"

	announce_pass "MAKE PASS"
	export AUTOANDR_MODE=make
	( autoandr_make all V=1 \
		${AUTOANDR_MAKE_FLAGS} \
		MAKE="${AUTOANDR_DIR}/autoandr make" \
		CCLD="${AUTOANDR_DIR}/autoandr ccld"         \
		CXXLD="${AUTOANDR_DIR}/autoandr cxxld"   \
		CXXLINK="${AUTOANDR_DIR}/autoandr cxxld"   \
		LIBTOOL="\$(SHELL) ${AUTOANDR_DIR}/autoandr libtool"   \
		AIDL_CPP="${AUTOANDR_DIR}/autoandr aidl-cpp"    \
	) 3>&1 1> "${AUTOANDR_STDOUT}" || die

	# Skipping install pass for now
	#
	#announce_pass "INSTALL PASS"
	#export AUTOANDR_MODE=install
	#( autoandr_make install V=1 \
	#	${AUTOANDR_MAKE_FLAGS} \
	#	DESTDIR=${DESTDIR} \
	#	MAKE="${AUTOANDR_DIR}/autoandr make" \
	#	CCLD="${AUTOANDR_DIR}/autoandr ccld"         \
	#	CXXLD="${AUTOANDR_DIR}/autoandr cxxld"    \
	#) 3>&1 1> "${AUTOANDR_STDOUT}" || die

	autoandr_cleanup

	cd ${SOURCE_DIR} || die

	marker="Added by autoandr"
	if sed -i.bak "/# $marker\$/d" Makefile.in
	then
		rm Makefile.in.bak
	else
		die "Call to 'sed' failed"
	fi
	echo "EXTRA_DIST += Android.mk" $(find `rel_path "${BUILD_DIR}"` -type f) "# $marker" >> Makefile.in
}


show_help() {
	show_version
	echo ""
	echo "syntax: autoandr [general-args] <command> [command-args]"
	echo ""
	echo "General Arguments:"
	echo "    -v,--verbose .................... Verbose output"
	echo "    -V,--version .................... Print version"
	echo "    -?,-h,--help .................... Show help"
	echo ""
	echo "Commands:"
	echo ""
	echo "    start <configure-args>"
	echo "        Starts the process of building the Android.mk files."
	echo "        Must be executed from the root of the project. Any"
	echo "        arguments that you want passed to the configure script"
	echo "        should be specified after the command."
	echo ""
}

# ---------------------------------------------------------------------------

# Parse the arguments present before the command
while [[ $# -ge 1 ]]
do
	case $1 in
		-v|--verbose)
			AUTOANDR_STDOUT=/dev/stdout
			;;
		-V|--version)
			show_version
			exit 0
			;;
		-j*)
			AUTOANDR_MAKE_FLAGS="${AUTOANDR_MAKE_FLAGS} $1"
			;;
		-*)
			die "Unknown argument \"$1\""
			;;
		*)
			break
			;;
	esac
	shift
done

AUTOANDR_STDOUT=${AUTOANDR_STDOUT-/dev/null}

case $1 in
	cc)       shift ; autoandr_cc "$@" ;;
	ccld)     shift ; autoandr_ccld "$@" ;;
	ar)       shift ; autoandr_ar "$@" ;;
	ld)       shift ; autoandr_ld "$@" ;;
	cxx)      shift ; autoandr_cxx "$@" ;;
	cxxld)    shift ; autoandr_cxxld "$@" ;;
	libtool)  shift ; autoandr_libtool "$@" ;;
	cpp)      shift ; autoandr_cpp "$@" ;;
	make)     shift ; autoandr_make "$@" ;;
	install)  shift ; autoandr_install "$@" ;;
	ranlib)   shift ; autoandr_ranlib "$@" ;;
	aidl-cpp) shift ; autoandr_aidl_cpp "$@" ;;

	start)    shift ; autoandr_start "$@" ;;
	cleanup)  shift ; autoandr_cleanup "$@" ;;

	*)        die "Unknown command \"$1\"" ;;
esac
