# Rename files to strip all special characters.
# All files by default.
# Usage: name [FILES]
function name() {
	local IFS=$'\n'
	local targets=("${@}")
	local count=0
	local total=${#}
	local failed=0

	# all targets except hidden by default.
	if [[ "${targets}" = "" ]]; then
		targets=([^.]*)
		total=${#targets[@]}
	fi

	# process.
	for target in "${targets[@]}"; do
		# increment counter.
		((count++))

		# parse new name.
		local ext=""
		local name="${target}"

		# ext only for files.
		if [[ -f "${target}" ]]; then
			ext=".${target##*.}"
			name="${target%.*}"
		fi
		
		# Files w/o extension support.
		[[ "${ext#.}" = "${name}" ]] && ext=""

		# Get new name.
		local new_name=$(parse_simplify "${name}")${ext,,}

		# status line.
		local status="[${count}/${total}] ${target} -> ${new_name}"
		echo -e "${status}"

		# check if same name.
		[[ "${target}" = "${new_name}" ]] && continue

		# check if target name already exists.
		if [[ -f "${new_name}" ]]; then
			echo -e "${color_bred}${status}: already exists!${color_default}"
			((failed++))
		fi

		# rename target.
		mv -- "${target}" "${new_name}"

		if [[ ${?} != 0 ]]; then
			echo -e "${color_bred}${status}: Failed.${color_default}"
			((failed++))
		fi
	done

	if [[ ${failed} != 0 ]]; then
		echo -e "${color_bred}Failed: ${failed}.${color_default}"
		false
	fi
}

# Rename all files to their hashes while keeping extensions.
# All files by default.
# Usage: name_hash [FILES]
function name_hash() {
	local IFS=$'\n'
	local targets=("${@}")
	local count=0
	local total=${#}
	local failed=0

	# all files except hidden by default.
	if [[ "${targets}" = "" ]]; then
		targets=($(ls --classify | grep -v /\$))
		total=${#targets[@]}
	fi

	# process.
	for target in "${targets[@]}"; do
		# increment count.
		((count++))

		# extract extension.
		local extension="${target##*.}"
		if [[ "${extension}" = "${target}" ]]; then
			extension=""
		else
			extension=".${extension}"
		fi

		# hash the new name.
		local hash=$(pv "${target}" | sha1sum | cut -d\	-f1)
		new_name="${hash,,}${extension,,}"
		
		# prepare status.
		local status="[${count}/${total}] ${target} -> ${new_name}"

		# check if same name.
		if [[ "${target}" = "${new_name}" ]]; then
			# echo -e "${color_green}${status}: No change.${color_default}"
			echo -e "${status}"
			continue
		fi

		# show change.
		echo -e "${status}"

		# rename target.
		mv -- "${target}" "${new_name}"
		
		if [[ ${?} != 0 ]]; then
			echo -e "${color_bred}${status}: Failed.${color_default}"
			((failed++))
		fi
	done

	if [[ ${failed} != 0 ]]; then
		echo -e "${color_bred}Failed: ${failed}.${color_default}"
		false
	fi
}

# Check hashes for previously renamed files.
# All files by default.
# Usage: name_hash_check [FILES]
function name_hash_check() {
	local IFS=$'\n'
	local targets=("${@}")
	local total=${#}
	local count=0
	local failed=0

	# all targets by default.
	if [[ "${targets}" = "" ]]; then
		targets=($(ls --classify | grep -v /\$))
		total=${#targets[@]}
	fi

	# process.
	for target in "${targets[@]}"; do
		# increment count.
		((count++))

		# status info.
		local status="[${count}/${total}] ${target}"

		echo -e "${status}"

		# extract hashes.
		local stored="${target%%.*}"
		local actual=$(pv "${target}" | sha1sum | cut -d\	-f1)

		# compare hashes.
		if [[ "${stored}" != "${actual}" ]]; then
			echo -e "${color_bred}${status}: Failed.${color_default}"
			((failed++))
		fi
	done

	if [[ ${failed} != 0 ]]; then
		echo -e "${color_bred}Failed: ${failed}.${color_default}"
		false
	fi
}

# Rename files for Jellyfin series, i.e. Episode S01E01.mkv
# All files by default.
# Usage: name_series <SEASON> [FILES]
function name_series() {
	local IFS=$'\n'
	local season="${1}"
	local targets=("${@:2}")
	local count=0
	local episode=0
	local total=${#}
	local failed=0

	# error when no season number specified.
	if [[ "${season}" = "" ]]; then
		echo "usage: name_series <SEASON> [FILES]"
		return 2
	fi

	# all targets by default.
	if [[ "${targets}" = "" ]]; then
		targets=($(ls --classify | grep -v /\$))
		total=${#targets[@]}
	fi

	# process.
	for target in "${targets[@]}"; do
		# increment episode number.
		((count++))
		((episode++))

		# extract new name.
		local new_name="Episode S${season}E$(printf %02d ${episode}).${target##*.}"

		# prepare status.
		local status="[${count}/${total}] ${target} -> ${new_name}"
		echo -e "${status}"

		# Warning on no change.
		[[ "${target}" = "${new_name}" ]] && continue

		# rename target.
		mv -- "${target}" "${new_name}"
		
		if [[ ${?} != 0 ]]; then
			echo -e "${color_bred}${status}: Failed.${color_default}"
			((failed++))
		fi
	done

	if [[ ${failed} != 0 ]]; then
		echo -e "${color_bred}Failed: ${failed}.${color_default}"
		false
	fi
}

# Rename files for Kavita manga format.
# All files by default.
# Usage: name_manga <SEASON> [FILES]
function name_manga() {
	local IFS=$'\n'
	local season="${1}"
	local targets=("${@:2}")
	local count=0
	local episode=0
	local total=${#}
	local manga="${PWD##*/}"
	local failed=0

	# error when no season number specified.
	if [[ "${season}" = "" ]]; then
		echo "usage: name_manga <SEASON> [FILES]"
		return 2
	fi

	# all targets by default.
	if [[ "${targets}" = "" ]]; then
		targets=($(ls --classify | grep -v /\$))
		total=${#targets[@]}
	fi

	# process.
	for target in "${targets[@]}"; do
		# increment episode number.
		((count++))
		((episode++))

		# extract new name.
		local new_name="${manga} Vol.${season} Ch.${episode}.${target##*.}"

		# prepare status.
		local status="[${count}/${total}] ${target} -> ${new_name}"
		echo -e "${status}"

		# Warning on no change.
		[[ "${target}" = "${new_name}" ]] && continue

		# rename target.
		mv -- "${target}" "${new_name}"
		
		if [[ ${?} != 0 ]]; then
			echo -e "${color_bred}${status}: Failed.${color_default}"
			((failed++))
		fi
	done

	if [[ ${failed} != 0 ]]; then
		echo -e "${color_bred}Failed: ${failed}.${color_default}"
		false
	fi
}

# Rename files with new extension.
# All files by default.
# Usage: name_ext <EXTENSION> [FILES]
function name_ext() {
	local IFS=$'\n'
	local extension="${1}"
	local targets=("${@:2}")
	local count=0
	local total=$((${#}-1))
	local failed=0

	# error when no new extension specified.
	if [[ "${extension}" = "" ]]; then
		help name_ext
		return 2
	fi

	# all targets by default.
	if [[ "${targets}" = "" ]]; then
		targets=($(ls --classify | grep -v /\$))
		total=${#targets[@]}
	fi
	
	# process.
	for target in "${targets[@]}"; do
		# increment count.
		((count++))

		# extract new name.
		local new_name="${target%.*}"."${extension}"

		# Prepare status.
		local status="[${count}/${total}] ${target} -> ${new_name}"
		echo -e "${status}"

		# Warning on no change.
		[[ "${target}" = "${new_name}" ]] && continue

		# rename target.
		mv -- "${target}" "${new_name}"
		
		if [[ ${?} != 0 ]]; then
			echo -e "${color_bred}${status}: Failed.${color_default}"
			((failed++))
		fi
	done

	if [[ ${failed} != 0 ]]; then
		echo -e "${color_bred}Failed: ${failed}.${color_default}"
		false
	fi
}

# Change file name prefix.
# All matching files by default.
# Usage: name_prefix <OLD> <NEW> [FILES]
function name_prefix() {
	local IFS=$'\n'
	local old="${1}"
	local new="${2}"
	local targets=("${@:3}")
	local count=0
	local total=$((${#}-2))
	local failed=0

	# All matching targets by default.
	if [[ "${targets}" = "" ]]; then
		targets=(${old}*)
		total=${#targets[@]}
	fi
	
	# Process.
	for target in "${targets[@]}"; do
		# Increment counter.
		((count++))

		# Create new name.
		local new_name="${new}${target#$old}"

		# Prepare status.
		local status="[${count}/${total}] ${target} -> ${new_name}"
		echo -e "${status}"

		# Warning on no change.
		[[ "${target}" = "${new_name}" ]] && continue
		
		# Rename.
		mv -- "${target}" "${new_name}"
		
		if [[ ${?} != 0 ]]; then
			echo -e "${color_bred}${status}: Failed.${color_default}"
			((failed++))
		fi
	done

	if [[ ${failed} != 0 ]]; then
		echo -e "${color_bred}Failed: ${failed}.${color_default}"
		false
	fi
}

# Change file name postfix.
# All matching files by default.
# Usage: name_postfix <OLD> <NEW> [FILES]
function name_postfix() {
	local IFS=$'\n'
	local old="${1}"
	local new="${2}"
	local targets=("${@:3}")
	local count=0
	local total=$((${#}-2))
	local failed=0

	# All matching targets by default.
	if [[ "${targets}" = "" ]]; then
		targets=(*${old})
		total=${#targets[@]}
	fi
	
	# Process.
	for target in "${targets[@]}"; do
		# Increment counter.
		((count++))

		# Create new name.
		local new_name="${target%$old}${new}"

		# Prepare status.
		local status="[${count}/${total}] ${target} -> ${new_name}"
		echo -e "${status}"

		# Warning on no change.
		[[ "${target}" = "${new_name}" ]] && continue
		
		# Rename.
		mv -- "${target}" "${new_name}"
		
		if [[ ${?} != 0 ]]; then
			echo -e "${color_bred}${status}: Failed.${color_default}"
			((failed++))
		fi
	done

	if [[ ${failed} != 0 ]]; then
		echo -e "${color_bred}Failed: ${failed}.${color_default}"
		false
	fi
}

# Replace part of the name.
# All matching files by default.
# Usage: name_replace <OLD> <NEW> [FILES]
function name_replace() {
	local IFS=$'\n'
	local old="${1}"
	local new="${2}"
	local targets=("${@:3}")
	local count=0
	local total=$((${#}-2))
	local failed=0

	# All matching targets by default.
	if [[ "${targets}" = "" ]]; then
		targets=(*${old}*)
		total=${#targets[@]}
	fi
	
	# Process.
	for target in "${targets[@]}"; do
		# Increment counter.
		((count++))

		# Create new name.
		local new_name="${target//$old/$new}"

		# Prepare status.
		local status="[${count}/${total}] ${target} -> ${new_name}"
		echo -e "${status}"

		# Warning on no change.
		[[ "${target}" = "${new_name}" ]] && continue
		
		# Rename.
		mv -- "${target}" "${new_name}"
		
		if [[ ${?} != 0 ]]; then
			echo -e "${color_bred}${status}: Failed.${color_default}"
			((failed++))
		fi
	done

	if [[ ${failed} != 0 ]]; then
		echo -e "${color_bred}Failed: ${failed}.${color_default}"
		false
	fi
}