#!/bin/sh
#
# This script compiles a Bela project on the BeagleBone Black and
# optionally runs it. Pass a directory path in the first argument. 
# The source files in this directory are copied to the board and compiled.

# set defaults unless variables are already set

SCRIPTDIR=$(dirname "$0")
[ -z $SCRIPTDIR ] && SCRIPTDIR="./" || SCRIPTDIR=$SCRIPTDIR/ 
. $SCRIPTDIR.bela_common || { echo "You must be in Bela/scripts to run these scripts" | exit 1; }  

WATCH="0"
usage()
{
	THIS_SCRIPT=`basename "$0"`
	echo "Usage: $THIS_SCRIPT [-c command-line-args] [-nbfF] <directory-with-source-files>"
	echo "
	This script copies a directory of source files to the BeagleBone, compiles
	and runs it. The Bela core files should have first been copied over
	using the setup_board.sh script supplied with Bela.

	The source directory should contain at least one .c, .cpp or .S file.
	If the argument -n is passed, the output will not be run after compiling.
	The -c option passes command-line arguments to
	the Bela program; enclose the argument string in quotes.

	-p arg : sets the name of the project to run (default: $BBB_PROJECT_NAME ) 
	-r arg : additional folder which contents will be copied to the destination folder. Use this, e.g.: for audio files or Pd/pyo sources

	By default, the project runs in the foreground of the current terminal,
	within a screen session that can be detached later. The -f argument runs
	the project in the foreground of the current terminal, without screen, so
	the output can be piped to another destination. The -b argument runs it
	in a screen in the background, so no output is shown. The -m argument allows
	to pass arguments to the Makefile before the run target. For instance,
	pass -m \`"projectclean"\` or \`-m "distclean"\` to clean project-specific
	pre-built objects, or all the pre-built objects, respectively."
}

OPTIND=1

while [ "$2" != "" ]; do
	case $1 in
		-c)
			shift
			COMMAND_ARGS="$1"
		;;
		-b)
			RUN_IN_FOREGROUND=0
		;;
		-f)
			RUN_WITHOUT_SCREEN=1
		;;
		-n)
			RUN_PROJECT=0
		;;
		-p)
			shift
			BBB_PROJECT_NAME="$1"
		;;	
		-r)
			shift
			# TODO: this option can probably be removed, replaced by including multiple paths as regular positional arguments at the end.
			ADDITIONAL_PATH="$1"
		;;
		-m)
			shift
			BBB_MAKEFILE_OPTIONS="$1"
		;;
		--watch)
			WATCH=1
		;;
		-h|-\?)
			usage
			exit 0
		;;
		*)
			usage
			exit 1
		;;
	esac
	shift
done


#Only include all the files if the provided path is not empty
[ -z "$ADDITIONAL_PATH" ] || ADDITIONAL_PATH="$ADDITIONAL_PATH/*"

# Check that we have a directory containing at least one source file
# as an argument

if [ -z "$1" ]
then
	usage
	exit 2
fi

FIND_STRING="find $* -maxdepth 10000 -type f "
EXTENSIONS_TO_FIND='\.cpp\|\.c\|\.S\|\.pd'
FOUND_FILES=$($FIND_STRING | grep "$EXTENSIONS_TO_FIND")
if [ -z "$FOUND_FILES" ]
then
	 printf "ERROR: Please provide a directory containing .c, .cpp, .S or .pd files.\n\n"
	 exit
fi

BBB_PROJECT_FOLDER=$BBB_PROJECT_HOME"/"$BBB_PROJECT_NAME #make sure there is no trailing slash here
BBB_NETWORK_TARGET_FOLDER=$BBB_ADDRESS:$BBB_PROJECT_FOLDER

echo "Stopping running process..."
# sets the date and stop running process
ssh $BBB_ADDRESS "date -s \"`date '+%Y%m%d %T %Z'`\" > /dev/null; mkdir -p $BBB_PROJECT_FOLDER; make QUIET=true --no-print-directory -C $BBB_BELA_HOME stop"

#concatenate arguments to form path.
HOST_SOURCE_PATH= #initially empty, will be filled with input arguments
for i in "$@" #parse input arguments
do
	HOST_SOURCE_PATH+=" $1"
	shift
	# Copy new souce files to the board
done

# This file is used to keep track of when the last upload was made,
# so to check for modifications if WATCH is active
reference_time_file="$SCRIPTDIR/../tmp/"
uploadBuildRun(){
	[ $WATCH -eq 1 ] && touch $reference_time_file
	# Copy new source files to the board
	echo "Copying new source files to BeagleBone..."
	if [ -z "`which rsync`" ];
	then
		#if rsync is not available, brutally clean the destination folder
		#and copy over all the files again and recompile them
		ssh bbb "make --no-print-directory -C $BBB_BELA_HOME sourceclean PROJECT=$BBB_PROJECT_NAME";
		scp -r $HOST_SOURCE_PATH $ADDITIONAL_PATH "$BBB_NETWORK_TARGET_FOLDER"
	else
		#rsync 
		# --delete makes sure it removes files that are not in the origin folder
		# -c evaluates changes using md5 checksum instead of file date, so we don't care about time skews 
		# --no-t makes sure file timestamps are not preserved, so that the Makefile will not think that targets are up to date when replacing files on the BBB
		#  with older files from the host. This will solve 99% of the issues with Makefile thinking a target is up to date when it is not.
		rsync -ac --out-format="   %n" --no-t --delete-after --exclude=$BBB_PROJECT_NAME --exclude=build $HOST_SOURCE_PATH"/" $ADDITIONAL_PATH "$BBB_NETWORK_TARGET_FOLDER/" #trailing slashes used here make sure rsync does not create another folder inside the target folder
	fi

	if [ $? -ne 0 ]
	then
		echo "Error while copying files"
		exit
	fi

	# Make new Bela executable and run
	MAKE_COMMAND="make --no-print-directory QUIET=true -C $BBB_BELA_HOME PROJECT='$BBB_PROJECT_NAME' CL='$COMMAND_ARGS' $BBB_MAKEFILE_OPTIONS"
	if [ $RUN_PROJECT -eq 0 ]
	then
		echo "Building project..."
		ssh $BBB_ADDRESS "$MAKE_COMMAND"
	else
      echo "Building and running project..."
	    if [ $WATCH -eq 1 ]
		then
          if [ $RUN_WITHOUT_SCREEN -eq 1 ];
          then 
              # try to emulate run_without_screen: run with fifo
             ssh $BBB_ADDRESS "$MAKE_COMMAND runscreenfifo" & BACKGROUND_PROCESS_PID=$!
           # run this in the background, it will be killed anyhow when the process stops.
           # Either with the trap below or in another way
             trap "kill $BACKGROUND_PROCESS_PID; exit 0;" 2 9 
           else
             ssh $BBB_ADDRESS "$MAKE_COMMAND runscreen"
           fi
		else
		  if [ $RUN_WITHOUT_SCREEN -ne 0 ]
		  then
		  	ssh -t $BBB_ADDRESS "$MAKE_COMMAND run"	
		  elif [ $RUN_IN_FOREGROUND -eq 0 ]
		  then
		  	ssh $BBB_ADDRESS "$MAKE_COMMAND runscreen"
		  else
		  	ssh -t $BBB_ADDRESS "$MAKE_COMMAND runscreenfg"
		  fi
		fi
	fi
}
# run it once and then (maybe) start waiting for changes
uploadBuildRun

if [ $WATCH -ne 0 ]; then
	while true
	do
		echo "Waiting for changes in $HOST_SOURCE_PATH, or press ctrl-c to terminate"
		CORE_DIR="$SCRIPTDIR/../core"
		INCLUDE_DIR="$SCRIPTDIR/../include"
		wait_for_change $HOST_SOURCE_PATH "$reference_time_file" && {
			echo "Content of "$HOST_SOURCE_PATH" has changed"
		}
		echo "Files changed"
		uploadBuildRun
	done
fi
