#!/bin/sh

configdir=/etc/alterator/mirror/config
desturl=/mirror
destdir=/srv/public/mirror

repositorydir=/etc/apt/repositories
mirrordir=/etc/apt/mirrors

alterator_api_version=1

url_re='^\(ftp://\|http://\|rsync://\|file:/\)[a-zA-Z0-9._/:@-]\+$'
rsync_url_re='^rsync://[a-zA-Z0-9._/-:@]\+$'

. alterator-sh-functions
. avahi-sh-functions
. shell-quote
. shell-config

### low level

repository_awk()
{
    alterator-dump-desktop \
        -v lang="$in_language" \
        -v out="Filename;X-Path;X-Has-Noarch;X-Mirror;Name" \
        -v def="noname;/notfound;no;yes" \
	"$@"
}

mirror_awk()
{
    alterator-dump-desktop \
        -v lang="$in_language" \
        -v out="Filename;X-Repositories;Name;Comment" \
        -v def="noname;all" \
	"$@"
}

config_get()
{
    local v="$(shell_config_get "$configdir/$1" "$2")"
    string_quote_remove "$v"
}

config_set()
{
    local f="$configdir/$1"
    [  -s "$f" ] || echo ". $configdir/.common" >"$f"

    shell_config_set "$f" "$2" "\"$3\""
}

tr_size()
{
    sed -e "s/M/`_ "Mb"`/" \
	-e "s/K/`_ "Kb"`/" \
	-e "s/G/`_ "Gb"`/"
}


### high level
read_arch()
{
    local arch="$(config_get "$1" ARCH)"
    echo "${arch%% noarch}"
}

read_local()
{
    [ "$(config_get "$1" ALTERATOR_LOCAL)" = "yes" ]
}

read_publish()
{
    [ "$(config_get "$1" ALTERATOR_PUBLISH)" = "yes" ]
}

write_publish()
{
    local name="$1";shift
    local status="$1";shift

    if test_bool "$status"; then
	local mirror="$(config_get "$name" ALTERATOR_MIRROR)"
	local custom_url="$(config_get "$name" ALTERATOR_CUSTOM_URL)"

	[ "$mirror" = "custom" ] || custom_url=

	if read_local "$name"; then
	    mirror=custom
	    custom_url="$desturl"
	fi

	config_set "$name" ALTERATOR_PUBLISH yes
	publish_service "alterator-mirror-$name" "System updates at %h ($name)" "_apt._tcp" 0 \
		"r=$name" \
		"m=$mirror" \
		"u=$custom_url" \
		"a=$(read_arch "$name")"
    else
	config_set "$name" ALTERATOR_PUBLISH no
	unpublish_service "alterator-mirror-$name"
    fi
}

list_repository()
{
    repository_awk $repositorydir/*.desktop|
	while read name path noarch mirror description;do
	    [ "$mirror" = "yes" ] || continue

	    name="${name##*/}"
	    name="${name%.desktop}"

	    if [ ! -s "$configdir/$name" ];then
		write_table_item \
		    name "$name" \
		    description "$description" \
		    mirror "" \
		    arch "" \
		    local_status "off" \
		    local_du "" \
		    publish "off"
		continue
	    fi

	    local r_mirror="$(config_get "$name" ALTERATOR_MIRROR)"

	    local r_path=
	    if [ "$r_mirror" = "custom" ];then
		r_path="$(config_get "$name" ALTERATOR_CUSTOM_URL)"
	    elif [ -n "$r_mirror" ];then
		r_path="$(alterator-dump-desktop -v lang="$in_language" -v out=Name "$mirrordir/$r_mirror.desktop")"
	    fi

	    local r_arch="$(read_arch "$name")"

	    local r_local_du="($(run_localized du -sh "$destdir/$path" 2>/dev/null| cut -f1| tr_size))"
	    local r_local_status=
	    if read_local "$name"; then
		[ "$r_local_du" != '()' ] || r_local_du="(0 `_ "Kb"`)"
		r_local_status="on"
	    else
		[ "$r_local_du" != "()" ] || r_local_du=""
		r_local_status="off"
	    fi

	    r_publish=
	    if read_publish "$name"; then
		r_publish="on"
	    else
		r_publish="off"
	    fi

	    write_table_item \
		name "$name" \
		description "$description" \
		mirror "$r_path" \
		arch "$r_arch" \
		local_status "$r_local_status" \
		local_du "$r_local_du" \
		publish "$r_publish"
	done
}

list_mirror()
{
    local repo="$1";shift
    local IFS="	"

    mirror_awk $mirrordir/*.desktop|
	while read id repolist name comment; do

	    repolist=";$repolist;"
	    [ "$repolist" = ";all;" -o -z "${repolist##*;$repo;*}" ] || continue

	    id="${id##*/}"
	    id="${id%.desktop}"

	    printf '%s\t%s (%s)\n' "$id" "$name" "$comment"
	done | write_enum

    write_enum_item "custom" "`_ "Custom url"`"
}

list_arch()
{
    write_enum_item "i586"
    write_enum_item "x86_64"
}


read_storage()
{
    local real_destdir="$(readlink -e "$destdir")"
    run_localized df -lhP |
	sed 1d |
	sort -r -k 6,6 |
	while read fs total use avail percent mpoint; do
	    [ -z "${real_destdir##$mpoint*}" ] || continue
	    write_string_param "storage_avail" "$(echo "$avail"|tr_size)"
	    break
	done
}

get_rsync_url()
{
    if [ "$1" = "custom" ];then
	echo "$2"
    else
	shell_config_get "$mirrordir/$1.desktop" X-RSYNC-URI
    fi
}

## initial tuning
[ "$(config_get ".common" DESTROOT)" = "$destdir" ] ||
    config_set ".common" DESTROOT "$destdir"

on_message()
{
	case "$in_action" in
		list)
			case "$in__objects" in
			    avail_repository)
				list_repository;;
			    avail_arch)
				list_arch;;
			    avail_mirror)
				[ -n "$in_name" ] && list_mirror "$in_name" ;;
			esac
			;;
		validate_mirror)
			[ "$in_mirror" = "custom" ] ||
			    grep -qs 'X-RSYNC-URI=' "$mirrordir/$in_mirror.desktop" ||
			    write_error "Not a rsync mirror"
			;;
		read)
			case "$in__objects" in
			    /)
				write_bool_param enabled "$(config_get ".common" ALTERATOR_ENABLED)"
				read_storage
				;;
			    repository)
				[ -n "$in_name" ] || return

				repository_awk $repositorydir/$in_name.desktop|
				    (read name path noarch mirror description;
					write_string_param description "$description")

				write_string_param	arch		"$(config_get "$in_name" ARCH|tr ' ' ';')"
				write_string_param	mirror		"$(config_get "$in_name" ALTERATOR_MIRROR)"
				write_string_param	custom_url	"$(config_get "$in_name" ALTERATOR_CUSTOM_URL)"
				write_bool_param	local		"$(config_get "$in_name" ALTERATOR_LOCAL)"
				write_bool_param	publish		"$(config_get "$in_name" ALTERATOR_PUBLISH)"
				;;
			esac
			;;
		write)
		    case "$in__objects" in
			/)
			    ! test_bool "$in_enabled"
			    config_set ".common" ALTERATOR_ENABLED "$?"
			;;
			repository)
			    if [ -n "$in_clear" -a -n "$in_name" ];then
				repository_awk "$repositorydir/$in_name.desktop"|
				(read name path noarch description;
				    [ -n "$path" ] && rm -rf "$destdir/$path")
			    elif [ -n "$in_commit" ];then
				local r_file="$repositorydir/$in_name.desktop"
				local r_path="$(shell_config_get "$r_file" X-Path)"
				local r_noarch="$(shell_config_get "$r_file" X-Has-Noarch)"

				#check custom_url
				if [ "$in_mirror" = "custom" ] ;then
				    if [ -z "$in_custom_url" ];then 
					write_error "`_ "Custom url should be defined"`"
					return
				    elif ! echo "$in_custom_url"|grep -qs "$url_re";then
					write_error "`_ "Invalid or unsupported protocol. Should be http,ftp or rsync"`"
					return
				    elif [ -n "$in_local" ] && ! echo "$in_custom_url"|grep -qs "$rsync_url_re";then
					write_error "`_ "Can mirror only from sources with rsync procotol"`"
					return
				    fi
				fi

				config_set "$in_name" LIST "$r_path"
				[ -n "$in_arch" -a "$r_noarch" = "yes" ] && in_arch="${in_arch};noarch"
				config_set "$in_name" ARCH "$(echo $in_arch|tr ';' ' ')"

				config_set "$in_name" ALTERATOR_MIRROR "$in_mirror"
				config_set "$in_name" ALTERATOR_CUSTOM_URL "$in_custom_url"

				local rsync_url="$(get_rsync_url "$in_mirror" "$in_custom_url")"
				if [ -n "$rsync_url" ] && test_bool "$in_local"; then
				    config_set "$in_name" ALTERATOR_LOCAL yes
				    config_set "$in_name" SRCROOT "$rsync_url"
				else
				    config_set "$in_name" ALTERATOR_LOCAL no
				    config_set "$in_name" SRCROOT ""
				fi

				write_publish "$in_name" "$in_publish"
			    fi
		    esac
		    ;;
	esac
}

message_loop
