#!/bin/bash

# shellcheck shell=sh
# shellcheck disable=SC2034 
# shellcheck disable=SC2059
# shellcheck disable=SC1091
# shellcheck disable=SC1090
# shellcheck disable=SC2116

set -e
#set -x

if [ "$(id -u)" -ne 0 ]; then
	echo "$0 needs root: please use sudo."
	exit 1
fi

# Source Auxilium (args parser)
. /usr/share/auxilium/auxilium.sh

auxilium_init "$(basename "$0")" -m 'Displays list of devices and their physical location'

auxilium_add redmine -s r -t opt -m 'Format for redmine'
auxilium_add field -s f -t str -l "id|mount_point|majmin|scsi|vendor|serial|model|firmware|size|description|fo_name" -d "serial" -m 'Field to display under Device Name'
auxilium_add csv -t opt -m 'Return a CSV formatted list of devices (id,kname,mount-point,scsi,majmin,status,vendor,model,serial,firmware,size,description)'
auxilium_add locate -t positional -a -m 'List of device to locate (sdx or BoxXDiskX)'


if [ -f "/usr/share/ferreus-orbit/common.sh" ]; then
	. "/usr/share/ferreus-orbit/common.sh"
elif [ -f "share/common.sh" ] ; then
	. "share/common.sh"
elif [ -f "../share/common.sh" ] ; then
	. "../share/common.sh"
else
	echo "Cannot load common.sh: exiting"
	exit 1
fi

auxilium_parse "$@"

fo_lock

fo_get_name(){
	width="$2"
	locate="False"
	fo_name="$1"
	fullname=$(fo_get_disk_info "${fo_name}" mount_point)
	[ -z "$fullname" ] && fullname=$(fo_get_disk_info "${fo_name}" kname)
	name=$(basename "${fullname}")
	# shellcheck disable=SC2154
	[ "${name}" = "$AUXILIUM_ARG_locate" ] && locate="True"
	mount | grep -q "${fullname}" || fullname="${UNMOUNTED}${fullname}"
	fo_center_align "$width" "$(fo_contain "$AUXILIUM_ARG_locate" "${name}")" "$fullname"
}

fo_get_field(){
	fo_name="$1"
	# shellcheck disable=SC2154
	field="$AUXILIUM_ARG_field"
	width="$2"
	name=$(fo_get_disk_info "${fo_name}" mount_point)
	[ -z "$name" ] && name=$(fo_get_disk_info "${fo_name}" kname)
	shortname=$(basename "${name}" 2>/dev/null)
	f=$(fo_get_disk_info "${fo_name}" "${field}")
	fo_center_align "$width" "$(fo_contain "$AUXILIUM_ARG_locate" "${shortname}")" "$f"
}


fo_display_array(){
	unset header footer
	if [ "$1" = "--header" ]; then
		header='True'
		shift 1
	elif [ "$1" = "--footer" ]; then
		footer='True'
		shift 1
	fi
	fo_name="$1"
	k_name="$2"
	size="$3"
	[ "${size}" = "null" ] && size=0
	model="$4"
	sn="$5"
	fw="$6"
	descr="$7"
	color_begin=''
	color_end=''
	arrow=''
	LEN_ARROW=4
	to_locate=0
	short_fo=$(basename "${fo_name}" 2>/dev/null)
	short_k=$(basename "${k_name}" 2>/dev/null)
	if [ -n "${fo_name}" ] && [ "$(fo_contain "${AUXILIUM_ARG_locate}" "${short_fo}")" -eq 1 ]; then
		to_locate=1
	elif [ -z "${fo_name}" ] && [ -n "${k_name}" ] && [ "$(fo_contain "${AUXILIUM_ARG_locate}" "${short_k}")" -eq 1 ]; then
		to_locate=1
	fi
	if [ "$to_locate" -eq 1 ];then
		if [ -z "$AUXILIUM_ARG_redmine" ]; then
			color_begin="${RED}"
			color_end"=${NORM}"
		else
			arrow='--> '
		fi
	fi
	lentotal=$((LEN_ARROW + LEN_MODEL + LEN_SN + LEN_MOUNT + 60))
	lenm=$((LEN_MOUNT + LEN_ARROW))
	if [ -n "${header}" ]; then
		fo_repeat_char '_' $lentotal;echo
		printf -- "|%-${lenm}s|%-12s|%-15s|%-${LEN_MODEL}s|%-${LEN_SN}s|%-10s|%-15s|\n" "$fo_name" "$k_name" "$size" "$model" "$sn" "$fw" "$descr"
		printf -- "|$(fo_repeat_char '-' ${lenm})|------------|---------------|$(fo_repeat_char '-' "${LEN_MODEL}")|$(fo_repeat_char '-' "${LEN_SN}")|----------|---------------|\n"
	elif [ -n "${footer}" ]; then
		fo_repeat_char '¯' $lentotal;echo
	else
		printf -- "|${color_begin}%-${lenm}s|%-12s|%-15s|%-${LEN_MODEL}s|%-${LEN_SN}s|%-10s|%-15s${color_end}|\n" "${arrow}${fo_name}" "${arrow}${k_name}" "${size}" "$model" "$sn" "$fw" "$descr"
	fi
}

fo_write_disks_infos(){
	did="$1"
	kname="$2"
	mount_point="$3"
	scsi="$4"
	majmi="$5"
	vendor="$6"
	model="$7"
	serial="$8"
	version="$9"
	shift 9
	size="$1"
	descr="$2"
	eval "$(udevadm info -q property --export "${kname}")"
	majmin="${MAJOR}:${MINOR}"
	if fo_check_raid; then
		descr="RAIDx Disk"
		dids=$(fo_get_did)
		dev="/dev/sda"
		[ -e "$kname" ] && dev="$kname"
		for did in $dids; do
			fo_name=$(fo_get_sorted_name "$kname" "$did")
			unset vendor model serial version
			smartctl -i -d megaraid",${did}" "${kname}" 2>/dev/null 1>/tmp/fo_smt
			while IFS=: read -r k_smt v_smt; do
				k_smt=$(echo "$k_smt")
				case $k_smt in
					"Vendor")
						# shellcheck disable=SC2086
						vendor=$(echo ${v_smt})
						;;
					Serial\ [Nn]umber)
						# shellcheck disable=SC2086
						serial=$(echo ${v_smt})
						;;
					"Device Model"|"Product")
						# shellcheck disable=SC2086
						model=$(echo ${v_smt})
						;;
					"Revision"|"Firmware Version")
						# shellcheck disable=SC2086
						version=$(echo ${v_smt})
						;;
					"LU is fully provisioned")
						descr="RAID0 Disk"
						;;
				esac
			done < /tmp/fo_smt
			rm /tmp/fo_smt
			printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n" \
						"${did}" \
						"$kname" \
						"$mount_point" \
						"$fo_name" \
						"$scsi" \
						"$majmin" \
						"$vendor" \
						"$model" \
						"$serial" \
						"$version" \
						"$size" \
						"$descr" >> "$FO_CACHE_DISKS_INFOS"
		done
		unset did kname mount_point scsi majmin size descr
	else
		fo_name=$(fo_get_sorted_name "$kname")
		printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n" \
					"${id}" \
					"$kname" \
					"$mount_point" \
					"$fo_name" \
					"$scsi" \
					"$majmin" \
					"$vendor" \
					"$model" \
					"$serial" \
					"$version" \
					"$size" \
					"$descr" >> "$FO_CACHE_DISKS_INFOS"
	fi
}

fo_load_disks_infos(){
	# File format : did,kname,mountpoint,fo_name,scsi,majmin,
	# vendor,model,serial,version,size,description
	#id,kname,mountpoint,scsi,majmin,status,vendor,model,serial,version,size,description
	fo_use_cache_file "${FO_CACHE_DISKS_INFOS}" && return 0
	fo_use_cache_file "${FO_CACHE_FILE_LSHW}" || lshw -c disk 2>/dev/null > "${FO_CACHE_FILE_LSHW}" || true
	use_fo="$USE_FO_NAME"
	USE_FO_NAME=1
	while IFS=: read -r k v; do
		# shellcheck disable=SC2086
		k=$(echo ${k})
		[ -z "$skip" ] || continue
		case "$k" in
		'*-cdrom')
				[ -n "$id" ] && fo_write_disks_infos "${id}" "$kname" "$mount_point" "$scsi" "$majmin" "$vendor" "$model" "$serial" "$version" "$size" "$descr"
				unset id kname mount_point scsi majmin vendor model serial version size descr
				skip=1
		;;
		'*-disk')
			if [ -z "$v" ]; then
				[ -n "$id" ] && fo_write_disks_infos "${id}" "$kname" "$mount_point" "$scsi" "$majmin" "$vendor" "$model" "$serial" "$version" "$size" "$descr"
				unset id kname mount_point scsi majmin vendor model serial version size descr
				skip=1
			else
				[ -n "$id" ] && fo_write_disks_infos "${id}" "$kname" "$mount_point" "$scsi" "$majmin" "$vendor" "$model" "$serial" "$version" "$size" "$descr"
				unset skip kname id mount_point scsi majmin vendor model serial version size descr
				id="${v}"
			fi
			;;
		'description')
			# shellcheck disable=SC2086
			descr=$(echo ${v})
		;;
		'logical name')
			case "$v" in
			" /dev/"*)
				# shellcheck disable=SC2086
				kname=$(echo ${v})
				;;
			" /srv/node/"*)
				# shellcheck disable=SC2086
				mount_point=$(echo ${v})
				;;
			esac
		;;
		'vendor')
			# shellcheck disable=SC2086
			vendor=$(echo ${v})
		;;
		'product')
			# shellcheck disable=SC2086
			model=$(echo ${v})
		;;
		'bus info')
			scsi=$(echo "${v}" | cut -d@ -f2)
		;;
		'version')
			# shellcheck disable=SC2086
			version=$(echo ${v})
		;;
		'serial')
			# shellcheck disable=SC2086
			serial=$(echo ${v})
		;;
		'size')
			# shellcheck disable=SC2086
			size=$(echo ${v})
		;;
		esac
	done < "${FO_CACHE_FILE_LSHW}"
	[ -z "$skip" ] && fo_write_disks_infos "$id" "$kname" "$mount_point" "$scsi" "$majmin" "$vendor" "$model" "$serial" "$version" "$size" "$descr"
	USE_FO_NAME=$use_fo
}

fo_get_disk_info(){
	field="$2"
	search=",${1},"
	grep "${search}" "${FO_CACHE_DISKS_INFOS}" > /tmp/fo_grp
	while IFS=, read -r id kname mount_point fo_name scsi majmin vendor model serial fw size descr; do
		case "$field" in
		id)
			echo "${id}"
		;;
		majmin)
			echo "${majmin}"
		;;
		scsi)
			echo "${scsi}"
		;;
		vendor)
			echo "${vendor}"
		;;
		serial)
			echo "${serial}"
		;;
		model)
			echo "${model}"
		;;
		firmware)
			echo "${fw}"
		;;
		description)
			echo "${descr}"
		;;
		mount_point)
			echo "${mount_point}"
		;;
		fo_name)
			echo "${fo_name}"
		;;
		kname)
			echo "${kname}"
		;;
		size)
			echo "${size}"
		;;
		esac
	done < /tmp/fo_grp
	rm /tmp/fo_grp
}

main(){
	if [ -z "$AUXILIUM_ARG_sh_completion" ]; then
		fo_init
	fi
	fo_load_disks_infos || true
	if [ -z "$AUXILIUM_ARG_csv" ]; then
		LEN_SN=18
		LEN_MODEL=18
		LEN_MOUNT=15
		while IFS="," read -r id kname mount_point fo_name scsi majmin vendor model serial fw size descr
		do
			[ "${#serial}" -gt "$LEN_SN" ] && LEN_SN=${#serial}
			[ "${#model}" -gt "$LEN_MODEL" ] && LEN_MODEL=${#model}
			[ "${#mount_point}" -gt "$LEN_MOUNT" ] && LEN_MOUNT=${#mount_point}
		done < "$FO_CACHE_DISKS_INFOS"
		fo_display_array --header "Mount point" "Kernel name" Size Model Serial Firmware Description

		sort -t ',' -k 3 -o "$FO_CACHE_DISKS_INFOS" "$FO_CACHE_DISKS_INFOS"
		while IFS="," read -r id kname mount_point fo_name scsi majmin vendor model serial fw size descr
		do
			fo_display_array "$mount_point" "$kname" "$size" "$model" "$serial" "$fw" "$descr"
		done < "$FO_CACHE_DISKS_INFOS"
		fo_display_array --footer;echo
		LEN_FIELD=18
		[ "$AUXILIUM_ARG_field" = "serial" ] && LEN_FIELD=$LEN_SN
		[ "$AUXILIUM_ARG_field" = "model" ] && LEN_FIELD=$LEN_MODEL

		# fo_build_dispo
		underscore=$(fo_repeat_char '_' "${LEN_FIELD}")
		minus=$(fo_repeat_char '-' "${LEN_FIELD}")
		higher=$(fo_repeat_char '¯' "${LEN_FIELD}")
		FO_DISPOSITION=$(printf "${FO_DISPOSITION}"|sed "s%{UNDERSCORE}%${underscore}%g")
		FO_DISPOSITION=$(printf "${FO_DISPOSITION}"|sed "s%{MINUS}%${minus}%g")
		FO_DISPOSITION=$(printf "${FO_DISPOSITION}"|sed "s%{HIGHER}%${higher}%g")
		while IFS="," read -r id kname mount_point fo_name scsi majmin vendor model serial fw size descr
		do
			# [ -z "$mount_point" ] && local fullname=$kname || local fullname=$mount_point
			# local name=$(basename "$fullname")
			n=$(fo_get_name "$fo_name" "${LEN_FIELD}")
			f=$(fo_get_field "$fo_name" "${LEN_FIELD}")
			FO_DISPOSITION=$(printf "${FO_DISPOSITION}"|sed "s%{${fo_name}}%${n}%" 2>/dev/null)
			FO_DISPOSITION=$(printf "${FO_DISPOSITION}"|sed "s%{SN_${fo_name}}%${f}%" 2>/dev/null)
		done < "$FO_CACHE_DISKS_INFOS"
		# final replace {new_line} by \n and @ by \
		# shellcheck disable=SC1003
		FO_DISPOSITION=$(printf "${FO_DISPOSITION}"|sed "s%{new_line}%\n%g"| tr '@' '\\')
		printf "${FO_DISPOSITION}\n"
	else
		cat "$FO_CACHE_DISKS_INFOS"
	fi
}

main