#
# Copyright (C) 2012 Simon Marchi <simon.marchi@polymtl.ca>A
#
# SPDX-License-Identifier: GPL-2.0-only
#

# Generates COMPREPLY with the existing session names
_lttng_complete_sessions() {
	local sessions
	sessions=$(lttng --mi xml list | sed '2 s/xmlns/ignore/g' | xmllint --xpath "//command/output/sessions/session/name" - 2>/dev/null | sed  -e 's/<name>//g' -e $'s/<\/name>/\\n/g')
	COMPREPLY=( $(compgen -W "${sessions}" -- $cur) )
	return
}
#

# Generates COMPREPLY with the available kernel event
_lttng_complete_kernel_events() {
	local kernel_event
	kernel_event=$(lttng --mi xml list -k |sed '2 s/xmlns/ignore/g' | xmllint --xpath "//command/output/domains/domain[./type = 'KERNEL']/events/event/name" - 2>/dev/null | sed -e "s/<name>//g" -e $"s/<\/name>/\\n/g")
	COMPREPLY=( $(compgen -W "${kernel_event}" -- $cur) )
	return
}

# Generates COMPREPLY with the available ust event
_lttng_complete_ust_events() {
	local ust_event
	ust_event=$(lttng --mi xml list -u | sed '2 s/xmlns/ignore/g' | xmllint --xpath "//command/output/domains/domain[./type = 'UST']/pids/pid/events/event/name" - 2>/dev/null | sed -e "s/<name>//g" -e $"s/<\/name>/\\n/g")
	COMPREPLY=( $(compgen -W "${ust_event}" -- $cur) )
	return
}

# Generates COMPREPLY with the available jul event
_lttng_complete_jul_events() {
	local jul_event
	jul_event=$(lttng --mi xml list -j | sed '2 s/xmlns/ignore/g' | xmllint --xpath "//command/output/domains/domain[./type = 'JUL']/pids/pid/events/event/name" - 2>/dev/null | sed -e "s/<name>//g" -e $"s/<\/name>/\\n/g")
	COMPREPLY=( $(compgen -W "${jul_event}" -- $cur) )
	return
}



# Generates COMPREPLY with whatever is in the $options variable.
_lttng_complete_options() {
	COMPREPLY=( $(compgen -W "${options}" -- $cur) )
}

# Generates COMPREPLY with whatever is in the $commands variable.
_lttng_complete_commands() {
	COMPREPLY=( $(compgen -W "${commands}" -- $cur) )
}

_lttng_cmd_addcontext() {
	options=$(lttng add-context --list-options)

	case $prev in
	--session|-s)
		_lttng_complete_sessions
		return
		;;
	--channel|-c)
		return
		;;
	--type|-t)
		return
		;;
	esac

	case $cur in
	-*)
		_lttng_complete_options
		return
		;;
	esac
}

_lttng_cmd_create() {
	options=$(lttng create --list-options)

	case $prev in
	--output|-o)
		_filedir -d
		return
		;;
	esac

	case $cur in
	-*)
		_lttng_complete_options
		return
		;;
	esac
}

_lttng_cmd_destroy() {
	options=$(lttng destroy --list-options)

	case $cur in
	-*)
		_lttng_complete_options
		return
		;;
	*)
		_lttng_complete_sessions
		return
		;;
	esac
}
_lttng_cmd_disablechannel() {
	options=$(lttng disable-channel --list-options)

	case $prev in
	--session|-s)
		_lttng_complete_sessions
		return
		;;
	esac

	case $cur in
	-*)
		_lttng_complete_options
		return
		;;
	esac
}
_lttng_cmd_disableevent() {
	options=$(lttng disable-event --list-options)

	case $prev in
	--session|-s)
		_lttng_complete_sessions
		return
		;;
	--channel|-c)
		return
		;;
	esac

	case $cur in
	-*)
		_lttng_complete_options
		return
		;;
	esac
}

_lttng_cmd_enablechannel() {
	options=$(lttng enable-channel --list-options)

	case $prev in
	--session|-s)
		_lttng_complete_sessions
		return
		;;
	esac

	case $cur in
	-*)
		_lttng_complete_options
		return
		;;
	esac
}

_lttng_cmd_enableevent() {
	options=$(lttng enable-event --list-options)

	case $prev in
	--session|-s)
		_lttng_complete_sessions
		return
		;;
	--channel|-c)
		return
		;;
	--probe)
		return
		;;
	--function)
		return
		;;
	esac


	#Check if we want kernel event completion
	if [[ "$COMP_LINE" == *"-k"* ]]; then
		_lttng_complete_kernel_events
		return
	fi

	#Check if we want ust event completion
	if [[ "$COMP_LINE" == *"-u"* ]]; then
		_lttng_complete_ust_events
		return
	fi

	#Check if we want jul event completion
	if [[ "$COMP_LINE" == *"-j"* ]]; then
		_lttng_complete_jul_events
		return
	fi

	case $cur in
	-*)
		_lttng_complete_options
		return
		;;
	esac

}

_lttng_cmd_list() {
	options=$(lttng list --list-options)

	case $prev in
	--channel|-c)
		return
		;;
	esac

	case $cur in
	-*)
		_lttng_complete_options
		return
		;;
	*)
		_lttng_complete_sessions
		return
	esac
}

_lttng_cmd_setsession() {
	options=$(lttng set-session --list-options)

	case $cur in
	-*)
		_lttng_complete_options
		return
		;;
	*)
		_lttng_complete_sessions
		return
		;;
	esac
}

_lttng_cmd_snapshot() {
	options=$(lttng snapshot --list-options)
	commands=$(lttng snapshot --list-commands)

	_lttng_find_command $((command_found_index + 1))

	if _lttng_cursor_is_after_command; then
		case $prev in
		--session|-s)
			_lttng_complete_sessions
			return
			;;
		esac

		case $cur in
		-*)
			_lttng_complete_options
			;;
		esac
	else
		_lttng_complete_commands
	fi
}

_lttng_cmd_start() {
	options=$(lttng start --list-options)

	case $cur in
	-*)
		_lttng_complete_options
		return
		;;
	*)
		_lttng_complete_sessions
		return
		;;
	esac
}

_lttng_cmd_stop() {
	options=$(lttng stop --list-options)

	case $cur in
	-*)
		_lttng_complete_options
		;;
	*)
		_lttng_complete_sessions
		;;
	esac
}

_lttng_cmd_version() {
	options=$(lttng version --list-options)

	case $cur in
	-*)
		_lttng_complete_options
		;;
	esac
}

_lttng_cmd_view() {
	options=$(lttng view --list-options)

	case $cur in
	-*)
		_lttng_complete_options
		;;
	esac
}



_lttng_before_command() {
	# Check if the previous word should alter the behavior
	case $prev in
	--group|-g)
		COMPREPLY=( $(compgen -g -- $cur) )
		return
		;;
	--sessiond-path)
		_filedir
		return
		;;
	esac

	case $cur in
	-*)
		# If the current word starts with a dash, complete with options
		_lttng_complete_options
		;;
	*)
		# Otherwise complete with commands
		_lttng_complete_commands
		;;
	esac
}

_lttng_after_command() {
	local cmd_name

	cmd_name=_lttng_cmd_${command_found//-/}

	type -t $cmd_name | grep -q 'function' && $cmd_name
}

# Check if the word passed as the first parameter corresponds to a
# command. $command must be set to the list of possible commands.
_lttng_is_command() {
	for command in $commands; do
		if [ "$1" == "$command" ]; then
			return 0
		fi
	done

	return 1
}

# Try to find a command in the current command line. Possible commands
# are passed in $commands.
#
# This function takes an optional parameter that indicates the index
# where to start the search in COMP_WORDS. If omitted, it defaults to 1.
#
# If a command is found, $command_found is filled with the name of the
# command and $command_found_index is set to the index of the command in
# $COMP_WORDS. If no command is found, $command_found is an empty string
# and $command_found_index is set to -1.
_lttng_find_command() {
	start=${1:-1}

	# The text of the found command
	command_found=""

	# The index of the found command in COMP_WORDS
	command_found_index=-1

	for (( i = start ; i < ${#COMP_WORDS[@]} ; i++ )); do
		_lttng_is_command ${COMP_WORDS[$i]}
		if [ $? -eq 0 ]; then
			command_found=${COMP_WORDS[$i]}
			command_found_index=$i
			break
		fi
	done
}

_lttng_cursor_is_after_command() {
	[ -n "$command_found" ] && [ "$COMP_CWORD" -gt "$command_found_index" ]
}

_lttng() {
	local cur prev commands command_found command_found_index

	# Get the current and previous word
	_get_comp_words_by_ref cur prev

	# Get the valid first-level LTTng commands and options
	commands=$(lttng --list-commands)
	options=$(lttng --list-options)

	_lttng_find_command

	# Check if the cursor is before or after the command keyword
	if _lttng_cursor_is_after_command; then
		_lttng_after_command
	else
		_lttng_before_command
	fi
}

complete -F _lttng lttng
