#!/bin/bash

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

ICEmu="$DIR/../build/ICEmu"

DEFAULT_ARMV7_CFG="$DIR/cfg/armv7"
DEFAULT_RISCV64_CFG="$DIR/cfg/riscv64"
DEFAULT_RISCV32_CFG="$DIR/cfg/riscv32"

## Plugin directories
PLUGIN_DIR+=(".")

# Read the environment variable ICEMU_PLUGIN_PATH
IFS=':'
read -ra PLUGIN_DIR_ENV <<< "$ICEMU_PLUGIN_PATH"
IFS=' '

if [ ! ${#PLUGIN_DIR_ENV[@]} -eq 0 ]; then
    PLUGIN_DIR+=("${PLUGIN_DIR_ENV[@]}")
fi

# Array with plugin directories
PLUGIN_DIR+=("$DIR/../plugins/build/lib")

## Config directories
CONFIG_DIR+=(".")
CONFIG_DIR+=("$DIR/cfg")

# Read the environment variable ICEMU_CONFIG_PATH
IFS=':'
read -ra CONFIG_DIR_ENV <<< "$ICEMU_CONFIG_PATH"
IFS=' '

if [ ! ${#CONFIG_DIR_ENV[@]} -eq 0 ]; then
    CONFIG_DIR+=("${CONFIG_DIR_ENV[@]}")
fi

function findfile() {
    local ffile=""
    local fname="$1"
    shift
    local arr=("$@")
    for pd in "${arr[@]}"; do
        if [ -f "$pd/$fname" ]; then
            local ffile="$pd/$fname"
            break
        fi
    done

    if [ -z $ffile ]; then
        local ffile="$fname"
    fi

    echo "$(realpath $ffile)"
}

function showfiles() {
    local fname="$1"
    shift
    local arr=("$@")
    for pd in "${arr[@]}"; do
        find $pd -type f -name "$fname" -exec basename {} \;
    done
}

config_file=""
elf_file=""

while (( "$#" )); do
    case $1 in
        -p|--plugin)
            #echo "found plugin arg"
            pass_args+="$1 "
            plugin="$(findfile "$2" "${PLUGIN_DIR[@]}")"
            pass_args+="$plugin "
            shift
            shift
            ;;
        -c|--config-file)
            #echo "found config arg"
            config="$(findfile "$2" "${CONFIG_DIR[@]}")"
            config_file=$(realpath "$config")
            shift
            shift
            ;;
        -h|--help)
            echo "ICEmu wrapper scipt"
            echo "Use --help-wrapper to get information about this helper wrapper"
            echo
            pass_args+="$1 "
            shift
            ;;
        --help-wrapper)
            echo "ICEmu wrapper script options:"
            echo "  --help-wrapper        produce this wrapper help message"
            echo "  -p,--plugin           plugin file name (searches in '.' and plugin dirs)"
            echo "  -c,--config-file      configuration file name (searches in '.' and cfg dirs) use 'none' for no config"
            echo "  --no-config           do not attempt to find/load a config (memory regions provided using -m)"
            echo "  --wrapper-info        print wrapper info and options"
            echo "  --wrapper-plugins     print all found plugins"
            shift
            exit 1
            ;;
        --wrapper-plugins)
            # Dump all plugins
            echo "Plugins:"
            showfiles "*.so" "${PLUGIN_DIR[@]}"
            shift
            exit 1
            ;;
        --wrapper-info)
            # Environment variable info
            echo "Use the environment variable ICEMU_PLUGIN_PATH to add plugin search directories (separated by ':')"
            echo "Use the environment variable ICEMU_CONFIG_PATH to add config search directories (separated by ':')"
            echo

            # Plugin search directories
            echo "Plugin search directories:"
            for p in "${PLUGIN_DIR[@]}"; do
                echo "  $p"
            done
            echo

            # Config search directories
            echo "Config search directories:"
            for c in "${CONFIG_DIR[@]}"; do
                echo "  $c"
            done
            echo

            exit 1
            ;;
        *.elf)
            elf_file="$(realpath $1)"
            pass_args+="$elf_file "
            shift
            ;;
        *)
            #echo "found passtrough"
            pass_args+="$1 "
            shift
            ;;
    esac
done

if [ -z "$elf_file" ]; then
      echo "No ELF file provided"
      exit 1
fi

# Check if a config is provided, otherwise use the default architecture config
if [ -z "$config_file" ]; then
    # Use the default config for the architecture
    if readelf -h $elf_file | grep "Machine" | grep -q "ARM"; then
      echo "ARMv7 architecture detected"
      config_file="$DEFAULT_ARMV7_CFG"

    elif readelf -h $elf_file | grep "Machine" | grep -q "RISC-V"; then

      if readelf -h $elf_file | grep "Class" | grep -q "ELF32"; then
        echo "RISCV32 architecture detected"
        config_file="$DEFAULT_RISCV32_CFG"
      elif readelf -h $elf_file | grep "Class" | grep -q "ELF64"; then
        echo "RISCV64 architecture detected"
        config_file="$DEFAULT_RISCV64_CFG"
      else
        echo "Architecture not detected from ELF and not provided using '-c'"
        exit 1
      fi

    else 
      echo "Architecture not detected from ELF and not provided using '-c'"
      exit 1
    fi

    echo "Config file: $config_file"
fi

# Source the config file (populates ARGS)
ARGS=""
PLUGINS=("")

source "$config_file"

# Get architecture specific plugins
for plug in ${PLUGINS[@]}; do
  plugin="$(findfile "$plug" "${PLUGIN_DIR[@]}")"
  pass_args+="-p $plugin "
done

# Build the command
cmd="$ICEmu $ARGS $pass_args"

# Run the emulator
echo "$cmd"
echo

# Disable memory leak warnings (Unicorn has one, out of our control)
export ASAN_OPTIONS=detect_leaks=0
$cmd
