#!/usr/local/bin/cbsd
#v11.1.12
MYARG=""
MYOPTARG="mode"
CBSDMODULE="qemu"
MYDESC="Ncurses based QEMU guest creation wizard"
EXTHELP="wf_qcreate"
ADDHELP="
${H3_COLOR}Description${N0_COLOR}:

The CBSD supports a large number of options for creating environments
and the TUI (text-user interface) dialog variant is probably the easiest.
This is an interactive dialog that generates a configuration file for the
'cbsd qcreate' command. You can see this configuration file if you answer
negatively to the 'Do you want to create jail immediately?' question at
the end of the dialogue.

${H3_COLOR}Options${N0_COLOR}:

${N2_COLOR}mode=${N0_COLOR} - set 'full' to unhide all atributes.

${H3_COLOR}Examples${N0_COLOR}:

 # cbsd qconstruct-tui

${H3_COLOR}See also${N0_COLOR}:

  cbsd qcreate --help
  cbsd qconstruct --help
  cbsd up --help

"

# TODO: bios='ovmf' for UEFI
. ${subrdir}/nc.subr
. ${cbsdinit}

. ${subrdir}/qemu.subr
# preliminary reading of some pre-defined constants for tui messages
readconf qemu-default-default.conf

. ${subrdir}/settings-tui.subr
. ${subrdir}/settings-tui-virtual.subr
. ${subrdir}/settings-tui-qemu.subr
. ${dialog}

extra_default_item=

gen_newjail_conf()
{
	local _i _required _mytest _ret

	_required="jname host_hostname ip4_addr ver arch imgsize"

	if [ ${is_cloud} -eq 1 ]; then
		_required="${_required} cloud_init_options"
	fi

	msg_ok="ok"

	for _i in ${_required}; do
		eval _mytest=\$$_i
		if [ -z "${_mytest}" ]; then
			f_dialog_msgbox "${_i} must be filled" "Error"
			extra_default_item="${_i}"
			return 0
		fi
	done

	unset extra_default_item

	# adjust default sectorize
	if [ -z "${sectorsize}" ]; then
		sectorsize="${default_sectorsize}"
		[ -z "${sectorsize}" ] && sectorsize="4096"
	fi

	#check for ip if oninterface
	if [ "${interface}" != "0" -a -n "${ip4_addr}" ]; then
		checkip ip=${ip4_addr} check=1 2>/dev/null
		case $? in
			2)
				msg_yes="ok"
				msg_no="not ok"
				f_dialog_noyes "It seems like ${ip4_addr} address already used on several devices on the LAN\nYou can found MAC address by \"arp -an\" command.\n If you believe that it's ok, choose 'ok' to continue or 'not ok' for another IP address" "WARNING"
				case $? in
					0)
						;;
					*)
						return 0
						;;
				esac
		esac
	fi

	if [ "${spice_enabled}" = "1" ]; then
		spice_default=1
	else
		spice_default=0
	fi

	gen_jconf
	ERR=$?

	[ ${ERR} -eq 0 ] || err 1 "${N1_COLOR}bad conf${N0_COLOR}"
	err 0 ${A}
}

dialog_menu_main()
{
	local title=" ${product} v${myversion} "
	local btitle="${DIALOG_BACKTITLE}"
	local prompt="Use menu to construct VM and create config file"

	local defaultitem= # Calculated below

	local hline=
	local mark
	local i _mytest

	f_dialog_default_fetch defaultitem

	# checkbox mark
	for i in astart xhci tablet usb; do
		eval _mytest=\$$i
		if [ "${_mytest}" = "1" ]; then
			export ${i}_mark="X"
		else
			export ${i}_mark=" "
		fi
	done

	item_let="A"
	item_num="0"
	local menu_list=""

	menu_list="${menu_list}	'${item_let} arch'		'$(curval arch)'		'target arch'"
	inc_menu_index item_num

	menu_list="${menu_list}	'${item_let} vm_os_type'	'$(curval vm_os_type)'		'Guest OS type'"
	inc_menu_index item_let
	menu_list="${menu_list}	'${item_let} vm_os_profile'	'$(curval vm_os_profile)'	'Guest OS profile'"
	inc_menu_index item_let

	if [ "${from_jail}" = "1" -a "${qemu_profile}" != "FreeBSD-bsdinstall-jail" ]; then
		menu_list="${menu_list}	'${item_let} jprofile'	'$(curval jprofile)'		'Select jail profile for jcreate'"
	fi

	local vm_package_num=$( cbsdsqlro local SELECT COUNT\(name\) FROM vmpackages )

	if ! is_number ${vm_package_num}; then
		if [ ${vm_package_num} -gt 0 ]; then
			menu_list="${menu_list}	'${item_let} vm_package'	'$(curval vm_package)'		'Package group name'"
			inc_menu_index item_let
		fi
	fi

	menu_list="${menu_list}	'${item_let} jname'		'$(curval jname)'		'A short jail name'"
	inc_menu_index item_let
	menu_list="${menu_list}	'${item_let} host_hostname'	'$(curval host_hostname)'	'Full (FQDN) jail hostname'"
	inc_menu_index item_let
	menu_list="${menu_list}	'${item_let} imgsize'		'$(curval imgsize)'		'reserved (expand) X size for free space'"
	inc_menu_index item_let

	if [ ${is_cloud} -eq 0 ]; then
		# moved to cloud-init helper for cloud host
		menu_list="${menu_list}	'${item_let} ip4_addr'	'$(curval ip4_addr)'	'${ip4_addr_msg}'"
		inc_menu_index item_let
	fi

	menu_list="${menu_list}	'${item_let} vm_ram'		'$(curval vm_ram)'		'RAM'"
	inc_menu_index item_let
	menu_list="${menu_list}	'${item_let} vm_cpus'		'$(curval vm_cpus)'		'CPUs number'"
	inc_menu_index item_let

	if [ ${is_cloud} -eq 0 ]; then
		# not for cloud
		menu_list="${menu_list}	'${item_let} vm_iso_path'	'$(curval vm_iso_path)'	'ISO Path for CD-ROM'"
		inc_menu_index item_let
	fi

	menu_list="${menu_list}	'${item_let} astart'		'[${astart_mark}]'		'Autostart with system'"
	inc_menu_index item_let

	menu_list="${menu_list}	'${item_let} interface'		'$(curval interface)'		'Interface selection and aliasing mode'"

	# todo
	inc_menu_index item_let
	menu_list="${menu_list} '${item_let} vm_vnc_port'	'$(curval vm_vnc_port)'		'VNC port'"

	if [ ${is_cloud} -eq 1 ]; then
		menu_list="${menu_list} '${item_let} cloud_init_options'        '$(curval cloud_init_options)'  'cloud-init settings'"
		inc_menu_index item_let
	fi

#	menu_list="${menu_list} '${item_let} debug_engine'		'$(curval debug_engine)'	'Run in debugger?'"
#	inc_menu_index item_let

	if [ "${zfsfeat}" = "1" ]; then
		menu_list="${menu_list} '-'			'-'				''"
		inc_menu_index item_num
		menu_list="${menu_list} '${item_num} imgtype'		'$(curval imgtype)'	'ZVOL or MD disk type'"
		inc_menu_index item_num
		menu_list="${menu_list} '${item_num} zfs_snapsrc'	'$(curval zfs_snapsrc)'	'Create qemu from ZFS snapshot'"
	fi

	inc_menu_index item_num
	menu_list="${menu_list} '${item_num} qemu_vnc_options'	'VNC options >>'		'VNC opt: bind:${qemu_vnc_tcp_bind} vnc_password:XXX'"
	inc_menu_index item_num


#	hide for a while
#	menu_list="${menu_list} '${item_num} qemu_spice_options'	'SPICE options >>'		'SPICE opt: bind:${qemu_spice_tcp_bind} spice_password:XXX'"
#	inc_menu_index item_num
#	menu_list="${menu_list} '${item_num} qemu_audio_options'	'Audio options >>'		'Audio opt: ${soundhw}'"
#	inc_menu_index item_num

	menu_list="${menu_list} '${item_num} qemu_options'	'Qemu options >>'	'Customize qemu options: qemu_hap:${qemu_hap} qemu_nestedhvm:${qemu_nestedhvm}'"
	inc_menu_index item_num

	menu_list="${menu_list} '${item_num} exit_behavior'	'Exit behavior settings'	'Exit behavior settings: poweroff:${on_poweroff},reboot:${on_reboot},crash:${on_crash}'"
	inc_menu_index item_num

	if [ "${from_jail}" = "1" -a "${qemu_profile}" != "FreeBSD-bsdinstall-jail" ]; then
		menu_list="${menu_list}	'-'				'JAIL SUB:'		'fromjail submenu'"
		[ -z "${swapsize}" ] && swapsize="4g"
		inc_menu_index item_let
		menu_list="${menu_list}	'${item_let} vm_guestfs'	'$(curval vm_guestfs)'	'Choose filesystem for boot image'"
		inc_menu_index item_let
		menu_list="${menu_list}	'${item_let} swapsize'		'$(curval swapsize)'	'Allocate and Configure for swap partition'"
		inc_menu_index item_let
		menu_list="${menu_list}	'${item_let} pkglist'		'$(curval pkgnum)'	'mark pkg for install from repo'"
		inc_menu_index item_let
		menu_list="${menu_list}	'${item_let} gw4'		'$(curval gw4)'		'Default router for qemu or vimage'"
		inc_menu_index item_let
		menu_list="${menu_list}	'${item_let} ver'		'$(curval ver)'		'choose code base version'"
		inc_menu_index item_let
		menu_list="${menu_list}	'${item_let} applytpl'		'$(curval applytpl)'	'Apply cbsd templates'"
		inc_menu_index item_let
		menu_list="${menu_list}	'${item_let} floatresolv'	'$(curval floatresolv)'	'Auto correct for jail resolv.conf'"
		inc_menu_index item_let
		menu_list="${menu_list}	'${item_let} arch'		'$(curval arch)'	'target arch'"
		inc_menu_index item_num
		menu_list="${menu_list}	'${item_num} user_pw_root'	'Root Password'		'Change jail root password'"
		inc_menu_index item_num
		menu_list="${menu_list}	'${item_num} add_user'		'$(curval user_add)'	'Create additional account within VM'"
		inc_menu_index item_num
		menu_list="${menu_list}	'${item_num} services'		'Services >>'		'Toggle Startup Services'"
		inc_menu_index item_num
		menu_list="${menu_list}	'${item_num} pkglist'		'$(curval pkgnum)'	'mark pkg for install from repo'"
	fi

	menu_list="${menu_list}	'-'			'-'					'fromjail submenu'"
	inc_menu_index item_num
	menu_list="${menu_list}	'${item_num} GO'	'PROCEED!'				'PROCEED!'"

	if [ -n "${extra_default_item}" ]; then
		# scan for extra default item in menu list
		OIFS="${IFS}"
		IFS="'"
		for i in ${menu_list}; do
			IFS="${OIFS}"
			case "${i}" in
				[0-9]*${extra_default_item}|[aA-zZ]*${extra_default_item})
					defaultitem="${i}"
					break
					;;
			esac
		done
		IFS="${OIFS}"
	fi
	cbsd_menubox_with_help
	retval=$?

	f_dialog_data_sanitize menu_choice
	f_dialog_menutag_store "$menu_choice"
	f_dialog_default_store "$menu_choice"

	return $retval
}

#### [ MAIN AREA ] ####
Makefile="${CBSD_PWD}/CBSDfile"
if [ -r "${Makefile}" ]; then
	${ECHO} "${N1_COLOR}found CBSDfile: ${N2_COLOR}${Makefile}${N0_COLOR}"
	err 1 "${N1_COLOR}${CBSD_APP} doesn't not support for CBSDfile, please change current directory${N0_COLOR}"
fi
[ ! -f ${localcbsdconf} ] && err 1 "${N1_COLOR}no such conf file${N0_COLOR}"
. ${localcbsdconf}
. ${inventory}

zero_profile="qemu-default-default.conf"
default_profile="qemu-default-default.conf"

#defaults
. ${subrdir}/build.subr

# read for skip_qemu_init_warning
readconf ${default_profile}
init_qemu
readconf vnc.conf
readconf spice.conf

# re-read profile for init global_profile_file variable
get_construct_profile ${default_profile}
[ -z "${profile}" -a -n "${jail_profile}" ] && profile="${jail_profile}"

[ -z "${qemu_vnc_resolution}" ] && qemu_vnc_resolution="${default_vnc_width}x${default_vnc_height}"
[ -z "${qemu_vnc_tcp_bind}" ] && qemu_vnc_tcp_bind="${default_vnc_tcp_bind}"
[ -z "${qemu_vnc_vgaconf}" ] && qemu_vnc_vgaconf="${default_vnc_vgaconf}"
[ -z "${vnc_password}" ] && vnc_password="${default_vnc_password}"
[ -z "${qemu_spice_resolution}" ] && qemu_spice_resolution="${default_spice_width}x${default_spice_height}"
[ -z "${qemu_spice_tcp_bind}" ] && qemu_spice_tcp_bind="${default_spice_tcp_bind}"

# IPv6 only host?
case "${node_ip6_active}" in
	1)
		if [ "${node_ip4_active}" = "0" ]; then
			default_spice_tcp_bind="[::1]"
		fi
		;;
esac

[ -z "${spice_password}" ] && spice_password="${default_spice_password}"
[ -z "${imgtype}" ] && imgtype="zvol"
[ -z "${uuid}" ] && uuid="0"

baserw=1
ip4_addr="DHCP"
jprofile="default"
cloud_init_options=

f_dialog_title "$msg_system_console_configuration"
f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
f_mustberoot_init

# init first qconstruct settings
if [ ! -r ${tmpdir}/qconstruct.conf ]; then
	last_cache_crc="0"
	${CAT_CMD} > ${tmpdir}/qconstruct.conf <<EOF
last_vm_os_type="freebsd"
last_vm_os_profile="FreeBSD-x64-14.3"
last_vm_os_arch="amd64"
last_cache_crc="0"
EOF
else
	. ${tmpdir}/qconstruct.conf
fi

# todo: src=qemu
cache_crc=$( get-profiles src=iso cache_sum=1 )
if [ "${cache_crc}" != "${last_cache_crc}" ]; then
	${RM_CMD} -f "${tmpdir}"/qconstruct.conf
	/usr/local/cbsd/misc/cbsdsysrc -qf "${tmpdir}"/qconstruct.conf last_cache_crc="${cache_crc}"
fi

if [ "${default_profile}" = "default" -a -r ${tmpdir}/qconstruct.conf ]; then
	[ -r ${tmpdir}/get_construct_vm_os_profile.menu ] && ${RM_CMD} -f ${tmpdir}/get_construct_vm_os_profile.menu
	if [ -n "${last_vm_os_type}" ]; then
		vm_os_type="${last_vm_os_type}"
		get_construct_vm_os_type ${vm_os_type}
	fi
	if [ -n "${last_vm_os_profile}" ]; then
		vm_os_profile="${last_vm_os_profile}"
		get_construct_vm_os_profile ${vm_os_profile}
	fi
	if [ -n "${last_vm_os_arch}" ]; then
		arch="${last_vm_os_arch}"
		get_construct_arch ${arch}
	fi
else
	vm_iso_path="${register_iso_as}"
	apply_vm_package
fi

while [ 1 ]; do
	pkgnum=0
	[ -n "${pkglist}" -a "${pkglist}" != "NO" ] && pkgnum=$( ${WC_CMD} -w ${pkglist} | ${AWK_CMD} '{printf $1}' )

	dialog_menu_main
	retval=$?

	if [ $retval -eq $DIALOG_HELP ]; then
		get_help
		continue
	elif [ $retval -ne $DIALOG_OK ]; then
		f_die
	fi

	index=${mtag%% *}
	mychoice=${mtag##* }

	case "${mychoice}" in
		"EXIT")
			exit 0
			;;
		"GO")
			# store last choices
			/usr/local/cbsd/misc/cbsdsysrc -qf ${tmpdir}/qconstruct.conf last_vm_os_type="${vm_os_type}" \
				last_vm_os_profile="${vm_os_profile}" \
				last_vm_os_arch="${arch}" > /dev/null 2>&1
			gen_newjail_conf
			;;
		"-")
			continue
			;;
		interface)
			get_construct_interface -d 1 -s "tap vboxnet lo xnb wlan" -b 1 -v 1 -n 1
			;;
		astart|usb|tablet|xhci)
			invert_checkbox ${mychoice}
			continue
			;;
		*)
			get_construct_${mychoice}
			;;
	esac
done

exit 0
