#!/bin/sh

openntpd_file=/etc/ntpd.conf
ntp_file=/etc/ntp.conf
chrony_file=/etc/chrony.conf

sysconfigclock_file=/etc/sysconfig/clock
zonetab_file=/usr/share/zoneinfo/zone1970.tab
zoneinfo_dir=/usr/share/zoneinfo
tzdata_zi_file=/usr/share/zoneinfo/tzdata.zi

adjtime_file=/etc/adjtime
localtime_file=/etc/localtime

GCF=/etc/sysconfig/grub2
GU=/usr/sbin/update-grub
clocksource_current_file=/sys/devices/system/clocksource/clocksource0/current_clocksource
clocksource_available_file=/sys/devices/system/clocksource/clocksource0/available_clocksource

. alterator-sh-functions
. alterator-service-functions
. shell-config
. shell-var

### ntp

is_ntp_installed()
{
	if [ -f "$chrony_file" ] || [ -f "$openntpd_file" ] || [ -f "$ntp_file" ]; then
		return 0
	else
		return 1
	fi
}

ntpd_rdelim='[[:space:]]\+'
ntpd_wdelim=' '

read_pool()
{
	if [ -f "$chrony_file" ];then
		grep -e "^[[:space:]]*pool" "$chrony_file" | awk '{printf "%s ", $2}'
	elif [ -f "$openntpd_file" ];then
		grep -e "^[[:space:]]*servers" "$openntpd_file" | awk '{printf "%s ", $2}'
	elif [ -f "$ntp_file" ];then
		grep -e "^[[:space:]]*server" "$ntp_file" | awk '{printf "%s ", $2}'
	fi
}

write_pool_list()
{
	[ "$#" = 3 ] || return
	local config_file=$1
	local server_list=$2
	local template=$3
	for i in $server_list; do
		printf "$template" $i >> "$config_file"
	done
}

write_pool()
{
	if [ -f "$chrony_file" ];then
		sed -i -e "/^[[:space:]]*pool[[:space:]]\+/d" "$chrony_file"
		[ -z "$1" ] || write_pool_list "$chrony_file" "$1" "pool %s iburst\n"
	elif [ -f "$openntpd_file" ];then
		sed -i -e "/^[[:space:]]*servers*[[:space:]]\+/d" "$openntpd_file"
		[ -z "$1" ] || write_pool_list "$openntpd_file" "$1" "servers %s\n"
	elif [ -f "$ntp_file" ];then
		cat>"$ntp_file"<<EOF
#generated by alterator-datetime

driftfile /etc/ntp/drift
EOF
	[ -z "$1" ] || write_pool_list "$ntp_file" "$1" "server %s iburst burst prefer\n"
cat>>"$ntp_file"<<EOF
server 127.127.1.0 iburst
fudge  127.127.1.0 stratum 10

restrict default noquery nomodify
restrict 127.0.0.1
EOF
    fi
    if [ -f "$chrony_file" ]; then
	service_control chronyd condrestart
    else
        service_control ntpd condrestart
    fi
}

test_ntp_status()
{
    if [ -f "$chrony_file" ]; then
	service_control chronyd is-enabled
    else
        service_control ntpd is-enabled
    fi
}

write_ntp_status()
{
    if test_bool "$1"; then
      if [ -f "$chrony_file" ]; then

        service_control chronyd on
        service_control chronyd start
      else
	service_control ntpd on
	service_control ntpd start
      fi
    else
      if [ -f "$chrony_file" ]; then
        service_control chronyd off
        service_control chronyd condstop
      else
        service_control ntpd off
        service_control ntpd condstop
      fi
    fi
}

test_ntp_accept()
{
    local result=
    if [ -f "$chrony_file" ]; then
      if result="$(/usr/sbin/control chrony 2>/dev/null)";then
	[ "$result" = "server" ]
      else
	true
      fi
    else
      if result="$(/usr/sbin/control ntpd 2>/dev/null)";then
	[ "$result" = "server" ]
      else
	true
      fi

    fi
}

write_ntp_accept()
{
    if [ -f "$chrony_file" ]; then
      if /usr/sbin/control chrony >/dev/null 2>/dev/null;then
	if test_bool "$1";then
	    /usr/sbin/control chrony server >/dev/null 2>/dev/null
	else
	    /usr/sbin/control chrony client >/dev/null 2>/dev/null
	fi
      else
	true
      fi
    else
      if /usr/sbin/control ntpd >/dev/null 2>/dev/null;then
	if test_bool "$1";then
	    /usr/sbin/control ntpd server >/dev/null 2>/dev/null
	else
	    /usr/sbin/control ntpd client >/dev/null 2>/dev/null
	fi
      else
	true
      fi
    fi
}

### timezone
is_valid_timezone()
{
	local tz="${1-}"

	if [ -n "$tz" ] && [ -f "$zoneinfo_dir/$tz" ]; then
		return 0
	fi

	return 1
}

cat_isotab_file()
{
    local domain="${2:-$po_domain}"
    local langlist="$(write_language "$in_language")"
    local firstlang="${langlist%%:*}"

    LC_ALL="$firstlang" LANGUAGE="$langlist" dumpisotab 2>/dev/null|
	LC_ALL="$firstlang" LANGUAGE="$langlist" sort -k2,2 2>/dev/null
}

# Get timezone from kernel command line.
get_timezone_cmdline()
{
	sed -r -n 's/^(.+[[[:space:]])?tz=([^ ]*).*/\2/p' /proc/cmdline 2>/dev/null
}

GEOIP_URL="https://geoip.altlinux.org"

# Get timezone from geoip server (if network is up).
get_timezone_geoip()
{
	if ip route | grep -qs '^default'; then
		local insecure=

		# Don't use TLS if ca-certificates not installed
		[ -f /usr/share/ca-certificates/ca-bundle.crt ] ||
			insecure="-k"

		curl -s $insecure --max-time 2 "$GEOIP_URL/csv/" | cut -f8 -d,
	fi
}

# Guess timezone based on language.
get_timezone_lang()
{
	local lang="${1-}"
	local lang_code=

	if [ -z "$lang" ]; then
		lang="$(sed -r -n 's/^(.+[[[:space:]])?lang=([^ ]*).*/\2/p' /proc/cmdline 2>/dev/null)"
	fi

	lang_code="$(printf %s "$lang" |
		sed -r -e 's,[a-z]+_([^\.]+)(\..*)?,\1,' |
		tr '[:lower:]' '[:upper:]')"

	[ -z "$lang_code" ] ||
		grep "^$lang_code[[:space:]]" "/etc/alterator/datetime/defaultzones" |cut -f2
}

get_timezone()
{
	local lang="${1-}"
	local tz=

	# First try kernel command line
	tz="$(get_timezone_cmdline)"
	if is_valid_timezone "$tz"; then
		echo "$tz"
		return 0
	fi

	# Second try to use geoip server
	tz="$(get_timezone_geoip)"
	if is_valid_timezone "$tz"; then
		echo "$tz"
		return 0
	fi

	# As last resort try to guess based on language
	tz="$(get_timezone_lang "$lang")"
	if is_valid_timezone "$tz"; then
		echo "$tz"
		return 0
	fi

	return 1
}

read_zone()
{
	local ZONE=
	local language="${1:-$in_language}"

	if [ -f "$sysconfigclock_file" ]; then
		ZONE="$(shell_config_get "$sysconfigclock_file" "ZONE")"
	elif [ -L "$localtime_file" ]; then
		ZONE="$(readlink "$localtime_file" |
			sed "s,^.*$zoneinfo_dir/,,")"
	fi
	shell_var_unquote ZONE "$ZONE"

	if [ -z "$ZONE" ]; then
		ZONE="$(get_timezone "${language%%;*}")"
		[ -n "$ZONE" ] ||
			ZONE="Europe/London"
	fi

	printf "%s\n" "$ZONE"
}

write_zone()
{
	local zone="${1:-$in_zone}"

	is_valid_timezone "$zone" || return 1

	if [ -f "$sysconfigclock_file" ]; then
		shell_config_set "$sysconfigclock_file" "ZONE" "$zone"
		tzupdate
	else
		rm -f "$localtime_file"
		ln -s ..$zoneinfo_dir/$zone "$localtime_file"
	fi
}

init_timezone()
{
	local zone="${1-}"

	# Check config.
	# We need to setup it if there is no ZONE.
	if [ -f "$sysconfigclock_file" ]; then
		[ -z "$(shell_config_get "$sysconfigclock_file" "ZONE")" ] ||
			return 0
	else
		[ ! -L "$localtime_file" ] || return 0
	fi

	if [ -z "$zone" ]; then
		zone="$(read_zone)"
		[ -n "$zone" ] || return 1
	fi

	write_zone "$zone"
}

translate_zone()
{
    _ "$1" alterator-tzone-tz|tr '_' ' '
}

is_zone_link()
{
	if [ ! -f "$tzdata_zi_file" ] || grep -qs "^Z[[:blank:]]$1[[:blank:]]" "$tzdata_zi_file"; then
		return 1
	fi

	return 0
}

get_region_from_zone()
{
	local r=
	if is_zone_link "$1"; then
		r="$(sed -rn "s;^L[[:blank:]]([^[:blank:]]+)[[:blank:]]$1[[:blank:]]*$;\1;p" "$tzdata_zi_file")"
	else
		r="$1"
	fi
	echo "${r%%/*}"
}

list_zones_for_region() {
	(
		grep -v '^[[:blank:]]*#' "$zonetab_file" | cut -f3 | grep  "^$1/" |
			while read zone; do
				tz_num="$(TZ="$zone" date +%:::z)"
				tr_zone="$(translate_zone "$zone")"
				printf "%s|%s|%s\n" "$zone" "${tr_zone#*/}" "($tz_num)"
		done
		if [ -f "$tzdata_zi_file" ]; then
			grep "^L[[:blank:]]$1/" "$tzdata_zi_file" | cut -d' ' -f3 |
				while read zone; do
					# Skip zones that a link as <Region>/<Name> <Name>
					# (like L America/Jamaica Jamaica)
					if grep -qs "^Z[[:blank:]]$1/$zone[[:blank:]]" "$tzdata_zi_file"; then
						continue
					fi
					tz_num="$(TZ="$zone" date +%:::z)"
					tr_zone="$(translate_zone "$zone")"
					# Remove region from link zone name
					if [ "${zone%%/*}" = "$1" ]; then
						tr_zone="${tr_zone#*/}"
					fi
					printf "%s|%s|%s\n" "$zone" "${tr_zone#$1/}" "($tz_num)"
				done
		fi
	) | sort -t'|' -k 2,2 | tr '|' ' ' | write_enum
}

list_region() {
    grep -v '^[[:blank:]]*#' "$zonetab_file" | cut -f3 | sed -n -r 's|^([[:alpha:]]+)/[[:alpha:]/_-]+$|\1|p' | sort -u |
        while read region; do
            local tr_region="$(translate_zone "$region")"
            write_enum_item "$region" "$tr_region"
        done
}

# Old functions for countries. UI was changed, these functions are not used now.
# Keep them for now, just in case they are used by some 3d-party script.
# TODO: Drop them later,
read_country()
{
    cut -f1,3 "$zonetab_file" |grep "[[:space:]]$1" |cut -f1 |cut -f1 -d','
}

country_name()
{
    cat_isotab_file|sed -n "s/^$1[[:space:]]\+//p"
}

list_country() {
    cat_isotab_file|write_enum
}

list_zone() {
	local IFS="	"
	local code coordinates zone comments
	local tr_zone= tz_num=

	grep -E "^([[:upper:]][[:upper:]],)*$1(,[[:upper:]][[:upper:]])*[[:space:]]" "$zonetab_file" |
	while read code coordinates zone comments; do
		tz_num="$(TZ="$zone" date +%:::z)"
		tr_zone="$(translate_zone "$zone")"
		write_enum_item "$zone" "${tr_zone#*/} ($tz_num)"
	done
}

### utc
# Get UTC from kernel command line.
get_utc_cmdline()
{
	local utc=
	utc="$(sed -r -n 's/^(.+[[[:space:]])?utc=([^ ]*).*/\2/p' /proc/cmdline 2>/dev/null)"

	case "$utc" in
		0) echo "false"; return 0;;
		1) echo "true"; return 0;;
		*) return 1;;
	esac
}

read_utc()
{
    if [ -s "$sysconfigclock_file" ]; then
	shell_config_get "$sysconfigclock_file" UTC
    elif is_adjtime_utc; then
	echo "true"
    else
	echo "false"
    fi
}

write_utc()
{
    set_adjtime_utc "$1"

    [ -s "$sysconfigclock_file" ] || return 0

    if test_bool "$1";then
	shell_config_set "$sysconfigclock_file" UTC "true"
    else
	shell_config_set "$sysconfigclock_file" UTC "false"
    fi
}

### /etc/adjtime

is_adjtime_utc()
{
    [ -s "$adjtime_file" ] || return 0

    if [ "$(sed -n '3p' "$adjtime_file")" = "LOCAL" ]; then
        return 1
    else
        return 0
    fi
}

set_adjtime_utc()
{
    local new_str= old_str=

    if test_bool "$1"; then
        new_str=UTC
        old_str=LOCAL
    else
        new_str=LOCAL
        old_str=UTC
    fi

    if [ -s "$adjtime_file" ]; then
        sed -i "3{s/$old_str/$new_str/}" "$adjtime_file"
    else
        cat > "$adjtime_file" <<EOF
0.0 0 0
0
$new_str
EOF
    fi
}

### clocksource

clocksource_edit_grub() {
    [ -n "$1" ] || return

    if grep -q -e "^GRUB_CMDLINE_LINUX_DEFAULT=.*clocksource.*" "$GCF"
    then
        sed -i -e "/^GRUB_CMDLINE_LINUX_DEFAULT=/s/clocksource=[a-zA-Z0-9_-]*/clocksource=$1/" "$GCF"
    else
        sed -i -e "/^GRUB_CMDLINE_LINUX_DEFAULT=/s/'/ clocksource=$1'/2" "$GCF"
    fi

    $GU &>/dev/null
}

clocksource_set() {
    [ -n "$1" ] || return

    [ "$1" != $(clocksource_current) ] || return

    echo "$1" > "$clocksource_current_file"
    clocksource_edit_grub "$1"
}

clocksource_current() {
    cat "$clocksource_current_file"
}

clocksource_available() {
    cat "$clocksource_available_file" | tr " " "\n" | write_enum
}

clocksource_show() {
    [ $(arch) == "x86_64" ] && echo "Yes" || echo "No"
}

clock_service_start() {
    if sysv_service_exists 'clock'; then
        sysv_service_control 'clock' start >/dev/null 2>/dev/null
    fi
}

clock_service_sync() {
    if sysv_service_exists 'clock'; then
        sysv_service_control 'clock' sync >/dev/null 2>/dev/null
    else
        hwclock --systohc >/dev/null 2>/dev/null
    fi
}
