#!/usr/bin/env bash

# Copyright (C) 2022 NETINT Technologies
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

# This script is intended to help customers install Netint Android environment

script_version="v1.3"

# configure variables for terminal color text based on OS
function setup_terminal_colors() {
    if [[ $SHELL =~ .*zsh ]]; then
        cRst="\x1b[0m"
        cRed="\x1b[31m"
        cGrn="\x1b[32m"
        cYlw="\x1b[33m"
        cBlu="\x1b[34m"
        cMag="\x1b[35m"
        cCyn="\x1b[36m"
    else
        cRst="\e[0m"
        cRed="\e[31m"
        cGrn="\e[32m"
        cYlw="\e[33m"
        cBlu="\e[34m"
        cMag="\e[35m"
        cCyn="\e[36m"
    fi
}

# if release package folder exists and it matches expected md5sum, use folder for installation;
# else if tarball exists, use tarball;
# else proceed without FW/SW release
function select_tarball_vs_folder() {
    fw_folder=$(find . -maxdepth 1 -type d | grep -Poh 'Quadra_FW_V[0-9A-Z\.]{5}_[0-9A-Za-z]{3}$' | sort -V)
    if [ -f "md5sum" ] && [ ! -z $fw_folder ]; then
        expected_md5=$(grep "${fw_folder}" md5sum | grep -Poh '(?<=^# )[0-9a-f]{32}(?=  )')
        actual_md5=$(cd ${fw_folder}; find . -type f -not -iwholename '*.git*' -exec md5sum {} \; | LC_ALL='C' sort -k 2 | md5sum | head -c -4)
        if [[ "$expected_md5" != "$actual_md5" ]]; then
            fw_folder=""
        fi
    else
        fw_folder=""
    fi
    if [ -z $fw_folder ]; then
        fw_pack=$(ls Quadra_FW_V*.*.*.tar.gz | sort -V | tail -n 1)
        if [ ! -z $fw_pack ]; then
            fw_folder=$(echo ${fw_pack} | grep -Poh 'Quadra_FW_V[0-9A-Z\.]{5}_[0-9A-Za-z]{3}(?=\.tar\.gz)')
        fi
    fi

    sw_folder=$(find . -maxdepth 1 -type d | grep -Poh 'Quadra_SW_V[0-9A-Z\.]{5}_[0-9A-Za-z]{3}$' | sort -V)
    if [ -f "md5sum" ] && [ ! -z $sw_folder ]; then
        expected_md5=$(grep "${sw_folder}" md5sum | grep -Poh '(?<=^# )[0-9a-f]{32}(?=  )')
        actual_md5=$(cd ${sw_folder}; find . -type f -not -iwholename '*.git*' -exec md5sum {} \; | LC_ALL='C' sort -k 2 | md5sum | head -c -4)

        if [[ "$expected_md5" != "$actual_md5" ]]; then
            sw_folder=""
        else
            sw_release_num=$(echo ${sw_folder} | grep -Poh '(?<=Quadra_SW_V)[0-9A-Z\.]{5}_[0-9A-Za-z]{3}')
        fi
    else
        sw_folder=""
    fi
    if [ -z $sw_folder ]; then
        sw_pack=$(ls Quadra_SW_V*.*.*.tar.gz | sort -V | tail -n 1)
        if [ ! -z $sw_pack ]; then
            sw_folder=$(echo ${sw_pack} | grep -Poh 'Quadra_SW_V[0-9A-Z\.]{5}_[0-9A-Za-z]{3}(?=\.tar\.gz)')
            sw_release_num=$(echo ${sw_folder} | grep -Poh '(?<=Quadra_SW_V)[0-9A-Z\.]{5}_[0-9A-Za-z]{3}')
        fi
    fi
}

function install_yasm() {
    echo "======== install yasm ========"
    rc=1
    curl -O http://www.tortall.net/projects/yasm/releases/yasm-1.3.0.tar.gz &&
    tar -zxf yasm-1.3.0.tar.gz && rm yasm-1.3.0.tar.gz && cd yasm-1.3.0/ &&
    ./configure && make && sudo make install && cd .. &&
    rm -rf yasm-1.3.0 && echo "Successfully installed yasm" &&
    rc=0
    return $rc
}

function install_os_prereqs() {
    echo "======== Install prerequisite software packages ========"
    rc=0
    sudo apt-get update
    info="in"
    soft_list=("libssl-dev" "m4" "libncurses5" "zip" "git" "build-essential" "make" "cmake" "gcc" "g++" "patch" "ncurses-dev" "valgrind" "pkg-config" "curl")
    for i in "${soft_list[@]}"; do
        echo "Start install $i"
        sudo apt-get install "$i" -y
        if [ $? -eq 0 ]; then
            echo "Successfully install $i"
        else
            echo -e "${cRed}Error${cRst}: failed to install $i"
            rc=1
            exit 1
        fi
    done

    PY_VERSION=$(python -V 2>&1 | awk '{print $2}' | awk -F '.' '{print $1}')
    if [ $PY_VERSION == 2 ]; then
        echo "python2 has already installed, python version is ${PY_VERSION}"
    else
        echo 'Need install python2 '
        sudo apt-get install "$i" -y
        if [ $? -eq 0 ]; then
            echo "Successfully install $i"
            sudo ln -s /usr/bin/python2.7 /usr/bin/python
        else
            echo -e "${cRed}Error${cRst}: failed to install $i"
            rc=1
            exit 1
        fi
    fi
    return $rc
}

# $1 - Download source: "global" or "china"
function download_build_aosp() {
    echo "======== download and build aosp ========"
    rc=1
    mkdir ~/bin
    # This option is used by users in China
    if [ "$1" == "china" ]; then
        curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo >~/bin/repo && echo "OK" || exit 1
        chmod a+x ~/bin/repo
        export PATH=~/bin:$PATH

        u_n=$(git config --list | grep -E user.name)
        u_e=$(git config --list | grep -E user.email)
        if [ -z "$u_n" ]; then
            read -p 'Please input your git config user.name: ' name
            git config --global user.name $name
        fi

        if [ -z "$u_e" ]; then
            read -p 'Please input your git config user.email: ' email
            git config --global user.email $email
        fi

        sed -i 's/https:\/\/gerrit.googlesource.com\/git-repo/https:\/\/mirrors.tuna.tsinghua.edu.cn\/git\/git-repo/g' ~/bin/repo
        if [ -n "$(nl ~/bin/repo | sed -n '/https:\/\/gerrit.googlesource.com\/git-repo/p')" ]; then
            echo -e "${cRed}Error${cRst}: in ~/bin/repo, failed to replace googlesource git upstream with tsinghua git upstream. Please rectify manually."
            exit 1
        fi

        mkdir /home/$USER/$WORK_DIR
        cd /home/$USER/$WORK_DIR
        repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-9.0.0_r35

    # This option is used by other users
    elif [ "$1" == "global" ]; then
        curl http://commondatastorage.googleapis.com/git-repo-downloads/repo >~/bin/repo && echo "OK" || exit 1
        chmod a+x ~/bin/repo
        export PATH=~/bin:$PATH
        mkdir /home/$USER/$WORK_DIR
        cd /home/$USER/$WORK_DIR
        repo init -u https://android.googlesource.com/platform/manifest -b android-9.0.0_r35 --depth=1
    else
        echo "The parameter input is invalid, please re-enter it"
        exit 1
    fi

    if [ $? -eq 0 ]; then
        echo 'Successfully downloaded android-9.0.0_r35'
        echo 'Start repo sync'
        repo sync -c -j 8
    else
        echo -e "${cRed}Error${cRst}: failed to download android-9.0.0_r35"
        exit 1
    fi

    source build/envsetup.sh
    lunch $LUNCH_CMD
    make -j `nproc`
    if [ $? -eq 0 ]; then
        echo "Successfully ran 'make ${LUNCH_CMD}'"
    else
        echo -e "${cRed}Error${cRst}: failed to run 'make ${LUNCH_CMD}'"
        exit 1
    fi
    cd $base_dir && rc=0
    return $rc
}

function download_build_android_kernel() {
    echo "======== download and build Android kernel ========"
    rc=1
    if [ "$1" == "china" ]; then
        kernel_url="https://aosp.tuna.tsinghua.edu.cn/kernel/goldfish"
    elif [ "$1" == "global" ]; then
        kernel_url="https://android.googlesource.com/kernel/goldfish"
    else
        echo "The parameter input is invalid, please re-enter it"
        exit 1
    fi

    cd /home/$USER/$WORK_DIR || exit
    git clone -b android-goldfish-4.4-dev --depth 1 $kernel_url
    if [ $? -eq 0 ]; then
        echo 'Successfully downloaded Android kernel'
        echo 'compiling Android kernel'
        cd /home/$USER/$WORK_DIR/goldfish || exit
        # both 32 bit and 64 bit Android will use x86_64 for the Android kernel
        make ARCH=x86_64 x86_64_ranchu_defconfig
        if [ $? -eq 0 ]; then
            echo -e "Successfully compiled Android kernel"
        else
            echo -e "${cRed}Error${cRst}: failed to run 'make ARCH=x86_64 x86_64_ranchu_defconfig'"
            exit 1
        fi
    else
        echo -e "${cRed}Error${cRst}: failed to download Android kernel"
        exit 1
    fi

    # #auto
    # cp $base_dir/patch/.config ./
    #Manual
    sed -i '1261i CONFIG_BLK_DEV_NVME=y' .config
    sed -i '3434i CONFIG_NVMEM=y' .config
    sed -i '3380i CONFIG_AMD_IOMMU=y' .config
    cmd1=$(nl .config | sed -n '/CONFIG_BLK_DEV_NVME=y/p')
    cmd2=$(nl .config | sed -n '/CONFIG_NVMEM=y/p')
    cmd3=$(nl .config | sed -n '/CONFIG_AMD_IOMMU=y/p')
    if [ -z "$cm1" ] && [ -z "$cmd2" ] && [ -z "$cmd3" ]; then
        echo -e "${cRed}Error${cRst}: failed to modify Android kernel .config"
        exit 1
    fi
    make ARCH=x86_64 -j8 && cd $base_dir && rc=0
    return $rc
}

function verify_android_emulator() {
    echo "======== verify android emulator ========"
    rc=1
    soft_list1=(qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils cpu-checker)

    info="installed"
    for i in "${soft_list1[@]}"; do
        echo "Start install $i"
        cmd=$(sudo apt list --installed 2>/dev/null | grep $i)
        if [[ "${cmd}" == *"${info}"* ]]; then
            echo "$i install (SUCCESS)"
        else
            sudo apt-get install $i -y
        fi
    done

    #If libvirt-clients cannot be installed, you may need to replace it with libvirt bin and reinstall it
    sudo adduser $(id -un) kvm &&
        sudo chown $(id -un):$(id -un) -R /dev/kvm &&
        kvm-ok

    rm -rf emulator.log
    cd /home/$USER/$WORK_DIR &&
        source build/envsetup.sh
    lunch $LUNCH_CMD
    echo "emulator -wipe-data -writable-system -verbose -netdelay none -netspeed full -gpu off -no-window -qemu -kernel goldfish/arch/x86/boot/bzImage >$base_dir/emulator.log 2>&1 &"
    emulator -wipe-data -writable-system -verbose -netdelay none -netspeed full -gpu off -no-window -qemu -kernel goldfish/arch/x86/boot/bzImage >$base_dir/emulator.log 2>&1 &
    info='emulator: INFO: boot completed'
    echo "waiting check emulator state"

    sleep 10
    for i in {0..50}; do
        echo "Loop $i"
        out=$(cat $base_dir/emulator.log | grep completed)
        if [ "$out" = "${info}" ]; then
            echo -e "Successfully booted Android emulator"
            break
        elif (($i > 49)); then
            echo -e "${cRed}Error${cRst}: Failed to boot Android emulator"
            exit 1
        else
            sleep 5
        fi
    done

    cd $base_dir && rc=0
    return $rc
}

function install_vfio() {
    echo "======== Install VFIO ========"
    echo "Installing virt-manager"
    sudo apt-get install virt-manager -y
    sudo apt-get install python-spice-client-gtk -y

    # determine CPU vendor and edit grub
    cpuVendorName=$(lscpu | grep Vendor | egrep -o "(AMD|Intel)" | tr '[:upper:]' '[:lower:]')
    echo "Enabling ${cpuVendorName}_iommu in GRUB"
    if egrep -q "^GRUB_CMDLINE_LINUX(_DEFAULT)?=.*${cpuVendorName}_iommu=off" /etc/default/grub; then
        sudo sed -Ei "s/^(GRUB_CMDLINE_LINUX(_DEFAULT)?=.*)${cpuVendorName}_iommu=off/\1${cpuVendorName}_iommu=on/g" /etc/default/grub
    else
        sudo sed -Ei "s/^GRUB_CMDLINE_LINUX(_DEFAULT)?=\"/GRUB_CMDLINE_LINUX\1=\"${cpuVendorName}_iommu=on /g" /etc/default/grub
    fi
    # update grub
    sudo update-grub

    # reboot
    echo -e "${cRed}WARNING${cRst}: Please reboot computer, then proceed with next step."
}

function check_path_vfio() {
    echo "======== check vfio driver in kernel path ========"
    rc=1
    if [ ! -d /lib/modules/$(uname -r)/kernel/drivers/vfio ]; then
        echo -e "${cRed}Error${cRst}: vfio driver files not found in /lib/modules/$(uname -r)/kernel/drivers/vfio/. You may need to switch kernel version in grub boot"
        exit 1
    fi
    echo "vfio driver files found at /lib/modules/$(uname -r)/kernel/drivers/vfio/"
    rc=0
    return $rc
}

function check_insmod_vfio() {
    echo "======== check vfio driver loaded ========"
    rc=1
    sudo modprobe vfio
    sudo modprobe vfio-pci
    modinfo vfio-pci
    if [ $? -eq 0 ]; then
        echo "Successfully checked vfio-pci driver is online"
    else
        echo -e "${cRed}Error${cRst}: vfio-pci driver is not online. VFIO might not be properly installed"
        exit 1
    fi
    rc=0
    return $rc
}

function vfio_bind() {
    echo "======== Performing NVME unbind & VFIO bind ========"
    rc=1
    #modify /etc/security/limits.conf
    user=$(whoami)
    total_mem=$(free | grep Mem | awk '{print $2}')
    if ! cat /etc/security/limits.conf | egrep "^$USER +hard +memlock +$total_mem"; then
        sed -i "\$i${user} hard memlock ${total_mem}" /etc/security/limits.conf
    fi
    if ! cat /etc/security/limits.conf | egrep "^$USER +soft +memlock +$total_mem"; then
        sed -i "\$i${user} soft memlock ${total_mem}" /etc/security/limits.conf
    fi

    if [ -z "${pci_ids[@]}" ]; then
        echo -e "${cRed}Error${cRst}: no Quadra devices found"
        exit 1
    fi
    for ids in "${pci_ids[@]}"; do
        echo -e "sudo sh -c \"echo 0000:${ids} > /sys/bus/pci/drivers/nvme/unbind\""
        sudo sh -c "echo 0000:${ids} > /sys/bus/pci/drivers/nvme/unbind"
        echo "sudo modprobe vfio-pci"
        sudo modprobe vfio-pci
        echo -e "sudo sh -c \"echo 0000:${ids} > /sys/bus/pci/drivers/vfio-pci/bind\""
        sudo sh -c "echo 0000:${ids} > /sys/bus/pci/drivers/vfio-pci/bind"
        echo -e "sudo sh -c \"echo 1d82 0401 > /sys/bus/pci/drivers/vfio-pci/new_id\""
        sudo sh -c "echo 1d82 0401 > /sys/bus/pci/drivers/vfio-pci/new_id" && rc=0
    done
    echo "VFIO Bind (SUCCESS)"
    return $rc
}

function emulator_run() {
    echo "======== emulator run ========"
    rc=1
    dryrun=$1

    if [ "$ARCH" == '64' ]; then
        generic_num="x86_64"
    else
        generic_num="x86"
    fi
    sudo killall qemu-system-x86_64 && sudo killall adb && adb kill-server
    rm /home/$USER/${WORK_DIR}/out/target/product/generic_$generic_num/hardware-qemu.ini.lock

    device_fmt=""
    for id in "${pci_ids[@]}"; do
        echo "$id"
        out=$(lspci -nnk -s ${id} | grep vfio-pci)
        if [[ -z "${out}" ]]; then
            echo -e "${cRed}Error${cRst}: VFIO is disabled for Quadra device at PCIe address ${id}"
            exit 1
        fi
        device_fmt+=" -device vfio-pci,host=0000:${id}"
    done
    if [ "$dryrun" == "true" ]; then
        echo "bash run_emulator.sh $ARCH $device_fmt >emulator_log.txt 2>&1 &"
        bash run_emulator.sh "$ARCH" "$device_fmt" >emulator_log.txt 2>&1 &
    else
        echo "bash run_emulator.sh $ARCH >emulator_log.txt 2>&1 &"
        bash run_emulator.sh "$ARCH" >emulator_log.txt 2>&1 &
    fi
    for ((i = 0; i < 50; i++)); do
        echo "Loop $i"
        sleep 5
        if grep -q completed emulator_log.txt; then
            echo "$out1"
            echo "Android emulator launch success"
            rc=0
            break
        elif egrep -q "ERROR|Error" emulator_log.txt; then
            echo "$out2"
            echo -e "${cRed}Error${cRst}: Android emulator launch failure. Please check log and retry this step after reboot."
            rc=1
            exit 1
        fi
    done
    if [ $rc -ne 0 ]; then
        echo -e "${cRed}Error${cRst}: Android emulator launch timeout. Please check log and retry this step after reboot."
        exit 1
    fi
    rc=0
    return $rc
}

function adb_push() {
    echo "======== adb push ========"
    rc=1
    cp -r ${sw_folder}/AOSP/Android9/nidec/ /home/$USER/$WORK_DIR/hardware/interfaces/
    cp $base_dir/patch/aosp_change/manifest.xml /home/$USER/$WORK_DIR/
    cp $base_dir/patch/aosp_change/mediacodec.policy /home/$USER/$WORK_DIR/
    cd /home/$USER/$WORK_DIR/ &&
        source build/envsetup.sh &&
        lunch $LUNCH_CMD &&
        echo "mmm hardware/interfaces/nidec/1.0"
    mmm hardware/interfaces/nidec/1.0

    revision=$(grep -n -w -i 'NI_XCODER_REVISION\s' ${base_dir}/${sw_folder}/libxcoder/source/ni_defs.h | awk '{print $3}')
    echo "bash adb_push.sh $revision $ARCH" $base_dir/FFmpeg
    bash $base_dir/adb_push.sh "$revision" "$ARCH" $base_dir/FFmpeg
    if [ $? -ne 0 ]; then
        echo -e "${cRed}Error${cRst}: failed to upload ADB executables"
        exit 1
    fi
    echo "Successfully uploaded ADB executables"
    cd $base_dir && rc=0
    return $rc
}

# Build libxcoder and FFmpeg on Android emulator
function build_all() {
    echo "======== build all android ========"
    
    rc=1
    generate_ffmpeg_dir FFmpeg
    if [ $1 -eq 11 ]; then
        echo "bash build_all_android.sh ${ARCH} ${sw_folder}/libxcoder FFmpeg 11 ${sw_folder}/AOSP/Android11/nidec > build_all_android_log.txt 2>&1" &&
        bash build_all_android.sh ${ARCH} $sw_folder/libxcoder FFmpeg '11' ${sw_folder}/AOSP/Android11/nidec > build_all_android_log.txt 2>&1
        if [ $? -ne 0 ]; then
            echo -e "${cRed}Error${cRst}: failed to build libxcoder and FFmpeg for Android 11"
            exit 1
        fi
    fi
    if [ $1 -eq 9 ]; then
        echo "bash build_all_android.sh ${ARCH} ${sw_folder}/libxcoder FFmpeg > build_all_android_log.txt 2>&1" &&
        bash build_all_android.sh ${ARCH} $sw_folder/libxcoder FFmpeg > build_all_android_log.txt 2>&1
        if [ $? -ne 0 ]; then
            echo -e "${cRed}Error${cRst}: failed to build libxcoder and FFmpeg on Android emulator"
            exit 1
        fi
    fi
    out=$(cat build_all_android_log.txt | grep "Error|failed")
    if [ -z "$out" ]; then
        echo -e "Successfully built libxcoder and FFmpeg for Android $1"
    else
        echo -e "${cRed}Error${cRst}: failed to build libxcoder and FFmpeg for Android $1"
        echo $out
        exit 1
    fi

    if [ $1 -eq 9 ]; then
        emulator_run false
        adb_push
    fi
    rc=0
    return $rc
}

function android_rsrc_init() {
    echo "======== android rsrc init ========"
    rc=1
    emulator_run true
    sleep 10
    echo "bash init_android_rsrc_mon.sh $ARCH >init_rsrc.txt 2>&1"
    bash init_android_rsrc_mon.sh $ARCH >init_rsrc.txt 2>&1
    if [ $? -ne 0 ]; then
        echo -e "${cRed}Error${cRst}: Android init_rsrc failure"
        exit 1
    fi
    cat init_rsrc.txt
    out=$(cat init_rsrc.txt | grep Error)
    if [ -n "$out" ]; then
        echo -e "${cRed}Error${cRst}: Android init_rsrc failure"
        exit 1
    else
        echo -e "$ARCH Android init_rsrc sucessful.\n"
        echo "You can choose the Quit option to exit the installation script"
    fi
    rc=0
    return $rc
}

function extract_fw_sw_tarball() {
    echo "Please put the Netint Quadra FW/SW release tarballs or their extracted"
    echo "release folders in same directory as this script."
    echo -e "The latest FW release package found here is: ${cYlw}${fw_folder}${cRst}"
    echo -e "The latest SW release package found here is: ${cYlw}${sw_folder}${cRst}"

    echo -e -n "${cYlw}Press [Y/y] to confirm the use of these two release packages.${cRst} "
    read -n 1 -r
    echo ""
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        echo "Please ensure release package files and md5sum file you wish to use are latest"
        echo "versions in same directory as this script. Ensure they are unmodified (matches"
        echo "md5sum file). Then try again."
        end_script
    fi

    # Extract release packages
    if [ ! -z $fw_pack ]; then
        sudo rm -rf ${fw_folder}
        tar -zxf $fw_pack
    fi
    if [ ! -z $sw_pack ]; then
        sudo rm -rf ${sw_folder}
        tar -zxf $sw_pack
    fi
}

function install_libxcoder() {
    cd_success=false
    # determine whether old or new nvme module is to be used
    nvme_ver=$(modinfo -F version nvme 2> /dev/null)
    if [ -n $nvme_ver ] && [[ $(printf "${nvme_ver}\n0.10\n" | sort -V | tail -n 1) == "0.10" ]] && [[ "${nvme_ver}" != "0.10" ]]; then
        libxcoder_build_flags="--with-old-nvme-driver"
    else
        libxcoder_build_flags=""
    fi

    rc=1
    sudo rm -rf libxcoder &> /dev/null
    cp -r ${sw_folder}/libxcoder ./ && cd libxcoder && bash build.sh ${libxcoder_build_flags} &&
    cd .. && rc=0 && cd /dev/shm && cd_success=true &&
    sudo rm -f NI_lck_* NI_LCK_* NI_RETRY_LCK_* NI_shm_* NI_SHM_* &> /dev/null
    if $cd_success; then cd -; fi
    timeout -s KILL 5 init_rsrc 2>&1 > /dev/null
    rc=$?
    return $rc
}

# $1 - path to put generated FFmpeg folder
function generate_ffmpeg_dir() {
    rc=1
    echo "Downloading FFmpeg-${ver_num} from github..." &&
    sudo rm -rf $1 &> /dev/null; mkdir $1
    # Determine if target is a tag/branch name or commit SHA1. Download accordingly
    if  [[ `echo ${ver_num} | grep -E "^[0-9a-fA-F]{7,}$"` != "" ]]; then
        git clone https://github.com/FFmpeg/FFmpeg.git $1
        rc=$?; if [ $rc -ne 0 ]; then
            echo "Failed to git clone FFmpeg"
            return $rc
        fi
        cd $1 && git checkout ${ver_num} && cd ..
    else
        git clone -b ${ver_num} --depth=1 https://github.com/FFmpeg/FFmpeg.git $1
        rc=$?; if [ $rc -ne 0 ]; then
            echo "Failed to git clone FFmpeg"
            return $rc
        fi
    fi
    echo "Applying NETINT patch for FFmpeg-${ver_num}..." &&
    cp ${sw_folder}/FFmpeg-${ver_num}_netint_v${sw_release_num}.diff $1 &&
    cd $1 &&
    patch -t -p 1 < FFmpeg-${ver_num}_netint_v${sw_release_num}.diff &&
    cd .. &&
    rc=0
    return $rc
}

# $1 - FFmpeg version to use (eg. 4.3)
function install_ffmpeg_ver() {
    rc=1
    echo "Installation Path: ./FFmpeg/"
    echo "Note: This will install NETINT-Quadra FFmpeg-${ver_num} patch ontop base ${ver_num} FFmpeg"
    echo "      Any customizations must be integrated manually"
    echo ""
    echo "Compile FFmpeg with --enable-static to statically link FFmpeg libraries, or with"
    echo "--enable-shared if intending to interface with libavcodec directly."
    echo -e "${cYlw}Choose an option:${cRst}"
    select opt in "Compile with --enable-static" "Compile with --enable-shared"; do
        case $opt in
        "Compile with --enable-static")
            extra_build_flag=""
            break
            ;;
        "Compile with --enable-shared")
            extra_build_flag=" --shared"
            if ls /usr/local/lib/libav*.so* /usr/local/lib/libswscale.so* \
                /usr/local/lib/libswresample.so* /usr/local/lib/libpostproc.so* &>/dev/null; then
                echo "Old libav*, libswscale, libswresample, libpostproc packages in "
                echo "/usr/local/lib/ will interfere with new FFmpeg installed."

                echo -e "${cYlw}Choose an option:${cRst}"
                select opt in "Remove old FFmpeg libs" "Continue without removal" "Return to main menu"; do
                    case $opt in
                    "Remove old FFmpeg libs")
                        sudo rm /usr/local/lib/libav*.so* /usr/local/lib/libswscale.so* \
                            /usr/local/lib/libswresample.so* /usr/local/lib/libpostproc.so*
                        break
                        ;;
                    "Continue without removal")
                        break
                        ;;
                    "Return to main menu")
                        return $rc
                        ;;
                    *)
                        echo -e "${cRed}\Invalid choice!${cRst}"
                        ;;
                    esac
                done
            fi
            break
            ;;
        *)
            echo -e "${cRed}\Invalid choice!${cRst}"
            ;;
        esac
    done
    
    generate_ffmpeg_dir FFmpeg &&
    cd FFmpeg &&
    echo "Compiling FFmpeg-${ver_num}..." &&
    sudo make clean &> /dev/null || true &&
    bash build_ffmpeg.sh --ffprobe${extra_build_flag} &&
    sudo make install &&
    chmod 755 run_ffmpeg_quadra.sh &&
    cd .. &&
    rc=0
    sudo ldconfig 2> /dev/null
    return $rc
}

function end_script() {
    printf "\n"
    printf "Stopped quadra_android_quick_installer.sh\n"
    trap - EXIT
    exit 0
}

# $1 - rc
# $2 - prefix to print
function print_eval_rc() {
    if [[ $1 == 0 ]]; then
        echo -e "${cGrn}${2} ran succesfully${cRst}"
    else
        echo -e "${cRed}${2} failed${cRst}"
    fi
    return $1
}

# MAIN -------------------------------------------------------------------------
setup_terminal_colors

echo -e "This script performs installation of Android emulator environment with Netint
Quadra SW on Ubuntu host. Before use, please go to the BIOS and enable
virtualization options (eg. vt-x, vt-d).

For further installation help see README file"

if [ "$1" == "-h" ] || [ "$1" == "--help" ]; then
    echo -e "
Install environment sequence:
Step 1:  Select usage of '64 bit' or '32 bit' Android.
Step 2:  Select option to 'Setup Environment variables'.
Step 3:  Select option to 'Install prerequisite Linux packages (Ubuntu)'.
Step 4:  Select option to 'Install nvme-cli'.
Step 5:  Select option to 'Download Android NDK-r21d and SDK-r24.4.1'.
Step 6:  Select option to perform 'Firmware Update (Optional)' if desiring to
         upgrade firmware.
Step 7:  Select option to 'Download and build Android'. Download requires 60GB
         disk space, compile requires another 160GB of disk space.
Step 8:  Select option to 'Setup VFIO'. Host needs to be rebooted after this
         step. Continue steps after reboot.
Step 9: Select option to 'Check VFIO' is setup successfully.
Step 10: Select option to 'Build libxcoder and FFmpeg-n4.3 on Android emulator'.
Step 11: If previous step succeeds, the environment has been successfully
         installed. Select option to 'Quit'."
    exit 0
fi

trap end_script EXIT

base_dir=$(pwd)
pci_ids=($(lspci -d 1d82:0401 | awk '{print $1}'))
fw_pack=""
fw_folder=""
sw_pack=""
sw_folder=""
sw_release_num=""
select_tarball_vs_folder

extract_fw_sw_tarball

# Prompt for 64bit or 32bit Android usage
# define variables tied to android archecture for subsequent operations
first_prompt_loop=1
while [ $first_prompt_loop -eq 1 ]; do
    echo -e "${cYlw}Select usage of 64bit or 32bit Android:${cRst}"
    select opt in "64 bit" "32 bit" "Quit"; do
        case $opt in
        "64 bit")
            ARCH='64'
            WORK_DIR='android_work'
            LUNCH_CMD='aosp_x86_64-eng'
            echo -e "Android environment x86_64 (64 bit) selected"
            first_prompt_loop=0
            break
            ;;
        "32 bit")
            ARCH='32'
            WORK_DIR='android_work32'
            LUNCH_CMD='aosp_x86-eng'
            echo -e "Android environment x86 (32 bit) selected"
            first_prompt_loop=0
            break
            ;;
        "Quit")
            exit
            ;;
        *)
            echo -e "${cRed}\Invalid choice!${cRst}"
            break
            ;;
        esac
    done
done

# Setup options table
options=(
    "Setup Environment variables"
    "Install prerequisite Linux packages (Ubuntu)"
    "Install nvme-cli"
    "Download Android NDK-r21d and SDK-r24.4.1"
    "Firmware Update (Optional)"
    "Download and build Android"
    "Setup VFIO"
    "Check VFIO"
    "Build libxcoder and FFmpeg-n4.3 on Android 9 emulator"
    "Build libxcoder and FFmpeg-n4.3 for Android 11"
    "Quit"
)

while [ true ]; do
    echo -e "${cYlw}Choose an option:${cRst}"
    select opt in "${options[@]}"; do
        case $opt in
        "Setup Environment variables")
            echo -e "${cYlw}You chose $REPLY which is $opt${cRst}"

            sudo grep -qxF 'Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin' /etc/sudoers ||
            sudo `which sed` -i '/^Defaults    secure_path = /s/$/:\/usr\/local\/sbin:\/usr\/local\/bin/' /etc/sudoers &&
            sudo grep -qxF 'Defaults    env_keep += "PKG_CONFIG_PATH"' /etc/sudoers ||
            sudo sh -c "echo 'Defaults    env_keep += \"PKG_CONFIG_PATH\"' >> /etc/sudoers"

            export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig/ &&
            export LD_LIBRARY_PATH=/usr/local/lib/ &&
            sudo grep -qxF '/usr/local/lib' /etc/ld.so.conf ||
            sudo sh -c 'echo "/usr/local/lib" >> /etc/ld.so.conf'
            sudo ldconfig

            print_eval_rc $? "${opt}"
            break
            ;;
        "Install prerequisite Linux packages (Ubuntu)")
            echo -e "${cYlw}You chose $REPLY which is $opt${cRst}"
            install_os_prereqs &&
            install_yasm
            print_eval_rc $? "${opt}"
            break
            ;;
        "Install nvme-cli")
            echo -e "${cYlw}You chose $REPLY which is $opt${cRst}"
            nvme_cli_ver="1.6"
            if [[ $(gcc -dumpversion | grep -Poh "^\d+") -ge 11 ]]; then
                nvme_cli_ver="1.16"
            fi
            wget https://github.com/linux-nvme/nvme-cli/archive/v${nvme_cli_ver}.tar.gz &&
            tar -zxf v${nvme_cli_ver}.tar.gz && cd nvme-cli-*/ && sudo make && sudo make install && cd ..
            print_eval_rc $? "${opt}"
            break
            ;;
        "Download Android NDK-r21d and SDK-r24.4.1")
            echo -e "${cYlw}You chose $REPLY which is $opt${cRst}"
            # download android NDK and SDK
            wget https://dl.google.com/android/repository/android-ndk-r21d-linux-x86_64.zip &&
            wget https://dl.google.com/android/android-sdk_r24.4.1-linux.tgz &&
            # decompress android NDK and SDK
            rm -rf ./android-ndk-r* ./android-sdk-linux_r* 2> /dev/null || true &&
            fname=$(ls ./android-ndk-r*-linux-x86_64.zip | tail -n 1) &&
            dirname=$(basename ${fname%-linux-x86_64.zip}) &&
            unzip $fname -d . &&
            export ANDROID_NDK_ROOT=$(pwd)/$dirname &&
            fname=$(ls ./android-sdk_r*-linux.tgz | tail -n 1) &&
            tar -zxf $fname -C . &&
            export ANDROID_HOME=$(pwd)/android-sdk-linux

            print_eval_rc $? "${opt}"
            break
            ;;
        "Firmware Update (Optional)")
            echo -e "${cYlw}You chose $REPLY which is $opt${cRst}"
            cd_success=false
            cd $fw_folder && cd_success=true &&
            sudo bash quadra_auto_upgrade.sh
            print_eval_rc $? "${opt}"
            if $cd_success; then cd $base_dir; fi
            break
            ;;
        "Download and build Android")
            echo -e "${cYlw}You chose $REPLY which is $opt${cRst}"
            echo -e "Please prepare 220GB of disk space for this operation."
            in_prompt_loop=1
            while [ $in_prompt_loop -eq 1 ]; do
                echo -e "Please select server to download AOSP code (60GB)"
                select location in "Download from Global (google) server" "Download from China (tsinghua) mirror"; do
                    case $location in
                    "Download from Global (google) server")
                        echo -e "${cYlw}You chose $REPLY which is $location${cRst}"
                        location_arg="global"
                        in_prompt_loop=0
                        break
                        ;;
                    "Download from China (tsinghua) mirror")
                        echo -e "${cYlw}You chose $REPLY which is $location${cRst}"
                        location_arg="china"
                        in_prompt_loop=0
                        break
                        ;;
                    *)
                        echo -e "${cRed}\Invalid choice!${cRst}"
                        in_prompt_loop=1
                        break
                        ;;
                    esac
                done
            done
            download_build_aosp $location_arg &&
            download_build_android_kernel $location_arg &&
            verify_android_emulator
            print_eval_rc $? "${opt}"
            break
            ;;
        "Setup VFIO")
            echo -e "${cYlw}You chose $REPLY which is $opt${cRst}"
            install_vfio
            print_eval_rc $? "${opt}"
            break
            ;;
        "Check VFIO")
            echo -e "${cYlw}You chose $REPLY which is $opt${cRst}"
            check_path_vfio &&
            check_insmod_vfio
            print_eval_rc $? "${opt}"
            break
            ;;
        "Build libxcoder and FFmpeg-n4.3 on Android 9 emulator")
            echo -e "${cYlw}You chose $REPLY which is $opt${cRst}"
            ver_num="n4.3"
            vfio_bind &&
            build_all 9 &&
            android_rsrc_init
            print_eval_rc $? "${opt}"
            break
            ;;
        "Build libxcoder and FFmpeg-n4.3 for Android 11")
            echo -e "${cYlw}You chose $REPLY which is $opt${cRst}"
            ver_num="n4.3"
            build_all 11 &&
            print_eval_rc $? "${opt}"
            break
            ;;
        "Quit")
            exit
            ;;
        *)
            echo -e "${cRed}\Invalid choice!${cRst}"
            break
            ;;
        esac
    done

done
