#!/bin/ash
# Fatdog Disk Usage
# Copyright (C) James Budiono 2012, 2015
#
# License: GNU GPL Version 3 or later
#
# Note: the bits in Global Inits, which is part of GTK-server bash init code
#       is (C) Peter van Eerten. Everything else is (C) James Budiono
#
#
# 131117 L18L internationalisation

# std localisation stanza
export TEXTDOMAIN=fatdog
. gettext.sh
# performance tweak - use "C" if there is no localisation
! [ -e $TEXTDOMAINDIR/${LANG%.*}/LC_MESSAGES/$TEXTDOMAIN.mo ] &&
! [ -e $TEXTDOMAINDIR/${LANG%_*}/LC_MESSAGES/$TEXTDOMAIN.mo ] && LANG=C

### configuration variables
APPTITLE="$(gettext 'Fatdog64 Disk Usage')"
APPICON="/usr/share/pixmaps/midi-icons/speedometer48.png"
WINDOW_SIZE="400 300"		# in pixels, startup window width x height
TMP_MOUNT_PREFIX=/tmp/fatdog-disk-usage 

### runtime variables 
MAIN_WINDOW= VBOX= MAPPER=

[ $(id -u) -ne 0 ] && exec gtksu "$APPTITLE" "$0" "$@"

#---------------------------------------------------------- Global Inits
### global variables for proper GTK-server
GTK= NULL="NULL"
PIPE=/tmp/gtk.bash.$$
trap 'stop-gtk-server -fifo $PIPE; exit' HUP TERM INT # stop GTK-server in case of an error

### start GTK-server
gtk-server -fifo=$PIPE &
while [ ! -p $PIPE ]; do sleep 1; continue; done

### GTK-server helper functions
# Assignment function
define() { $2 $3 $4 $5 $6 $7 $8 $9; eval $1=\'"$GTK"\'; }

# Communicate with GTK-server
gtk()
{
/bin/echo "$@" > $PIPE
read GTK < $PIPE
}

#---------------------------------------------------------- GUI realization

# add GTK+ API not defined in gtk-server.cfg
add_missing_gtk_api() {
	gtk gtk_server_define gtk_window_new NONE WIDGET 1 INT	# bug fix
}

flush_gtk() {
	gtk gtk_events_pending
	while [ $GTK -eq 1 ]; do
		gtk gtk_main_iteration
		gtk gtk_events_pending
	done	
}

# $1 /dev/dm-x, returns dmdev /dev/mapper/xxx
dm_to_mapper() {
	case $1 in
		/dev/dm-*)
			dmdev=$(ls -l /dev/mapper/* 2> /dev/null | awk -v dmdev=${1##*-} '$6 == dmdev {print $10; exit; }')
			[ "$dmdev" ] || dmdev=$(ls -l /dev/mapper/* 2> /dev/null | awk -v dmdev="/${1##*/}$" '$NF ~ dmdev { print $(NF-2); exit; }')	
			;;
		*)
			dmdev=$1		
			;;
	esac
	#echo $dmdev
}

# $1 /dev/mapper/xxx, dmdev returns /dev/dm-x
mapper_to_dm() {
	case "$1" in
		/dev/mapper/*)
			dmdev=$(ls -l /dev/mapper 2>/dev/null | awk -v dmdev=${1##*/} '$10 == dmdev {print "dm-" $6; exit;}')
			[ "$dmdev" ] || dmdev=$(ls -l /dev/mapper 2>/dev/null | awk -v dmdev=${1##*/} '$(NF-2) == dmdev {sub(/.*\//,"",$NF); print $NF; exit;}')
			;;
		*)
			dmdev=$1		
			;;
	esac
}

# return USAGE
get_disk_usage() {
	Xdialog --title "$(gettext 'Working')" --no-buttons --infobox "$(gettext 'Checking disk usage, please wait ...')" 0 0 1000000 &
	XPID=$!
	local mountpoint count=0 DEVS="" device partitions
	
	# mount all mounted devices, where possible
	while read device; do
		partitions=$(ls -d /sys/block/$device/$device* 2> /dev/null | sed "s_/sys/block/$device/__g" | sort -V)
		[ -z "$partitions" ] && partitions=$device # use the partitions instead of the device, except if there is none
		for dev in $partitions; do
			dm_to_mapper /dev/$dev
			DEVS="$DEVS|^$dmdev "			
			if ! grep -Eqm 1 "^/dev/$dev |^$dmdev " /proc/mounts; then
				case $(guess_fstype /dev/$dev 2> /dev/null) in
					""|unknown|swap) continue ;;
				esac
				count=$(( $count + 1 ))	
				mkdir $TMP_MOUNT_PREFIX-$count 2> /dev/null
				#echo mount -o ro /dev/$dev $TMP_MOUNT_PREFIX-$count
				mount -o ro /dev/$dev $TMP_MOUNT_PREFIX-$count
			fi
		done
	done << EOF
$(ls -d /sys/block/* | sed 's_/sys/block/__g; /^ram[0-9]*/ d; /^nbd[0-9]*/ d; /^loop[0-9]*/ d;' | sort -V)
EOF
	DEVS=${DEVS#|}
	#echo $DEVS
	
	# $1-dev $2-size $3-used $4-free $5-fraction usage $6-percent usage
	USAGE=$(
		{	
			df -h | grep -E "$DEVS" | awk '{print $1, $2, $3, $4 }' | sort -u
			df -k | grep -E "$DEVS" | awk '{print $1, $2, $3, $4 }' | sort -u
		} | sort -V | awk '
				$1 == prev { printf("%.02f %d\n", $3/$2, 100*$3/$2) }
				$1 != prev { printf ("%s ", $0); prev=$1 }
	')
	#echo $USAGE
	
	# unmount all temporary mounts
	until [ $count -le 0 ]; do
		#echo umount $TMP_MOUNT_PREFIX-$count
		umount $TMP_MOUNT_PREFIX-$count
		! mountpoint -q $TMP_MOUNT_PREFIX-$count && rmdir $TMP_MOUNT_PREFIX-$count
		count=$(( $count - 1 ))
	done
	kill $XPID
}

build_content() {
	# create our container
	define VBOX gtk gtk_vbox_new 0 10
	gtk gtk_scrolled_window_add_with_viewport $SCROLL_WINDOW $VBOX	
			
	# then add text and progress bar item for all drives
	echo "$USAGE" | while read -r p; do
		# $1-dev $2-size $3-used $4-free $5-fraction usage $6-percent usage
		set -- $p
		mapper_to_dm $1
		define TEXT gtk gtk_label_new \"\" 
		gtk gtk_label_set_markup_with_mnemonic $TEXT \""<b>$dmdev ($2)</b>    \
<span color=\\\"red\\\"><b>$(gettext 'Used')</b> $3</span>    \
<span color=\\\"blue\\\"><b>$(gettext 'Free')</b> $4</span>"\"
		gtk gtk_misc_set_alignment $TEXT 0 0.5
		#gtk gtk_container_add $VBOX $TEXT
		gtk gtk_box_pack_start $VBOX $TEXT 0 0 0
		
		define BAR gtk gtk_progress_bar_new 
		gtk gtk_progress_bar_set_fraction $BAR $5 
		gtk gtk_progress_bar_set_text $BAR \""$(gettext 'Used'): ${6}%"\" 
		#gtk gtk_container_add $VBOX $BAR
		gtk gtk_box_pack_start $VBOX $BAR 0 0 0
	done	
}

build_frame() {
	# main window
	define MAIN_WINDOW gtk gtk_window_new GTK_WINDOW_TOPLEVEL
	gtk gtk_window_set_icon_from_file $MAIN_WINDOW $APPICON
	gtk gtk_window_set_title $MAIN_WINDOW \"$APPTITLE\"
	gtk gtk_window_set_position $MAIN_WINDOW GTK_WIN_POS_CENTER
	gtk gtk_container_set_border_width $MAIN_WINDOW 10
	gtk gtk_window_set_default_size $MAIN_WINDOW ${WINDOW_SIZE% *} ${WINDOW_SIZE#* }

	# main vbox
	define TOPVBOX gtk gtk_vbox_new 0 10 
	gtk gtk_container_add $MAIN_WINDOW $TOPVBOX
	
	# refresh button
	define REFRESH gtk gtk_button_new_from_stock gtk-refresh
	gtk gtk_box_pack_start $TOPVBOX $REFRESH 0 0 0

	# scroll window
	define SCROLL_WINDOW gtk gtk_scrolled_window_new
	gtk gtk_scrolled_window_set_policy $SCROLL_WINDOW GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC
	gtk gtk_scrolled_window_set_shadow_type $SCROLL_WINDOW GTK_SHADOW_NONE
	gtk gtk_container_add $TOPVBOX $SCROLL_WINDOW

	# connect signals
	gtk gtk_server_connect $MAIN_WINDOW delete-event quit	
	gtk gtk_server_connect $REFRESH clicked refresh	
}

################### main ###################

### gtk-server localisation stanza
gtk gtk_server_define setlocale NONE STRING 2 INT STRING
gtk gtk_server_define bindtextdomain NONE STRING 2 STRING STRING
gtk gtk_server_define textdomain NONE STRING 1 STRING
gtk setlocale 6 \"\" # 6 corresponds to LC_ALL
gtk bindtextdomain $TEXTDOMAIN $TEXTDOMAINDIR
gtk textdomain $TEXTDOMAIN

### init gui
add_missing_gtk_api
gtk gtk_init

### build gui
build_frame
get_disk_usage
build_content

### gtk main loop
gtk gtk_widget_show_all $MAIN_WINDOW
while true; do 
	define EVENT gtk gtk_server_callback wait
	case $EVENT in
		quit) break ;;
		refresh) 
			gtk gtk_widget_destroy $VBOX
			flush_gtk
			get_disk_usage
			build_content
			gtk gtk_widget_show_all $VBOX
			;;
	esac
done
gtk gtk_server_exit 

