#!/bin/bash
#
# This is a rather minimal example Argbash potential
# Example taken from http://argbash.readthedocs.io/en/stable/example.html
#
# ARG_OPTIONAL_SINGLE([tg_dir],[t],[path to the contract build target, only used when it's different from],[])
# ARG_OPTIONAL_SINGLE([detector],[d],[detector list, pass multiple detectors seperated by ',', pass 'all' to support all detectors],[all])
# ARG_POSITIONAL_SINGLE([src_dir],[path to the contract source],[])
# ARG_OPTIONAL_SINGLE([output],[o],[location of audit reports],[./audit-result])
# ARG_HELP([The general script's help msg])
# ARGBASH_GO()
# needed because of Argbash --> m4_ignore([
### START OF CODE GENERATED BY Argbash v2.9.0 one line above ###
# Argbash is a bash code generator used to get arguments parsing right.
# Argbash is FREE SOFTWARE, see https://argbash.io for more info
# Generated online by https://argbash.io/generate


die()
{
	local _ret="${2:-1}"
	test "${_PRINT_HELP:-no}" = yes && print_help >&2
	echo "$1" >&2
	exit "${_ret}"
}


begins_with_short_option()
{
	local first_option all_short_options='tdoh'
	first_option="${1:0:1}"
	test "$all_short_options" = "${all_short_options/$first_option/}" && return 1 || return 0
}

# THE DEFAULTS INITIALIZATION - POSITIONALS
_positionals=()
# THE DEFAULTS INITIALIZATION - OPTIONALS
_arg_tg_dir=
_arg_detector="all"
_arg_output="./audit-result"


print_help()
{
	printf '%s\n' "The general script's help msg"
	printf 'Usage: %s [-t|--tg_dir <arg>] [-d|--detector <arg>] [-o|--output <arg>] [-h|--help] <src_dir>\n' "$0"
	printf '\t%s\n' "<src_dir>: path to the contract source"
	printf '\t%s\n' "-t, --tg_dir: path to the contract build target, only used when it's different from (no default)"
	printf '\t%s\n' "-d, --detector: detector list, pass multiple detectors seperated by ',', pass 'all' to support all detectors (default: 'all')"
	printf '\t%s\n' "-o, --output: location of audit reports (default: './audit-result')"
	printf '\t%s\n' "-h, --help: Prints help"
}


parse_commandline()
{
	_positionals_count=0
	while test $# -gt 0
	do
		_key="$1"
		case "$_key" in
			-t|--tg_dir)
				test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
				_arg_tg_dir="$2"
				shift
				;;
			--tg_dir=*)
				_arg_tg_dir="${_key##--tg_dir=}"
				;;
			-t*)
				_arg_tg_dir="${_key##-t}"
				;;
			-d|--detector)
				test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
				_arg_detector="$2"
				shift
				;;
			--detector=*)
				_arg_detector="${_key##--detector=}"
				;;
			-d*)
				_arg_detector="${_key##-d}"
				;;
			-o|--output)
				test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
				_arg_output="$2"
				shift
				;;
			--output=*)
				_arg_output="${_key##--output=}"
				;;
			-o*)
				_arg_output="${_key##-o}"
				;;
			-h|--help)
				print_help
				exit 0
				;;
			-h*)
				print_help
				exit 0
				;;
			*)
				_last_positional="$1"
				_positionals+=("$_last_positional")
				_positionals_count=$((_positionals_count + 1))
				;;
		esac
		shift
	done
}


handle_passed_args_count()
{
	local _required_args_string="'src_dir'"
	test "${_positionals_count}" -ge 1 || _PRINT_HELP=yes die "FATAL ERROR: Not enough positional arguments - we require exactly 1 (namely: $_required_args_string), but got only ${_positionals_count}." 1
	test "${_positionals_count}" -le 1 || _PRINT_HELP=yes die "FATAL ERROR: There were spurious positional arguments --- we expect exactly 1 (namely: $_required_args_string), but got ${_positionals_count} (the last one was: '${_last_positional}')." 1
}


assign_positional_args()
{
	local _positional_name _shift_for=$1
	_positional_names="_arg_src_dir "

	shift "$_shift_for"
	for _positional_name in ${_positional_names}
	do
		test $# -gt 0 || break
		eval "$_positional_name=\${1}" || die "Error during argument parsing, possibly an Argbash bug." 1
		shift
	done
}

parse_commandline "$@"
handle_passed_args_count
assign_positional_args 1 "${_positionals[@]}"

# OTHER STUFF GENERATED BY Argbash

### END OF CODE GENERATED BY Argbash (sortof) ### ])
# [ <-- needed because of Argbash

TOP=$(realpath $(dirname "${BASH_SOURCE[0]}"))
DETECTORS="div-before-mul ext-call inconsistency incorrect-json-type lock-callback non-callback-private non-private-callback prepaid-gas promise-result reentrancy round self-transfer tautology timestamp transfer unhandled-promise unsafe-math unused-ret upgrade-func yocto-attach complex-loop public-interface dup-collection-id storage-gas unregistered-receiver unsaved-changes unclaimed-storage-fee nft-approval-check nft-owner-check"

# export environs
export NEAR_SRC_DIR=$(realpath $_arg_src_dir)
if [[ "$_arg_tg_dir" != "" ]]
then
    export NEAR_TG_DIR=$(realpath $_arg_tg_dir)
else
    export NEAR_TG_DIR=$(realpath $_arg_src_dir)
fi
export CSV_PATH=$(realpath $_arg_output)
export TMP_DIR=$(realpath `pwd`/.rustle-tmp-`date +%s`)

if [[ $(uname -s) = Darwin ]]
then
	SED=gsed
else
	SED=sed
fi

make -C $TOP echo

# set built-in detector type array

# declare -A builtin_detectors
# # for detector in $(echo `ls $TOP/docs/detectors` | sed 's/.md//g')
# for detector in $DETECTORS
# do
#     builtin_detectors[$detector]=1
# done
read -ra builtin_detectors <<< $DETECTORS

# expand severity level
_arg_detector=$(echo $_arg_detector | $SED 's/\ball\b/high,medium,low,info/g')
_arg_detector=$(echo $_arg_detector | $SED 's/\bhigh\b/unhandled-promise,non-private-callback,reentrancy,unsafe-math,self-transfer,incorrect-json-type,unsaved-changes,nft-approval-check,nft-owner-check/g')
_arg_detector=$(echo $_arg_detector | $SED 's/\bmedium\b/div-before-mul,round,lock-callback,yocto-attach,dup-collection-id,unregistered-receiver/g')
_arg_detector=$(echo $_arg_detector | $SED 's/\blow\b/prepaid-gas,non-callback-private,unused-ret,upgrade-func,tautology,storage-gas,unclaimed-storage-fee/g')
_arg_detector=$(echo $_arg_detector | $SED 's/\binfo\b/inconsistency,timestamp,ext-call,promise-result,transfer,complex-loop,public-interface/g')
_arg_detector=$(echo $_arg_detector | $SED 's/\bnep-interface\b/nep141-interface,nep145-interface,nep148-interface,nep171-interface,nep177-interface,nep178-interface,nep181-interface,nep245-interface/g')

# expand by NEP type
## NEP141
_arg_detector=$(echo $_arg_detector | $SED 's/\bnep-ft\b/nep141-interface,self-transfer,unregistered-receiver/g')
## NEP145
_arg_detector=$(echo $_arg_detector | $SED 's/\bnep-storage\b/nep145-interface,unclaimed-storage-fee/g')
## NEP171,NEP178
_arg_detector=$(echo $_arg_detector | $SED 's/\bnep-nft\b/nep171-interface,nft-approval-check,nft-owner-check/g')

# run audit

make -C $TOP clean_tmp

IFS=',' read -ra input_detectors <<< "$_arg_detector"

HAS_RUNNED=false
for i in "${input_detectors[@]}"
do
    if [[ "$i" != "" ]]
    then
        # if [[ ${builtin_detectors[$i]} -eq 1 || $i =~ nep[0-9]+-interface ]]
        if [[ ${builtin_detectors[*]} =~ $i || $i =~ nep[0-9]+-interface ]]
        then
            make -C $TOP $i
            # builtin_detectors[$i]=0  # mark as used
            HAS_RUNNED=true  # mark as used
        else
            echo -e "\e[31m[!] Invalid or repeated detector type: $i\e[0m"  # ]]
        fi
    fi
done

# for detector in ${builtin_detectors[@]}
# do
#     if [[ $detector -eq 0 ]]  # has runned this detector
#     then
if [ $HAS_RUNNED = true ]
then
    make -C $TOP audit-report
fi
#         break
#     fi
# done

make -C $TOP clean_tmp

# ] <-- needed because of Argbash
