#!/usr/bin/env bash

NAME="cpmvv"
CODENAME="cpmvv"
COPYRIGHT="Copyright (C) 2018 Nathan Shearer"
LICENSE="GNU General Public License 2.0"
VERSION="1.0.0.0"

# \brief Ensures dependencies are present
# \param $@ The dependencies to check for
function cpmvv_check_dependencies
{
	for TOOL in "$@"; do
		if ! type "$TOOL" >/dev/null 2>/dev/null; then
			echo "$CODENAME: \"$TOOL\" is required for this application to work correctly." >&2
			exit
		fi
	done
}

# \brief Displays the help and exits the program
function cpmvv_help
{
	#     01234567890123456789012345678901234567890123456789012345678901234567890123456789
	echo "Description:"
	echo "  Copy or move files and verify file integrity."
	echo
	echo "Usage:"
	echo "  $CODENAME [options] SOURCE... DESTINATION"
	echo
	echo "Options:"
	echo "  --bwlimit RATE"
	echo "    Specify the maximum rsync transfer rate. An optional suffix can be included"
	echo "    for KiB/MiB/etc. Default is 0 which specifies no limit."
	echo "  --diffuzzy-args \"args\""
	echo "    Set the arguments passed to diffuzzy. Default args are empty."
	echo "  -n, --no-clobber"
	echo "    Do not overwrite an existing file."
	echo "  --rm"
	echo "    Remove source if diffuzy does not find any differences. Source is not"
	echo "    removed by default."
	echo "  --rsync-args \"-aH --inplace\""
	echo "    Set the arguments passed to rsync. Default args shown above."
	echo "  -v"
	echo "    Increase the verbosity level by 1."
	echo "  --verbose #"
	echo "    Use more or less verbose output. Valid values are:"
	echo "      0  No output."
	echo "      1  Default. Show differences between the source and destination."
	echo "      2  Show each file source and destination."
	echo "      3  Show verbose diffuzzy and verbose rm."
	echo "      4  Show verbose rsync."
	echo
	echo "Examples:"
	echo "  $CODENAME /mnt/oldserver/* /mnt/newserver"
	echo "  $CODENAME --bwlimit 128KiB /mnt/backup/* /mnt/archive"
	echo
	echo "Version:"
	echo "  $NAME $VERSION"
	echo "  $COPYRIGHT"
	echo "  Licensed under $LICENSE"
}

function cpmvv_main
{
	local SOURCE=("$@")
	local DESTINATION=${SOURCE[-1]}
	unset 'SOURCE[${#SOURCE[@]}-1]'
	
	for FILE in "${SOURCE[@]}"; do
		cpmvv_file "$FILE" "$DESTINATION"
	done
}

function cpmvv_file
{
	local SOURCE="$1"
	local SOURCE_BASENAME=$(basename "$SOURCE")
	local DESTINATION="$2"
	local STATUS=0
	if [ $VERBOSE -ge 2 ]; then
		echo "'$SOURCE' -> '$DESTINATION/$SOURCE_BASENAME'"
	fi
	local SOURCE_TYPE=$(stat -c %F "$SOURCE")
	if [ "$SOURCE_TYPE" = "directory" ]; then
		if ! $PRETEND; then
			rsync $RSYNC_ARGS "$SOURCE" "$DESTINATION"
		fi
		find "$SOURCE" -mindepth 1 -maxdepth 1 -print0 | \
		sort -z | \
		{
			local STATUS=0
			while IFS= read -r -d $'\0' FILE; do
				cpmvv_file "$FILE" "$DESTINATION/$SOURCE_BASENAME"
				if [ $? -ne 0 ]; then
					STATUS=1
				fi
			done
			return $STATUS
		}
		if [ $? -ne 0 ]; then
			STATUS=1
		else
			$REMOVE && rm $RM_ARGS "$SOURCE"
			if [ $? -ne 0 ]; then
				STATUS=1
			fi
		fi
	else
		if ! $PRETEND; then
			rsync $RSYNC_ARGS "$SOURCE" "$DESTINATION"
			diffuzzy $DIFFUZZY_ARGS "$SOURCE" "$DESTINATION/$SOURCE_BASENAME"
			if [ $? -ne 0 ]; then
				STATUS=1
			else
				$REMOVE && rm $RM_ARGS "$SOURCE"
				if [ $? -ne 0 ]; then
					STATUS=1
				fi
			fi
		fi
	fi
	return $STATUS
}

#------------------------------------------------------------------------------
# default configuration

DIFFUZZY_ARGS=""
PRETEND=false
REMOVE=false
RM_ARGS="-fd"
RSYNC_ARGS="-lptgoD --inplace --dirs -H -A -X --numeric-ids"
VERBOSE=1

#------------------------------------------------------------------------------
# command line arguments

if [ $# -eq 0 ]; then
	cpmvv_help
	exit 1
fi
if [ $# -eq 1 ]; then
	case "$1" in
		'-h'|'--help')
			cpmvv_help
			exit
			;;
		*)
			cpmvv_help
			exit 1
			;;
	esac
fi
while [ $# -ne 0 ]; do
	case "$1" in
		'--bwlimit')
			RSYNC_ARGS="$RSYNC_ARGS --bwlimit $2"
			shift 2
			;;
		'--diffuzzy-args')
			DIFFUZZY_ARGS="$2"
			shift 2
			;;
		'-h'|'--help')
			cpmvv_help
			exit
			;;
		"-n"|"--no-clobber")
			RSYNC_ARGS="$RSYNC_ARGS --ignore-existing"
			shift
			;;
		"-p"|"--pretend")
			PRETEND=true
			if [ "$VERBOSE" -eq 0 ]; then
				VERBOSE=1
			fi
			shift
			;;
		'--rm')
			REMOVE=true
			shift
			;;
		'--rsync-args')
			RSYNC_ARGS="$2"
			shift 2
			;;
		'-v')
			VERBOSE=$(($VERBOSE+1))
			shift
			;;
		"--verbose")
			VERBOSE="$2"
			shift 2
			;;
		*)
			break;;
	esac
done
if [ $VERBOSE -ge 3 ]; then
	DIFFUZZY_ARGS="$DIFFUZZY_ARGS -v"
	RM_ARGS="$RM_ARGS -v"
fi
if [ $VERBOSE -ge 4 ]; then
	RSYNC_ARGS="$RSYNC_ARGS --progress"
fi

#------------------------------------------------------------------------------
# prepare environment

cpmvv_check_dependencies diffuzzy rsync

#------------------------------------------------------------------------------
# begin execution

cpmvv_main "$@"
