#!/usr/bin/env sh

### Script: changeconfig
##
## 設定ファイルの値を更新する。
##
## Metadata:
##
##   id - 3869c46c-0eec-4d0a-8d31-ddc3af9be2d4
##   author - <qq542vev at https://purl.org/meta/me/>
##   version - 3.0.3
##   date - 2022-10-20
##   since - 2019-08-02
##   copyright - Copyright (C) 2019-2022 qq542vev. Some rights reserved.
##   license - <CC-BY at https://creativecommons.org/licenses/by/4.0/>
##   package - w3mplus
##
## See Also:
##
##   * <Project homepage at https://github.com/qq542vev/w3mplus>
##   * <Bug report at https://github.com/qq542vev/w3mplus/issues>
##
## Help Output:
##
## ------ Text ------
## Usage:
##   changeconfig [OPTION]... [FILE]...
##
## Options:
##   -i,     --{no-}in-place     FILE を更新して保存する
##           --max NUMBER        計算結果の最大値を指定する
##           --min NUMBER        計算結果の最小値を指定する
##   -p,     --param NAME=VALUE | NAME=OPERATOR=UNSIGNED_NUMBER | NAME=! 
##                               NAME の値を更新する
##           --no-param          -p, --param をリセットする
##   -h,     --help              このヘルプを表示して終了する
##   -v,     --version           バージョン情報を表示して終了する
##
## Exit Status:
##     0 - successful termination
##    64 - command line usage error
##    65 - data format error
##    66 - cannot open input
##    67 - addressee unknown
##    68 - host name unknown
##    69 - service unavailable
##    70 - internal software error
##    71 - system error (e.g., can't fork)
##    72 - critical OS file missing
##    73 - can't create (user) output file
##    74 - input/output error
##    75 - temp failure; user is invited to retry
##    76 - remote error in protocol
##    77 - permission denied
##    78 - configuration error
##   129 - received SIGHUP
##   130 - received SIGINT
##   131 - received SIGQUIT
##   143 - received SIGTERM
## ------------------

readonly 'VERSION=changeconfig 3.0.3'

. 'initialize.sh'
. 'option_error.sh'
. 'regex_match.sh'
. 'awkv_escape.sh'
. 'append_array_posix.sh'

# @getoptions
parser_definition() {
	setup REST abbr:true error:option_error plus:true no:0 help:usage \
		-- 'Usage:' "  ${2##*/} [OPTION]... [FILE]..." \
		'' 'Options:'

	flag  placeFlag -i --{no-}in-place init:@no -- 'FILE を更新して保存する'
	param max     --max        validate:'regex_match "${OPTARG}" "^[+-]?(0|[1-9][0-9]*)(\\.[0-9]+)?$"' var:NUMBER -- '計算結果の最大値を指定する'
	param min     --min        validate:'regex_match "${OPTARG}" "^[+-]?(0|[1-9][0-9]*)(\\.[0-9]+)?$"' var:NUMBER -- '計算結果の最小値を指定する'
	param :'append_array_posix param "${OPTARG}"' -p --param validate:'regex_match "${OPTARG}" "^[0-9A-Za-z_-]+="' var:'NAME=VALUE | NAME=OPERATOR=UNSIGNED_NUMBER | NAME=!' -- 'NAME の値を更新する'
	flag  param   --no-param   init:@no on: no: -- '-p, --param をリセットする'
	disp  :usage  -h --help    -- 'このヘルプを表示して終了する'
	disp  VERSION -v --version -- 'バージョン情報を表示して終了する'

	msg -- '' 'Exit Status:' \
		'    0 - successful termination' \
		'   64 - command line usage error' \
		'   65 - data format error' \
		'   66 - cannot open input' \
		'   67 - addressee unknown' \
		'   68 - host name unknown' \
		'   69 - service unavailable' \
		'   70 - internal software error' \
		"   71 - system error (e.g., can't fork)" \
		'   72 - critical OS file missing' \
		"   73 - can't create (user) output file" \
		'   74 - input/output error' \
		'   75 - temp failure; user is invited to retry' \
		'   76 - remote error in protocol' \
		'   77 - permission denied' \
		'   78 - configuration error' \
		'  129 - received SIGHUP' \
		'  130 - received SIGINT' \
		'  131 - received SIGQUIT' \
		'  143 - received SIGTERM'
}
# @end

# @gengetoptions parser -i parser_definition parse "${1}"
# @end

eval "$(getoptions parser_definition parse "${0}")"
parse ${@+"${@}"}
eval "set -- ${REST}"

tmpDir=$(mktemp -d)
tmpConfig="${tmpDir}/config"
awkScript=$(
	cat <<-'__EOF__'
	BEGIN {
		split("", not)
		split("", param)

		not["0"] = 1; not["1"] = 0;
		not["TRUE"] = "FALSE"; not["True"] = "False"; not["true"] = "false";
		not["FALSE"] = "TRUE"; not["False"] = "True"; not["false"] = "true";
		not["YES"] = "NO"; not["Yes"] = "No"; not["yes"] = "no";
		not["NO"] = "YES"; not["No"] = "Yes"; not["no"] = "yes";

		for(i = 1; i < ARGC; i++) {
			if(ARGV[i] == "--") {
					delete ARGV[i]
					break
			}

			position = index(ARGV[i], "=")
			param[substr(ARGV[i], 1, position - 1)] = substr(ARGV[i], position + 1)

			delete ARGV[i]
		}
	}

	{
		if(match($0, /^[ \t]*[0-9A-Za-z-][_.0-9A-Za-z-]+[ \t]+/)) {
			name = substr($0, RSTERT, RLENGTH)
			gsub(/[ \t]/, "", name)

			value = substr($0, RLENGTH + 1)
			gsub(/[ \t]$/, "", value)

			if(name in param) {
				if((param[name] ~ /^[+*/%^-]=[1-9][0-9]*(\.[0-9]+)?$/) && (value ~ /^[+-]?(0|[1-9][0-9]*)(\.[0-9]+)?$/)) {
					operator = substr(param[name], 1, 1)
					decimalFlag = index(value, ".")

					if(operator == "+") {
						value += substr(param[name], 3)
					}	else if(operator == "-") {
						value -= substr(param[name], 3)
					}	else if(operator == "*") {
						value *= substr(param[name], 3)
					}	else if(operator == "/") {
						value /= substr(param[name], 3)
					}	else if(operator == "%") {
						value %= substr(param[name], 3)
					}	else if(operator == "^") {
						value ^= substr(param[name], 3)
					}

					if(max != "" && max < value) {
						value = max
					} else if(min != "" && value < min) {
						value = min
					} else if(!decimalFlag) {
						value = int(value)
					} else if(value == int(value)) {
						value = value ".0"
					}
				} else if((param[name] == "!") && (value in not)) {
					value = not[value]
				} else {
					value = param[name]
				}
			}

			printf("%s %s\n", name, value)
		} else {
			printf("%s\n", $0)
		}
	}
	__EOF__
)

command='awk -v "max=${max}" -v "min=${min}" -- "${awkScript}" '"${param} --"

case "${placeFlag}" in
	'0') eval "${command}" '${@+"${@}"}';;
	*)
		for config in ${@+"${@}"}; do
			case "${config}" in '-')
				printf "%s: '-i', '--in-place' オプションでは標準入力は使用できません。無視します。\\n" "${0##*/}" >&2
				continue
			esac

			eval "${command}" '"${config}"' >"${tmpConfig}"
			cat -- "${tmpConfig}" >"${config}"
		done
		;;
esac
