#!/bin/bash

function print_usage {
    cat << EOF
Usage: hjc [options] <class-name> ...
where [options] includes:
    -classpath <path>        search path for class files
    -sourcepath <path>       search path for hj source files (must includes path to class-name)
    -destdir <path>          set the location where to output classes
    -racedet                 Enable race-detection instrumentation
    -dcg                     Output dynamic computation graph as a dot file
    -rt <value>              set the targeted hj runtime to compile class for. (s = work-sharing blocking (default) | c = work-sharing cooperative | h workstealing help-first | w = workstealing work-first | a = workstealing adaptive)
    -fj                      Use Fork-Join framework -- experimental (only in work-sharing mode)
    -v -verbose --verbose    print verbose debugging information
    -S<arg>                  [USE WITH CAUTION] pass <arg> directly to soot.
        					 e.g. -S-optName=value (if option has args, = is required and value shouldn't have one)
    -S-info					 print soot information 
    -S-hjVerbose			 print verbose hj related debugging information
    -J-opt					 pass an option directly to the jvm (where opt is what you want to pass ex: -J-Xmx256mo)
    -h -help --help          print this message
    -version --version 	   	 print version number of the hj compiler

    Use "hjc -- -help" to get more detailed help on compiler options
EOF
    exit 1
}

CLASSNAME=
USER_CLASSPATH=
USER_SOURCEPATH=
RT=

RUNTIME_WSH_B="s"
RUNTIME_WSH_C="c"
RUNTIME_WST_HF="h"
RUNTIME_WST_WF="w"

function set_source_file_name() {
	FILENAME_PATH=`echo $args | sed "s/^ //g"`
    
    if [ ! -e "${FILENAME_PATH}" ]; then
        echo "ERROR: cannot find input file ${FILENAME_PATH}"
        exit 1
    fi
	#We extract the source file name
	FILENAME=`echo ${FILENAME_PATH##*/}`
}

function set_sootargs() {
	soot_args_cleaned=""
	for opt in `echo $soot_args`; do
		#opt has the form optName=optValue
		#We want to remove the =
		newOpt=`echo $opt | sed 's/=/ /'`
		soot_args_cleaned="${soot_args_cleaned} $newOpt"
	done
	
	soot_args=${soot_args_cleaned}
}

function set_sourcepath() {
	set_source_file_name

	#We extract the path that prepend the source file name.
	PREPEND_PATH=`echo ${FILENAME_PATH%"$FILENAME"}`

	# if any, we add it to the sourcepath
	if [ ! -z "$PREPEND_PATH" ]; then
		if [ -z "$USER_SOURCEPATH" ]; then
			USER_SOURCEPATH="${PREPEND_PATH}"
		else
			USER_SOURCEPATH="${PREPEND_PATH}:${USER_SOURCEPATH}"
		fi
	fi	
}

function set_classname() {
	set_source_file_name

	#we need to remove .hj suffix, as soot only takes the classname as parameter
	CLASSNAME=`echo $FILENAME | sed 's/.hj$//g'`
}

[ -n "$JAVA_HOME" ] || JAVA_HOME='${env.JAVA_HOME}'

if [ -n "$JAVA_HOME" -a -e "$JAVA_HOME/bin/java" ]; then
    JAVA="$JAVA_HOME/bin/java"
elif [ -n "$JRE_HOME" -a -e "$JRE_HOME/bin/java" ]; then
    JAVA="$JRE_HOME/bin/java"
else
    echo "ERROR: JAVA_HOME ($JAVA_HOME) is not pointing to a JRE or a JDK"
    exit 1
fi

if [ -z "${HJ_HOME}" ]; then
	echo ""
	echo "ERROR: HJ_HOME environment variable must be defined and point to an HJ Distribution"
	echo ""
    exit 1
fi

SOOT_DIST_HOME=${HJ_HOME}
SOOT_DIST_LIB_DIR=${SOOT_DIST_HOME}/lib
SOOT_DIST_LIB_SRCDIR=${SOOT_DIST_LIB_DIR}/src

HJC_CLASSPATH=

for jar in `ls ${SOOT_DIST_LIB_DIR}/*.jar`; do
	HJC_CLASSPATH=${HJC_CLASSPATH}:$jar
done

HJC_SOURCEPATH=${SOOT_DIST_LIB_SRCDIR}

verbose=""
version=""
HjVERBOSE=
java_args=""
soot_args=""
args=""

parse=true
while [ -n "$1" ]; do
    if [ -z "$parse" ]; then
	args="$args $1"
        shift
        continue
    fi
    case "$1" in
        -h|-help|--help) print_usage; break;;
        -v|-verbose|--verbose) verbose="1";;
        -version|--version) version="1";;
        -classpath|-cp) shift; USER_CLASSPATH="$1";;
        -sourcepath|-sp) shift; USER_SOURCEPATH="$1";;
        -destdir|-d) shift; DEST_DIR="$1";;
        -rt) shift; RT="$1";;
        -racedet) RACE_DET_ON="yes";;
        -dcg) DYN_COMP_GRAPH_ON="yes";;
        -J*) java_args="${java_args} ${1##-J}";;
        -S*) soot_args="${soot_args} ${1##-S}";;
        --) parse=;;
        *) args="$args $1";;
    esac
    shift
done

if [ ! -z "$version" ]; then
	JAVA_CMD="$JAVA -Xmx512m -classpath ${HJC_CLASSPATH} soot.hj.HjSootMain -version"
	eval ${JAVA_CMD}
	exit $?
fi

if [ -z "$args" ]; then
	print_usage;
fi 

# soot only takes the Classname as argument, however it will still try to find 
# a Classname.hj file in its path. 
# This check ensures only .hj files will be submit to soot.
hj_src_pattern=*.hj

case $args in 
  $hj_src_pattern) echo "" ;;
  *help)  echo "" ;;
  *) echo "ERROR: Source file $args must have a .hj extension to be compiled"; exit 1;; 
esac

if [ -n "$DYN_COMP_GRAPH_ON" ]; then
    soot_args="${soot_args} -dcg"
fi

if [ -n "$RACE_DET_ON" ]; then
	#default to work-first if -rt is not set
	if [ -z "$RT" ]; then
		RT="${RUNTIME_WST_WF}"
	fi

	# double checking conflicting options
	if [ "$RT" != "w" ]; then
		echo "Error: race-detection instrumentation requires '-rt w' option"
		exit 1;
	else
		soot_args="${soot_args} -racedet"	
	fi
fi

if [ -n "$RT" ]; then
	soot_args="${soot_args} -rt=${RT}"
fi

# convert soot option from '-opt=val' to '-opt val'
set_sootargs

#sets USER_SOURCEPATH
set_sourcepath

#sets CLASSNAME to be compiled
set_classname

if [ ! -z "${soot_args}" ]; then
	SOOT_OPTIONS="${SOOT_OPTIONS} ${soot_args}"
fi

if [ ! -z "$USER_SOURCEPATH" ]; then
	SOOT_OPTIONS="${SOOT_OPTIONS} -sp \".:${HJC_SOURCEPATH}:${USER_SOURCEPATH}\""
else
	SOOT_OPTIONS="${SOOT_OPTIONS} -sp \".:${HJC_SOURCEPATH}\""	
fi 

if [ ! -z "$USER_CLASSPATH" ]; then
	SOOT_OPTIONS="${SOOT_OPTIONS} -cp \"${USER_CLASSPATH}\""
fi 

if [ ! -z "$DEST_DIR" ]; then
	SOOT_OPTIONS="${SOOT_OPTIONS} -d \"${DEST_DIR}\""
fi 


# if no mx options are passed as argument we default vm to 512mo
MX=`echo ${java_args} | grep \\\-Xm`

if [ -z "${MX}" ]; then
	java_args="${java_args} -Xmx512m "
fi

# ensure script terminates as soon as an error detected
set -e

#File to compile, is filename without the .hj extension. That's how soot works...
# main-class is necessary to avoid wst warning that main has been inferred
JAVA_CMD="$JAVA ${java_args} -classpath ${HJC_CLASSPATH} soot.hj.HjSootMain ${SOOT_OPTIONS} -hj -pp -main-class '$CLASSNAME' '$CLASSNAME'"
	
[ -n "$verbose" ] && echo ${JAVA_CMD}

eval ${JAVA_CMD}
exit $?
