#!/bin/bash
set -e

SSHARGS="-t -o ControlPath=~/.ssh/master-$$ -o ControlMaster=auto -o ControlPersist=600"

function error_handler {
	echo "Error in $*"
	if [ -n "$redirect" ]
	then
		cat /tmp/${USER}_unison.log
	fi
}

function sync_dir {
	# looking for .fsignore file
	if [ -f $dir/.fsignore ]
	then
		ignore_txt=".. ignoring"
		ignore=""
		while read line
		do
			ignore_txt="$ignore_txt: $line"
			ignore="$ignore -ignore \"Name $line\""
		done < $dir/.fsignore
		echo $ignore_txt
	fi
	
	#syncing data
	eval "unison -sshargs \"$SSHARGS\" $fat -batch  $ignore $dir ssh://$user/unison_dirs/$dir $redirect" || error_handler "sync_dir/unison" $*
	
	if [ -n "$redirect" ]
	then
		grep "\-\-\-" /tmp/${USER}_unison.log || true
		grep "\[CONFLICT\]" /tmp/${USER}_unison.log || true
		grep "error" /tmp/${USER}_unison.log || true
	fi
}

function force {
	direction=$1
	dir=$2
	user=$3

	# looking for .fsignore file
	if [ -f $dir/.fsignore ]
	then
		ignore="--exclude-from=$dir/.fsignore"
	fi
	if [ "$direction" = "up" ]
	then
		rsync -av --delete $ignore $dir/ ${user}:unison_dirs/$dir/ || error_handler "force/rsync" $*
		sync_dir $*
	elif [ "$direction" = "down" ]
	then
		if eval "rsync -av --delete $ignore ${user}:unison_dirs/$dir/ $dir/ $redirect"
		then
			sync_dir $*
		else
			error_handler "force/rsync" $*
		fi
	else
		echo "invalid direction parameter" >&2
		exit 2
	fi
}

function syncDir {
# $1: base dir
# $2: dir
# $3/4: flags (optional):
#   -r: retry, if base dir is missing
#   -f: dir is a FAT file system
#   -i IGNORE: add ignore pattern. May be present more than once
#   -u [USER@]HOST: ssh-Login

	basedir=$1
	dir=$2
	retry=
	fat=""
	user="wagnertech.de"  # for downward compatibility
	ignore=""
	force=
	redirect="1>/tmp/${USER}_unison.log 2>&1"
	
	while :
	do
		case $3 in
		-r)
			 retry=true
			 shift 1
			 ;;
		-p)
			force=up
			shift 1
			;;
		-d)
			force=down
			shift 1
			;;
		-f)
			 fat="-fat"
			 shift 
			 ;;
		-i) #ignore pattern -> depricated
			echo "Use of -i option in config file is deprecated."
			echo "Use .fsignore file instead (see man page)"
			shift 2
			;;
		-u)
			 user=$4
			 shift 2
			 ;;
		-v)
			 redirect=""
			 shift 1
			 ;;
		--) # End of all options
			 shift
			 break
			 ;;
		-*)
			 echo "Unknown option: $3" >&2
			 exit 1
			 ;;
		*)  # no more options. Stop while loop
			 break
			 ;;
		esac
	done
	
	# looking for base dir
	if [ -d $basedir ]
	then
		pushd $basedir >/dev/null || exit 1
		
		# looking for sync dir
		if [ ! -d $dir ]
		then
			echo "$dir not existing." >&2
			exit 1
		fi

		echo "syncing $dir ..."
		
		# sync .fsignore in advance
		localign=$(test -f $dir/.fsignore; echo $?)
		remoteign=$(ssh $SSHARGS -n $user "ls unison_dirs/$dir/.fsignore" 1>/dev/null 2>&1; echo $?) || error_handler "syncDir/ssh1" $*
		if [ $localign -eq 0 -a $remoteign -eq 0 ]
		then
			if ! eval "unison -sshargs \"$SSHARGS\" $fat -batch $dir/.fsignore ssh://$user/unison_dirs/$dir/.fsignore $redirect"
			then
				echo "syncing .fsignore failed"
				cat /tmp/michael_unison.log
			fi
		elif [ $localign -ne 0 -a $remoteign -eq 0 ]
		then
			scp $user:unison_dirs/$dir/.fsignore $dir/  || error_handler "syncDir/scp" $*
		fi
		
		if [ -n "$force" ]
		then
			force $force $dir $user
			return
		fi

		# check existence of remote directory
		if ! eval ssh $SSHARGS -n $user "ls -d unison_dirs/$dir" $redirect
		then
			echo "ssh problem or remote directory not existing."
			echo "Try a ssh login to $user, then do a 'mFileSync -p'."
			error_handler "syncDir/ssh2" $*
		else
			sync_dir $*
		fi

		echo "done."
		popd >/dev/null
	else
		if [ "$retry" != "true" ]
		then
			echo "$basedir not existing."
			exit 1
		fi
		echo "Waiting for base dir $basedir."
	fi
}


usage="mFileSync <config-file>"
if [ $# -lt 1 ]
then
	echo $usage
	exit 1
fi

if [ -f $1 ]
then
	# process config dir

	while true
	do

		# read config file
		while read line
		do
			if [ ${line:0:1} != "#" ]
			then
				base=${line%%,*}
				tmp=${line%,*}
				dir=${tmp#*,}
				flags=${line##*,}
				syncDir $base $dir $flags
			fi
		done < $1
	
		sleep 60
	done

else
	# process single directory
	syncDir . $*
fi

