#!/usr/bin/env bash
# Usage: intel-oc nocolor|internal|stop|log|quiet

OC_LOG=/var/log/intel-oc.log
OC_TIMEOUT=120
MAX_DELAY=300
MIN_DELAY=30
# apply without delay
NO_DELAY=10

[[ -f $RIG_CONF ]] && source $RIG_CONF
set -o pipefail

n=`gpu-detect INTEL`
if [[ $n -eq 0 ]]; then
	#echo "No INTEL GPU detected"
	exit 0
fi

[[ "$1" != "nocolor" ]] && source colors

if [[ "$1" == "log" ]]; then
	[[ ! -f $OC_LOG ]] && echo "${YELLOW}$OC_LOG does not exist${NOCOLOR}" && exit 1
	cat $OC_LOG 2>/dev/null && echo -e "\n${GRAY}=== $OC_LOG === $( stat -c %y $OC_LOG )${NOCOLOR}"
	exit
fi

# do not run OC simultaneously
if [[ "$2" != "internal" ]]; then
    readarray -t pids < <( pgrep -f "timeout .*$OC_LOG" )
	for pid in "${pids[@]}"; do
	    echo -e "${BYELLOW}Killing running intel-oc ($pid)${NOCOLOR}\n"
	    # timeout process PID is equal to the PGID, so using it to kill process group
	    kill -- -$pid
	done
fi

# just exit here
[[ "$1" == "stop" ]] && exit 0

# For Intel GPU not working yet
#[[ $MAINTENANCE == 2 ]] &&
#    echo "${YELLOW}Maintenance mode enabled, exiting${NOCOLOR}" &&
#    exit 1

# start main OC with timeout and logging
if [[ "$2" != "internal" ]]; then
    trap "echo -n $NOCOLOR" EXIT
    timeout --foreground -s9 $OC_TIMEOUT bash -c "set -o pipefail; $0 \"$1\" internal 2>&1 | tee $OC_LOG"
    exitcode=$?
    if [[ $exitcode -ne 0 && $exitcode -ne 143 ]]; then
	echo "${RED}ERROR: INTEL OC failed${NOCOLOR}"
	[[ "$1" != "quiet" ]] && cat $OC_LOG | message error "INTEL OC failed" payload > /dev/null
    fi
    exit $exitcode
fi

print_array() {
	local desc=$1
	local arr=($2)
	local align=10
	local pad=5
	printf "%-${align}s :" "$desc"
	for item in "${arr[@]}"
	do
		printf "%${pad}s" "$item"
	done
	printf "\n"
}

apply_mem() {
   return 0
}


[[ -f $INTEL_OC_CONF ]] && source $INTEL_OC_CONF || exit 1

[[ $MAINTENANCE == 2 ]] &&
	echo "${YELLOW}Maintenance mode enabled, exiting${NOCOLOR}" &&
	exit 1

date
echo -e "\nDetected $n ${BCYAN}Intel${NOCOLOR} cards\n"

if [[ ! -f $GPU_DETECT_JSON ]]; then
	gpu_detect_json=`gpu-detect listjson`
else
	gpu_detect_json=$(< $GPU_DETECT_JSON)
fi


idx=0
while IFS=";" read busid brand name mem vbios; do
	BUSID[idx]="$busid"
	BRAND[idx]="$brand"
	NAME[idx]="$name"
	RAM[idx]="$mem"
	VBIOS[idx]="$vbios"
	((idx++))
done < <( echo "$gpu_detect_json" | jq -r -c '.[] | select(.brand == "intel" or .vendor == "INTEL") | (.busid+";"+.brand+";"+.name+";"+.mem+";"+.vbios)' 2>/dev/null )


n=${#BUSID[@]}
if [[ $n -eq 0 ]]; then
	echo -e "${RED}No cards available for OC!\n${NOCOLOR}Please check BIOS settings, risers, connectors and PSU.\nTry to update INTEL drivers."
	exit 1
fi

[[ -f "$BUSID_FILE" ]] && source $BUSID_FILE

PARAMS=(CORE_CLOCK PLIMIT)

# pad arrays
for param in "${PARAMS[@]}"; do
	[[ -z ${!param} ]] && continue
	declare -n ref_arr="${param}"
	ref_arr=( ${!param} )
	for ((i=${#ref_arr[@]}; i < n; i++)); do
		ref_arr[i]="${ref_arr[-1]}" # use last element of initial array
	done
done

print_array "GPU BUS ID" "${BUSID[*]/:00\.0}"
for param in "${PARAMS[@]}"; do
	arr="${param}[*]"
	[[ -z "${!arr}" ]] && continue
	print_array "$param" "${!arr}"
done

oc_err=0
fan_idx=0
exitcode=0
index=0

for (( i=0; i < n; i++ )); do
	name="${NAME[i]/INTEL /}"

	echo ""
	busid="${BUSID[$i]}"
        err=0
        core_clk=
        pl=

	if [[ "${BRAND[i]}" != "intel" ]]; then
		echo "${YELLOW}===${NOCOLOR} GPU ${CYAN}-${NOCOLOR}, ${PURPLE}${BUSID[i]} ${BCYAN}$name${NOCOLOR} - ${BYELLOW}${VBIOS[i]} ${YELLOW}=== $(date +%T)${NOCOLOR}"
		continue
	fi

	echo "${YELLOW}===${NOCOLOR} GPU ${CYAN}$index${NOCOLOR}, ${PURPLE}${BUSID[i]} ${BCYAN}$name ${WHITE}${RAM[i]}${NOCOLOR} ${YELLOW}=== $(date +%T)${NOCOLOR}"

        [[ `echo /sys/bus/pci/devices/0000:"${busid}"/drm/card*/` =~ \/card([0-9]+)\/ ]]
        cardno=${BASH_REMATCH[1]}
        hwmondir=`realpath /sys/class/drm/card$cardno/device/hwmon/hwmon*/`

        [[ -z $cardno ]] && echo -e "${RED}ERROR: can not match card id${NOCOLOR}" && continue

        # Core Clock
        if [[ -n $CORE_CLOCK && ${CORE_CLOCK[$i]} -gt 0 ]]; then
           core_clk=${CORE_CLOCK[$i]}
           [[ -e /sys/class/drm/card$cardno/gt_boost_freq_mhz ]] && echo "$core_clk" > /sys/class/drm/card$cardno/gt_boost_freq_mhz 2>&1 ; err+=$?
           [[ -e /sys/class/drm/card$cardno/gt_max_freq_mhz ]] && echo "$core_clk"   > /sys/class/drm/card$cardno/gt_max_freq_mhz   2>&1 ; err+=$?
        fi

        # Power Limit
        if [[ -n $PLIMIT && ${PLIMIT[$i]} -gt 0 ]]; then
           pl=$(( PLIMIT[$i]*1000000 ))
           [[ -e $hwmondir/power1_max ]] && echo "$pl" > $hwmondir/power1_max
        fi

        [[ -n $core_clk ]] && echo -n "Core Clock: ${GREEN}${core_clk}${NOCOLOR} MHz "
        [[ -n $pl ]] && echo -n "Power Limit: ${GREEN}${PLIMIT[$i]}${NOCOLOR} W"
        echo ""
        if [[ $err -gt 0 ]]; then
           echo "${YELLOW}OC for Intel applied with errors!${NOCOLOR}"
           oc_err+=$err
        fi

	((index++))
done

exit $exitcode
