#!/bin/bash
#
#Copyright 2012 - 2018 CurlyMo & mkreisl <development@xbian.org>
#
#This file is part of XBian - XBMC on the Raspberry Pi.
#
#XBian is free software: you can redistribute it and/or modify it under the
#terms of the GNU General Public License as published by the Free Software
#Foundation, either version 3 of the License, or (at your option) any later
#version.
#
#XBian is distributed in the hope that it will be useful, but WITHOUT ANY
#WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
#FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
#details.
#
#You should have received a copy of the GNU General Public License along
#with XBian. If not, see <http://www.gnu.org/licenses/>

# Writes or updates overclocking value to file
#  $1 [Integer] arm_freq
#  $2 [Integer] core_freq
#  $3 [Integer] sdram_freq
#  $4 [Integer] over_voltage
#  $OCSCHMOO [Integer]
# Returns
#  none

function updateOCValuesFn() {
	deleteConfigVarFn "sdram_schmoo"
	if (( $1 > $OCSCHMOO )); then
		OCEXTRA="\nsdram_schmoo=0x02000020"
	else
		OCEXTRA=""
	fi
	getCurrentOCSettingsFn $1 $2 $3 $4
	if (( $CURRENTOC == 0 )); then
		sed -i ':a;N;$!ba;s/\n/|/g;s/||# \*\{78\}|# \* Raspberry Pi Overclocking                                                  \*|# \*\{78\}||//g;s/|/\n/g' /boot/config.txt
		deleteConfigVarFn "arm_freq"
		deleteConfigVarFn "core_freq"
		deleteConfigVarFn "sdram_freq"
		deleteConfigVarFn "over_voltage"
	else
		if ! grep -q "Raspberry Pi Overclocking" /boot/config.txt; then
			echo -e "\n\n# ******************************************************************************"   >> /boot/config.txt
			echo        "# * Raspberry Pi Overclocking                                                  *"   >> /boot/config.txt
			echo -e     "# ******************************************************************************\n" >> /boot/config.txt
		fi
		if [ "$1" != '...' ]; then updateConfigVarFn "arm_freq" $1;   else deleteConfigVarFn "arm_freq"; fi
		if [ "$2" != '...' ]; then updateConfigVarFn "core_freq" $2;  else deleteConfigVarFn "core_freq"; fi
		if [ "$3" != '...' ]; then updateConfigVarFn "sdram_freq" $3; else deleteConfigVarFn "sdram_freq"; fi
		if [ "$4" != '...' ]; then updateConfigVarFn "over_voltage" $4$OCEXTRA; else deleteConfigVarFn "over_voltage"; fi
	fi
}

# Retrieve the current overclocking settings
#  $1 $2 $3 $4 [Integer] optional
#              If given args  (arm_freq, core_freq, sdram_freq, over_voltage)
#              are used instead of reading from file /boot/config.txt
# Returns
#  $CURRENTOC [Integer]
#  - -1 Custom overclock
#  - *  Array key of current overclock
#  $OCOLDSETTINGS [Array]
#  - 0 ARM Frequency
#  - 1 Core Frequency
#  - 2 SDRAM Frequency
#  - 3 Over voltage

function getCurrentOCSettingsFn() {
	OCOLDSETTINGS=();
	if test "$(xbian-arch)" = "iMX6"; then
		RETURN=$(grep overclock /boot/boot.scr.txt)
		if [ "0$(echo ${RETURN##*overclock=} | awk '{print $1}')" -eq 1 ]; then
			OC=1200
		else
			OC=996
		fi
		OCOLDSETTINGS[0]=${OC}
	elif (( $# == 4 )); then
		OCOLDSETTINGS[0]=$1
		OCOLDSETTINGS[1]=$2
		OCOLDSETTINGS[2]=$3
		OCOLDSETTINGS[3]=$4
	else
		selectConfigVarFn "arm_freq="
		OCOLDSETTINGS[0]=${RETURN#*=}
		selectConfigVarFn "core_freq="
		OCOLDSETTINGS[1]=${RETURN#*=}
		selectConfigVarFn "sdram_freq="
		OCOLDSETTINGS[2]=${RETURN#*=}
		selectConfigVarFn "over_voltage="
		OCOLDSETTINGS[3]=${RETURN#*=}
	fi
	CURRENTOC=-1;
	NREMPTY=0;
	for KEY in ${!OCSETTINGS[@]}; do
		IFS=" ";
		SETTINGS=(${OCSETTINGS[$KEY]});
		I=0;
		for KEY1 in ${!SETTINGS[@]}; do
			if [ ! -z "${OCOLDSETTINGS[$KEY1]}" -a "${SETTINGS[$KEY1]}" = "${OCOLDSETTINGS[$KEY1]}" ]; then
				I=$(($I+1));
			elif [ -z "${OCOLDSETTINGS[$KEY1]}" ] && [ "${SETTINGS[$KEY1]}" = "n/a" -o "${SETTINGS[$KEY1]}" = "..." ]; then
				I=$(($I+1));
			fi
			if [ $I -eq ${#SETTINGS[@]} ]; then
				CURRENTOC=$KEY;
			fi
		done
	done
	X=0;
	DEFAULTVALUES=(${OCSETTINGS[0]});
	for KEY in ${!OCOLDSETTINGS[@]}; do
		if [ -z "${OCOLDSETTINGS[$KEY]}" ]; then
			X=$(($X+1));
			OCOLDSETTINGS[$KEY]=${DEFAULTVALUES[$KEY]};
		fi
	done;
	if [ $X -eq 4 ]; then
		CURRENTOC=0;
	fi
}

# Parse the overclock values in a menu structure
#  $1 [Integer] Current OC setting
# Returns
#  $OCMENU [Array]
#  - * Rows of the overclock menu
function createOCDLGMenuFn() {
	OCMENU=();
	for KEY in ${!OCSETTINGS[@]}; do
		IFS=" ";
		ROW=$(($KEY+1))","
		if [ ! -z $(echo "${OCDANGEROUS[*]}" | grep -o ${OCNAMES[$KEY]}) ]; then
			ROW+="\Z1";
			SAFE=-1;
		elif [ ! -z $(echo "${OCSAFE[*]}" | grep -o ${OCNAMES[$KEY]}) ]; then
			ROW+="\Z2";
			SAFE=0;
		else
			ROW+="\Zn";
			SAFE=1;
		fi
		ROW+=${OCNAMES[$KEY]};
		SETTINGS=(${OCSETTINGS[$KEY]});
		I=0;
		for KEY1 in ${!SETTINGS[@]}; do
			I=$(($I+1));
			[ "${SETTINGS[$KEY1]}" != '.' ] || continue
			ROW+=",";
			if [ $SAFE -eq -1 ]; then
				ROW+="\Z1";
			elif [ $SAFE -eq 0 ]; then
				ROW+="\Z2";
			else
				ROW+="\Zn";
			fi
			ROW+=${SETTINGS[$KEY1]};
		done
		if [ $1 -eq $KEY ]; then
			ROW+=",on";
		else
			ROW+=",off";
		fi
		OCMENU+=($ROW);
	done
	STATUS="off"
	if [ $1 -eq -1 ]; then
		STATUS="on";
	fi
	IFS=$ORIGINALIFS;

	test "$(xbian-arch)" = "iMX6" && return 0
	if [ $CURRENTOC -eq -1 ]; then
		test "$(xbian-arch)" = "iMX6" && OCMENU+=($(($KEY+2)),"\Z1"$(_ overclocking.label.custom),$STATUS) || \
			OCMENU+=($(($KEY+2)),"\Z1"$(_ overclocking.label.custom),"\Z1"${OCOLDSETTINGS[0]},"\Z1"${OCOLDSETTINGS[1]},"\Z1"${OCOLDSETTINGS[2]},"\Z1"${OCOLDSETTINGS[3]},$STATUS)
	else
		test "$(xbian-arch)" = "iMX6" && OCMENU+=($(($KEY+2)),"\Z1"$(_ overclocking.label.custom),$STATUS) || \
			OCMENU+=($(($KEY+2)),"\Z1"$(_ overclocking.label.custom),"\Z1...","\Z1...","\Z1...","\Z1...",$STATUS)
	fi
}

# Update the overclock settings to predefined values
# Returns
#  * [Integer]
#  - 1 Succes
#  - 0 Failed
function updateOCSettingsFn() {
	NEWOCSETTING=$1;
	IFS=" ";
	NEWOCVALUES=(${OCSETTINGS[$NEWOCSETTING]});
	NUMERIC=1
	for VALUES in ${NEWOCVALUES[@]}; do
		[ "${VALUES}" != 'n/a' -a "${VALUES}" != '...' ] || continue
		if ! [[ "$VALUES" =~ ^[0-9]+$ ]]; then
			NUMERIC=0
		fi
	done
	IFS=$ORIGINALIFS;
	if [ $NUMERIC -eq 1 ]; then
		if test "$(xbian-arch)" = "iMX6"; then
			if test ${NEWOCVALUES[0]} -eq 1200; then
				sed -i 's/overclock=./overclock=1/' /boot/boot.scr.txt
			else
				sed -i 's/overclock=./overclock=0/' /boot/boot.scr.txt
			fi
			[ -x /boot/mks ] && /boot/mks > /dev/null || :
		else
			updateOCValuesFn ${NEWOCVALUES[@]}
		fi
		getCurrentOCSettingsFn

		if [ $CURRENTOC -eq $NEWOCSETTING ]; then
			return 1;
		else
			return 0;
		fi
	else
		return 2;
	fi
}

# Update the overclock settings to custom values
#  $1 [String] Space seperated values (ARM CORE SDRAM VOLTAGE)
# Returns
#  * [Integer]
#  - 1 Succes
#  - 0 Failed
function updateCustomOCSettingsFn() {
	NEWOCVALUES=($1);
	
	NUMERIC=1;
	for VALUES in ${NEWOCVALUES[@]}; do
		if ! [[ "$VALUES" =~ ^[0-9]+$ ]]; then
			NUMERIC=0
		fi
	done
	if [ $NUMERIC -eq 1 ]; then
		updateOCValuesFn ${NEWOCVALUES[@]}
		IFS=$ORIGINALIFS;
		getCurrentOCSettingsFn
		if [ "${OCOLDSETTINGS[*]}" == "${NEWOCVALUES[*]}" ]; then
			return 1;
		else
			return 0;
		fi
	else
		return 2;
	fi
}
