#!/usr/bin/env bash
#shellcheck disable=SC2034,SC2155,SC2154,SC2181
#
#	Requeriments:
# - qemu
# - edk2-ovmf (when UEFI booting)
#
#  big-runimage
#  Created: 2023/04/25
#  Altered: 2023/12/04
#
#  Copyright (c) 2023-2023, Vilmar Catafesta <vcatafesta@gmail.com>
#  All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions
#  are met:
#  1. Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
#  2. Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#
#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
#  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
#  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
#  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
#  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
#  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
#  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
#  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
#  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
#  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

export TEXTDOMAINDIR=/usr/share/locale
export TEXTDOMAIN=chili-runimage

#debug
export PS4='${red}${0##*/}${green}[$FUNCNAME]${pink}[$LINENO]${reset} '
#set -x
#set -e

#system
readonly APP="${0##*/}"
readonly _VERSION_='1.3.00-20231204'
readonly DEPENDENCIES=('tput' 'printf' 'qemu-system-x86_64' 'gettext')
readonly PACKAGEDEP=([tput]='ncurses' [printf]='coreutils' [qemu - system - x86_64X]='qemu' [gettext]='gettext')
readonly iface_bridge='br0'
declare xmem='16G'
declare -i uefi=0
declare -i bridge=0
declare -a qemu_options=()
trap cleanup_working_dir EXIT

function cleanup_working_dir {
	if [[ -d "${working_dir}" ]]; then
		rm -rf -- "${working_dir}"
	fi
}

function DOT {
	printf "%s" "${blue}:: ${reset}"
}

function die {
	local msg=$1
	shift
	printf "  %b %s\\n" "${CROSS}" "${bold}${red}${msg}"
	exit 1
}

function log_msg() {
	local retval="${PIPESTATUS[0]}"

	if [[ $retval -eq 0 ]]; then
		printf "  %b %s\\n" "${TICK}" "${*}"
	else
		printf "  %b %s\\n" "${CROSS}" "${*}"
	fi
}

function sh_checkRoot {
	local str="$(gettext "Verificação de usuário root")"
	if [[ "$(id -u)" != "0" ]]; then
		die "${red}$(gettext "erro: você não pode executar esta operação a menos que seja root")"
	fi
	printf "  %b %s\\n" "${TICK}" "${str}"
	return 0
}

sh_version() {
	printf "%s\n" "${black}${0##*/} v${_VERSION_}${reset}"
	printf "\t%s\n\t%s\n\t%s\n\t%s\n" "${bold}${black}Copyright (C) 2023 vcatafesta@gmail.com" \
		"$(gettext "Licença GPLv3+: GNU GPL versão 3 ou posterior") <https://gnu.org/licenses/gpl.html>" \
		"$(gettext "Este é um software livre: você é livre para alterá-lo e redistribuí-lo.")" \
		"$(gettext "NÃO HÁ GARANTIA, em toda a extensão permitida por lei.")$reset"
	exit 0
}

function sh_setenvironment {
	declare -gA Alocale=([0]=pt_BR [1]=en_US [2]=de_DE [3]=fr_FR [4]=es_ES [5]=it_IT)
	tput sgr0 # reset colors
	bold=$(tput bold)
	reset=$(tput sgr0)
	white="${bold}$(tput setaf 7)"
	black="${bold}$(tput setaf 0)"
	red=$(tput bold)$(tput setaf 196)
	green=$(tput setaf 2)
	yellow=$(tput bold)$(tput setaf 3)
	blue=$(tput setaf 4)
	pink=$(tput setaf 5)
	cyan=$(tput setaf 6)
	orange=$(tput setaf 3)
	purple=$(tput setaf 125)
	violet=$(tput setaf 61)
	COL_NC='\e[0m' # No Color
	COL_LIGHT_GREEN='\e[1;32m'
	COL_LIGHT_RED='\e[1;31m'
	TICK="${white}[${COL_LIGHT_GREEN}✓${COL_NC}${white}]"
	CROSS="${white}[${COL_LIGHT_RED}✗${COL_NC}${white}]"
	INFO="[i]"
	# shellcheck disable=SC2034
	DONE="${COL_LIGHT_GREEN} done!${COL_NC}"
	OVER="\\r\\033[K"
	DOTPREFIX="  ${black}::${reset} "
}

function sh_unsetvarcolors {
	unset bold reset cyan red blue white black
	unset green yellow orange pink cyan purple violet
}

function sh_checkDependencies {
	local d
	local errorFound=0
	declare -a missing

	for d in "${DEPENDENCIES[@]}"; do
		[[ -n $(command -v "$d") ]] && { :; } || {
			printf "%s\n" "${red}ERROR${reset}: $(gettext "Não foi possível encontrar o comando") ${cyan}'$d'${reset} -> $(gettext "instalar pacote") '${PACKAGEDEP[$d]}'"
			missing+=("$d")
			errorFound=1
		}
	done

	if ((errorFound)); then
		echo "===================================================="
		echo "${yellow}             $(gettext "IMPOSSÍVEL CONTINUAR")"
		echo "${black}$(gettext "Este script precisa dos comandos listados acima")"
		echo "${black}$(gettext "Instale-os e/ou verifique se eles estão em seu") ${red}\$PATH${reset}"
		echo "===================================================="
		die $(gettext "Abortando...")
	fi
}

function filerun_bios {
	if test $# -ge 1; then
		if test -r $1; then
#			qemu-system-x86_64 -drive file=${1},format=raw,if=none,id=disk1 -device ide-hd,drive=disk1,bootindex=1 -device virtio-scsi-pci,id=scsi0 "${qemu_options[@]}"
			qemu-system-x86_64 -drive file=${1},if=none,id=disk1 -device ide-hd,drive=disk1,bootindex=1 -device virtio-scsi-pci,id=scsi0 "${qemu_options[@]}"
		else
			log_msg "${red}ERROR: ${cyan}'$1' ${red}$(gettext "erro de leitura ou não existe")"
		fi
	else
		sh_usage
	fi
}

function filerun_uefi {
	if test $# -ge 1; then
		if test -r $1; then
			local ovmf_code='/usr/share/edk2-ovmf/x64/OVMF_CODE.fd'
			local working_dir="$(mktemp -dt chili-runimage-$USER.XXX)"

			if [[ ! -f '/usr/share/edk2-ovmf/x64/OVMF_VARS.fd' ]]; then
				printf 'ERROR: %s\n' "OVMF_VARS.fd $(gettext "não encontrado. Instale o pacote") edk2-ovmf."
				exit 1
			fi
			cp -av -- '/usr/share/edk2-ovmf/x64/OVMF_VARS.fd' "${working_dir}/"

			if [[ ${1: -4} == ".iso" ]]; then
				# ISO disk
				qemu-system-x86_64 \
				    -cdrom $1 \
					-boot d \
					-drive if=pflash,format=raw,unit=0,file=${ovmf_code},read-only=on \
					-drive if=pflash,format=raw,unit=1,file=${working_dir}/OVMF_VARS.fd \
					"${qemu_options[@]}"
			else
				# RAW disk
				qemu-system-x86_64 \
				    -drive file=${1},format=raw,if=virtio \
				    -drive if=pflash,format=raw,unit=0,file=${ovmf_code},read-only=on \
				    -drive if=pflash,format=raw,unit=1,file=${working_dir}/OVMF_VARS.fd \
				    "${qemu_options[@]}"
			fi
		else
			log_msg "${red}ERROR: ${cyan}'$1' ${red}$(gettext "erro de leitura ou não existe")"
			sh_usage
		fi
	else
		sh_usage
	fi
}

function sh_set_qemu_common_options {
#	qemu_options+=(-drive file=/dev/sdq,format=raw)
#	qemu_options+=(-drive file=/dev/nvme1n1,format=raw)
	qemu_options+=(-no-fd-bootchk)
	qemu_options+=(-machine accel=kvm)
	qemu_options+=(-cpu host)
	qemu_options+=(-smp "$(nproc)")
    #	qemu_options+=(-m ${xmem})
    #   qemu_options+=(-name "$HOSTNAME")
	qemu_options+=(-name 'chili-runimage')
    #   qemu_options+=(-drive file=${1},if=none,id=disk1)
    #   qemu_options+=(-device ide-hd,drive=disk1,bootindex=1)
    #   qemu_options+=(-name archiso,process=archiso_0)
    #   qemu_options+=(-device virtio-scsi-pci,id=scsi0)
    #   qemu_options+=(-netdev user,id=net0)
    #   qemu_options+=(-device e1000,netdev=net0)
	#	qemu_options+=(-vga std)				# ✓ VGA compatible ✓ vgabios support ✓ UEFI support (QemuVideoDxe) ✓ linux driver (bochs-drm.ko)
	#	qemu_options+=(-device VGA)
	#	qemu_options+=(-device ramfb)			# ✗ not VGA compatible ✓ vgabios support ✓ UEFI support (QemuRamfbDxe)
	#	qemu_options+=(-device cirrus-vga)		# ✓ VGA compatible ✓ vgabios support ✓ UEFI support (QemuVideoDxe) ✓ linux driver (cirrus.ko)
	#	qemu_options+=(-device qxl)
    #	qemu_options+=(-device qxl-vga)
	qemu_options+=(-vga virtio) # ✓ VGA compatible ✓ vgabios support ✓ UEFI support (QemuVideoDxe) ✓ linux driver (virtio-gpu.ko)
	#	qemu_options+=(-device bochs-display)	# ✗ not VGA compatible	✓ vgabios support ✓ UEFI support (QemuVideoDxe) ✓ linux driver (bochs-drm.ko)
    #	qemu_options+=(-vga std)				# ✓ VGA compatible ✓ vgabios support ✓ UEFI support (QemuVideoDxe) ✓ linux driver (bochs-drm.ko)
	#	qemu_options+=(-device qxl-vga)
	#	qemu_options+=(-device ati-vga)
	#	qemu_options+=(-vga qxl) 				# ✓ VGA compatible ✓ vgabios support ✓ UEFI support (QemuVideoDxe) ✓ linux driver (qxl.ko) ✓ windows driver
	qemu_options+=(-display gtk)
	qemu_options+=(-device intel-hda)
	qemu_options+=(-audiodev pa,id=snd0,server=localhost)
	qemu_options+=(-device ich9-intel-hda)
	qemu_options+=(-device hda-output,audiodev=snd0)
	qemu_options+=(-global ICH9-LPC.disable_s3=1)
	qemu_options+=(-machine type=q35,smm=on,accel=kvm,usb=on,pcspk-audiodev=snd0)
	qemu_options+=(-serial stdio)
}

#				  	-netdev user,id=net0 \
#				  	-device virtio-net-pci,netdev=net0 \
#				  	-net nic,model=virtio \
#				  	-net user \

function sh_usage {
	cat <<EOF
$(gettext "Uso"):
	${orange}$APP${reset} [$(gettext "Opções") [-b] [-n] [-u]]

$(gettext "Opções"):
	-h|--help              $(gettext "imprima esta ajuda")
	-u|--uefi              $(gettext "defina o tipo de inicialização para") 'UEFI'
	-b|--bridge            $(gettext "configurar net como ponte")
	-n|--nocolor           $(gettext "remover cores da saída")
	-V|--version           $(gettext "imprimir versão do aplicativo")
	-m|--memory            $(gettext "quantidade inicial de memória de convidado")

$(gettext "Exemplo"):
	# ${orange}$APP${reset} -b -u file.iso         #$(gettext "Execute uma imagem, em ponte, usando") UEFI
	# ${orange}$APP${reset} -u file.img            #$(gettext "Execute uma imagem, em NAT, usando") UEFI
	# ${orange}$APP${reset} -b -u /dev/sdX         #$(gettext "Execute uma device, em ponte, usando") UEFI
	# ${orange}$APP${reset} -m 16G -b -u /dev/sdX  #$(gettext "Execute uma device, em ponte, 16Gb memória, usando") UEFI

	# ${orange}$APP${reset} file.iso               #$(gettext "Execute uma imagem usando") BIOS
	# ${orange}$APP${reset} -b file.img            #$(gettext "Execute uma imagem, em ponte, usando") BIOS
	# ${orange}$APP${reset} -m 16G /dev/sdX        #$(gettext "Execute uma device, 16GB memória, usando") BIOS
EOF
	exit 0
}

sh_setenvironment
sh_checkDependencies
sh_set_qemu_common_options

OPTIONS=m:ubVnh
LONGOPTIONS=memory:,uefi,bridge,version,nocolor,help
#if ! opts=($(getopt --options="$OPTIONS" --longoptions="$LONGOPTIONS" --name "$0" -- "$@")); then
#	sh_usage
#fi
#eval set -- "${opts[*]}"

opts=($(getopt --options="$OPTIONS" --longoptions="$LONGOPTIONS" --name "$0" -- "$@"))
eval set -- "${opts[*]}"

while test ${#opts[*]} -gt 0; do
	case $1 in
	-u | --uefi)
		uefi=1
		;;
	-b | --bridge)
		bridge=1
		;;
	-n | --nocolor)
		sh_unsetvarcolors
		;;
	-m | --memory)
		if [[ $2 =~ ^[0-9]+[MG]?$ ]]; then
			xmem=$2
			shift
		else
			die "$(gettext "Argumento inválido para -m. Use um formato como 16GB (por exemplo).")" >&2
		fi
		;;
	-V | --version) sh_version ;;
	-h | --help) sh_usage ;;
	--)
		shift
		break
		;;
	:)
		die "-$OPTARG $(gettext "requer um argumento")" >&2
		;;
	*)
		die "$(gettext "operação não suportada"): $1 ($(gettext "usar -h para ajuda"))"
		;;
	esac
	shift
done

if [[ $# > 0 ]] ; then
#	sh_checkRoot
	qemu_options+=(-m ${xmem})
	if ((bridge)); then
		random_mac_net0=$(python3 -c "import random; print(':'.join(['{:02x}'.format(random.randint(0, 255)) for _ in range(6)]))")
		random_mac_net1=$(python3 -c "import random; print(':'.join(['{:02x}'.format(random.randint(0, 255)) for _ in range(6)]))")
		#	echo $random_mac_net0
		#	echo $random_mac_net1
        qemu_options+=(-netdev bridge,id=net0)
		qemu_options+=(-device e1000,netdev=net0)
#		qemu_options+=(-netdev bridge,id=net0,br=$iface_bridge)
#		qemu_options+=(-device e1000,netdev=net0,mac=$random_mac_net0)
#		qemu_options+=(-netdev bridge,id=net1,br=$iface_bridge)
#		qemu_options+=(-device e1000,netdev=net1,mac=$random_mac_net1)
	else
		qemu_options+=(-netdev user,id=net0)
		qemu_options+=(-device e1000,netdev=net0)
	fi
	if ((uefi)); then
		filerun_uefi "$@"
	else
		filerun_bios "$@"
	fi
else
	die "${opts[*]} $(gettext "falta parâmetro de imagem/disco/device"): ($(gettext "usar -h para ajuda"))"
fi
