#!/bin/bash

set -e

get_BDF()
{
    LSPCI_OUT=$1

    # Check if domain is present (format: DDDD:BB:SS.F or BB:SS.F)
    # Count colons to determine format
    COLON_COUNT=$(echo "${LSPCI_OUT}" | tr -cd ':' | wc -c)

    if [ "$COLON_COUNT" -eq 2 ]; then
        # Format with domain: DDDD:BB:SS.F
        DOMAIN=$(echo "${LSPCI_OUT}" | cut -d':' -f1)
        BUS=$(echo "${LSPCI_OUT}" | cut -d':' -f2)
        DEV=$(echo "${LSPCI_OUT}" | cut -d':' -f3 | cut -d'.' -f1)
        FUN=$(echo "${LSPCI_OUT}" | cut -d'.' -f2)
    else
        # Format without domain: BB:SS.F
        DOMAIN="0000"
        BUS=$(echo "${LSPCI_OUT}" | cut -d':' -f1)
        DEV=$(echo "${LSPCI_OUT}" | cut -d':' -f2 | cut -d'.' -f1)
        FUN=$(echo "${LSPCI_OUT}" | cut -d'.' -f2)
    fi

    # Convert BDF to decimal because xorg uses decimal
    DOMAIN=$((0x$DOMAIN))
    BUS=$((0x$BUS))
    DEV=$((0x$DEV))
    FUN=$((0x$FUN))

    # nvidia-xconfig format: PCI:bus@domain:device:function
    BDF="$BUS@$DOMAIN:$DEV:$FUN"

    echo $BDF
}

err_and_exit_zero()
{
	echo $@ && exit 1
}

edit_xconf()
{
	BDF=$1
	DRIVER=$2
	VENDOR_NAME=$3
	XORG_FILE=$4
	XORG_FILE_FULL="/etc/X11/xorg.conf.d/${XORG_FILE}"

	#edit xorg.conf.
	# <DO NOT try to format below lines.>
	sed -i "/Driver         \"nvidia\"/c\    Driver         \"${DRIVER}\"" \
		${XORG_FILE_FULL} || err_and_exit_zero "sed failed"

	# If file contains BusID, replace it
	if grep -q 'BusID          \"PCI:.*\"' ${XORG_FILE_FULL}; then
		sed -i "/BusID          \"PCI:.*\"/c \    BusID          \"PCI:${BDF}\"" \
			${XORG_FILE_FULL} || err_and_exit_zero "sed failed"
	else
		# Otherwise, append BusID
		sed -i "/Driver         \"${DRIVER}\"/a \    BusID          \"PCI:${BDF}\"" \
			${XORG_FILE_FULL} || err_and_exit_zero "sed failed"
	fi

	sed -i "/VendorName     \"NVIDIA Corporation\"/c\    VendorName     \"${VENDOR_NAME}\"" \
		${XORG_FILE_FULL} || err_and_exit_zero "sed failed"

	sed -i '/Section "ServerLayout"/i \
Section "ServerFlags" \
    Option         "AutoAddGPU" "off" \
EndSection\
' ${XORG_FILE_FULL} || err_and_exit_zero "sed failed"
#xorg.conf <DONE>

}


configure_aspeed()
{
	. /etc/os-release

	ASPEED_VGA=$1
	ASPEED_BDF=$(get_BDF "$ASPEED_VGA")
	DRIVER="ast"
	mv /etc/X11/xorg.conf /etc/X11/xorg.conf.d/xorg-aspeed.conf || err_and_exit_zero "mv failed"

	# For RHEL-like OSes, use modesetting
	if is_rhel_like_os; then
		DRIVER="modesetting"
	fi

	VENDOR_NAME="ASPEED Technology, Inc."
	XORG_FILE="xorg-aspeed.conf"

	edit_xconf "$ASPEED_BDF" "$DRIVER" "$VENDOR_NAME" "$XORG_FILE"
}

configure_nvidia()
{
	NVIDIA_VGA=$1
	NVIDIA_BDF=$(get_BDF "$NVIDIA_VGA")
	mv /etc/X11/xorg.conf /etc/X11/xorg.conf.d/xorg-nvidia.conf || err_and_exit_zero "mv failed"
	DRIVER="nvidia"
	VENDOR_NAME="NVIDIA Corporation"
	XORG_FILE="xorg-nvidia.conf"

	edit_xconf "$NVIDIA_BDF" "$DRIVER" "$VENDOR_NAME" "$XORG_FILE"
}


# Use common APIs to figure out platform
plat_funcs="/usr/local/sbin/nv_scripts/plat_funcs.bash"
. ${plat_funcs}
general_funcs="/usr/local/sbin/nv_scripts/general_funcs.bash"
. ${general_funcs}

if plat_needs_initial_nvidia_xconfig; then
    if [[ ! -f /etc/X11/xorg.conf ]]; then
        /usr/bin/nvidia-xconfig --allow-empty-initial-configuration \
        || err_and_exit_zero "nvidia-xconfig failed"
    fi
fi

if plat_needs_adaptive_nvidia_xconfig; then
	mkdir -p /etc/X11/xorg.conf.d || err_and_exit_zero "mkdir failed"

	# Remove xorg-nvidia.conf or xorg-aspeed.conf if exists
	# We dont take backups as these files are dynamically generated everytime
	# nvidia-conf-xconfig.service starts.
	rm  /etc/X11/xorg.conf.d/xorg-nvidia.conf > /dev/null 2>&1 || true
	rm  /etc/X11/xorg.conf.d/xorg-aspeed.conf > /dev/null 2>&1 || true

	NVIDIA_VGA=$(lspci | grep "VGA compatible controller: NVIDIA Corporation" | cut -d' ' -f1)
	NVIDIA_3D=$(lspci | grep "3D controller: NVIDIA Corporation" | cut -d' ' -f1)
	ASPEED_VGA=$(lspci | grep "VGA compatible controller: ASPEED Technology" | cut -d' ' -f1)

	if [ -z "${NVIDIA_VGA}" ]  && [ -z "${ASPEED_VGA}" ]; then
		err_and_exit_zero "Neither Nvidia nor ASPEED onboard VGA compatible controller found. Exiting without setup.."
	fi

	# Retrieve BIOS VGA settings
	# e.g
	# 	$dmidecode -t 11 | grep "OnBrd/Ext VGA Select"
	#	String 1: OnBrd/Ext VGA Select = Auto
	BIOS_VGA=`dmidecode -t 11 | grep "OnBrd/Ext VGA Select" | awk '{print $NF}'`

	if [ "${BIOS_VGA}" = "Auto" ] ;then
		# if no NVIDIA VGA device found then fallback to ASPEED
		 if [ -z "${NVIDIA_VGA}" ]; then
			echo "Nvidia VGA compatible controller not found"
			echo "Configuring ASPEED onboard VGA controller for display"
			configure_aspeed "$ASPEED_VGA"
		else
			configure_nvidia "$NVIDIA_VGA"
		fi

	elif [ "${BIOS_VGA}" = "Onboard" ] ;then
		if [ -z "${ASPEED_VGA}" ]; then
			echo "ASPEED VGA compatible controller not found for some reason"
			echo "Configuring Nvidia VGA controller for display"
			configure_nvidia "$NVIDIA_VGA"
		else
			configure_aspeed "$ASPEED_VGA"
		fi

	else
		# This means BIOS_VGA="External"
		if [ -n "${NVIDIA_VGA}" ]; then
			configure_nvidia "$NVIDIA_VGA"
		elif [ -n "${NVIDIA_3D}" ]; then
			configure_nvidia "$NVIDIA_3D"
		fi
	fi

	echo "New X configuration file written under /etc/X11/xorg.conf.d/"
	echo "If you restart this service, please reboot the system or restart the GNOME Display Manager (gdm3) service for these changes to take effect"
fi
exit 0
