#!/bin/sh -u

cachedir="/var/cache/alterator/net-eth"

rdelim='[[:space:]]\+'
wdelim=' '
default_bridge_type=bri

alterator_api_version=1

. alterator-sh-functions
. alterator-net-functions
. alterator-hw-functions
. shell-config
. shell-var

get_bridge_type()
{
	local name=$1; shift
	local ifacedir="$(ifacedir_with_cache "$cachedir" "$name")"
	if [ -d "$ifacedir" ]; then
		read_iface_option "$ifacedir" TYPE
	else
		echo "$default_bridge_type"
	fi
}

set_bridge_type()
{
	local name=$1; shift
	local bridge_type=$1; shift
	local ifacedir="$(ifacedir_with_cache "$cachedir" "$name")"
	if [ -d "$ifacedir" ]; then
		write_iface_option "$ifacedir" TYPE "$bridge_type"
	fi
}

list_avail_ifaces()
{
	local iface=
	list_eth | while read iface; do
		if iface_has_host_with_cache "$cachedir" "$iface"; then
			continue
		fi

		echo "$iface"
	done
}

list_bridge_members()
{
	local name="$1"; shift
	local ifacedir="$(ifacedir_with_cache "$cachedir" "$name")"

	if [ -d "$ifacedir" ]; then
		iface_type="$(read_iface_option "$ifacedir" TYPE)"
		if list_bridge_types | grep -qF "$iface_type"; then
			for s in $(read_iface_host_var "$ifacedir"); do
				echo "$s"
			done
		fi
	fi
}

update_members()
{
	local name="$1"; shift
	local ifacedir=
	local bridge_type="$(get_bridge_type "$name")"

	for iface in $(list_bridge_members "$name"); do
		ifacedir="$(ifacedir_with_cache "$cachedir" "$iface")"
		if [ -d "$ifacedir" ]; then
			case "$bridge_type" in
				ovsbr)
					write_iface_option "$ifacedir" TYPE ovsport
					write_iface_option "$ifacedir" BRIDGE "$name"
					;;
				*)
					write_iface_option "$ifacedir" TYPE eth
					delete_iface_option "$ifacedir" BRIDGE
					;;
			esac
		fi
	done
}

clear_member_options()
{
	local iface="$1"; shift
	local ifacedir="$(ifacedir_with_cache "$cachedir" "$iface")"
	if [ -d "$ifacedir" ]; then
		local iface_type="$(read_iface_option "$ifacedir" TYPE)"
		case "$iface_type" in
			ovsport)
				write_iface_option "$ifacedir" TYPE eth
				;;
		esac
		delete_iface_option "$ifacedir" BRIDGE
	fi
}

init_cache()
{
	local name="$1"; shift

	if [ -z "$name" ]; then
		return
	elif iface_will_removed "$cachedir" "$name"; then
		rm -r -- "$cachedir/$name/"
	elif [ -d "$cachedir/$name" ]; then
		return
	fi

	if [ -d "/etc/net/ifaces/$name" ]; then
		mkdir -p -- "$cachedir/"
		cp -a "/etc/net/ifaces/$name" "$cachedir/"
		return
	fi

	mkdir -p -- "$cachedir/$name"

	cat > "$cachedir/$name/options" <<OPTIONS_TEMPLATE
TYPE=$default_bridge_type
ONBOOT=yes
DISABLED=no
NM_CONTROLLED=no
CONFIG_WIRELESS=no
CONFIG_IPV4=yes
CONFIG_IPV6=no
BOOTPROTO=static
HOST=""
OPTIONS_TEMPLATE
}

on_message()
{
	case "$in_action" in
		list)
			case "${in__objects##*/}" in
				avail_ifaces) list_avail_ifaces | write_enum;;
				bridge_members) list_bridge_members "$in_bridge" | write_enum;;
				avail_bridge_types) list_bridge_types | write_enum;;
				avail_bridge_types_with_description)
					list_bridge_types | while read type; do
						description="$type"
						case "$type" in
							bri) description="Linux bridge";;
							ovsbr) description="Open vSwitch";;
						esac
						write_enum_item "$type" "$description"
					done
					;;
			esac
			;;
		read)
			case "$in__objects" in
				/)
					;;
				new_name)
					write_string_param "new_name" "$(next_iface_with_cache "$cachedir" br)"
					;;
				type)
					if [ -n "${in_name:-}" ]; then
						write_string_param "type" "$(get_bridge_type $in_name)"
					else
						write_string_param "type" "$default_bridge_type"
					fi
					;;
			esac
			;;
		write)
			init_cache "$in_bridge"

			case "$in__objects" in
				/)
					;;
				rm_bridge)
					remove_host_iface_with_cache "$cachedir" "$in_bridge"
					;;
				add_iface)
					host_add_slaves_with_cache "$cachedir" "$in_bridge" "$in_name"
					update_members "$in_bridge"
					;;
				del_iface)
					clear_member_options "$in_name"
					host_del_slaves_with_cache "$cachedir" "$in_bridge" "$in_name"
					;;
				set_type)
					set_bridge_type "$in_bridge" "$in_type"
					update_members "$in_bridge"
					;;
			esac
			;;
	esac
}

message_loop
