#!/bin/sh

# Control the processor characteristics
# Depends: -

b="$(tput bold)"
u="$(tput smul)"
red="$(tput setf 4)"
n="$(tput sgr0)"

help() {
	cat << EOF
${b}NAME${n}
	cpuctl - control the processor characteristics

${b}SYNOPSIS${n}
	${b}cpuctl${n} ${u}OPERATION${n} [${u}OPTION${n}] [${u}ARG${n}]

${b}OPERATIONS${n}
	${b}-E${n}, ${b}--energy${n}
		Perform ${u}OPTION${n} on energy performance mode.

	${b}-G${n}, ${b}--governor${n}
		Perform ${u}OPTION${n} on scaling governor.

	${b}-h${n}, ${b}--help${n} Display usage message and exit.

${b}OPTIONS (APPLY TO -E or -G)${n}
	${b}-l${n}, ${b}--list${n}
		List the available items.

	${b}-g${n}, ${b}--get${n}
		Get the current item.

	${b}-s${n}[${u}ITEM${n}], ${b}--set [${n}${u}ITEM${n}]
		Set the ${u}ITEM${n}, prompt for ${u}ITEM${n} if left empty.
EOF
}

# Exit if no option is provided
[ "$#" -eq 0 ] && help && exit 1

# Main program
# --------------------------------------

listItems()
{
	if [ "$mode" = "energy" ]; then
		modes="/sys/devices/system/cpu/cpufreq/policy0/energy_performance_available_preferences"
	elif [ "$mode" = "governor" ]; then
		modes="/sys/devices/system/cpu/cpufreq/policy0/scaling_available_governors"
	fi

	tr ' ' '\n' < "$modes" | sed  '/^$/d' \
		| awk -v line="$1" '{ if (line == "") print NR") "$0; else if (NR == line) print $0; }'
}

getItem()
{
	if [ "$mode" = "energy" ]; then
		mode="/sys/devices/system/cpu/cpufreq/policy0/energy_performance_preference"
	elif [ "$mode" = "governor" ]; then
		mode="/sys/devices/system/cpu/cpufreq/policy0/scaling_governor"
	fi

	cat "$mode"
}

setItem()
{
	select="$1"
	if [ -z "$select" ]; then
		listItems
		printf "Enter the number to set: "
		read -r select
	fi
	item="$(listItems "$select")"

	if [ "$mode" = "energy" ]; then
		message="energy performance mode"
		type="/sys/devices/system/cpu/cpufreq/policy*/energy_performance_preference"
	elif [ "$mode" = "governor" ]; then
		message="scaling governor"
		type="/sys/devices/system/cpu/cpufreq/policy*/scaling_governor"
	fi

	if ! sudo -v; then
		echo "${b}${red}Error:${n} setting $message requires root privileges." >&2
		exit 1
	fi

	for i in $type; do
		echo "$item" | sudo tee "$i" > /dev/null
	done
}

# Option parsing
# --------------------------------------

script="$(basename "$0")"
parsed="$(getopt --options "hEGlgs::" \
				 --longoptions "help,energy,governor,list,get,set::" \
				 -n "$script" -- "$@" 2>&1)"
result="$?"

# Exit if invalid option is provided
if [ "$result" -ne 0 ]; then
	echo "$parsed" | head -n 1 >&2
	echo "Try './$script --help' for more information." >&2
	exit 1
fi

eval set -- "$parsed"

while true; do
	case "$1" in
		-h)
			help
			exit
			;;
		-E | --energy)
			if [ -n "$mode" ]; then
				echo "${b}${red}Error:${n} only one operation may be used at a time." >&2
				exit 1
			fi
			mode="energy"
			shift
			;;
		-G | --governor)
			if [ -n "$mode" ]; then
				echo "${b}${red}Error:${n} only one operation may be used at a time." >&2
				exit 1
			fi
			mode="governor"
			shift
			;;
		-l | --list)
			option="list"
			shift
			;;
		-g | --get)
			option="get"
			shift
			;;
		-s | --set)
			option="set"
			shift
			;;
		--)
			shift
			break
			;;
		*)
			break
			;;
	esac
done

# Execute
# --------------------------------------

if [ -z "$mode" ]; then
	echo "${b}${red}Error:${n} no operation specified (use -h for help)" >&2
	exit 1
fi

if [ "$mode" = "energy" ] || [ "$mode" = "governor" ]; then
	case "$option" in
		list | "")
			listItems
			;;
		get)
			getItem
			;;
		set)
			setItem "$1"
			;;
	esac
fi