#!/bin/bash
#
# File: /usr/local/bin/copybyintermittend
#
# copy files by intermittend (used for copy a dir contents a lot of files)
#
#    Copyright (C) 2013 Ingo Kaesmann
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#
# Script template: 0.3.1
#
# Exit codes:
# 0 = OK
# 1 = Error in parameters
# 2 = Error in configfile, configfile old or not found
# 3 = Library old or not found
# 7 = File exist, but must not exist
# 8 = Error in other file or other file not found
# 99 = Other error
##############################################################################
# SOURCE FILES

. /usr/local/etc/main-inka-sh.conf			# main config
. $LLIBDIR/lib-inka-std.sh				# functions standard
test -e ~/.copybyintermittendrc && . ~/.copybyintermittendrc	# local config
#. /usr/local/etc/x.conf				# global config
#. ~/.$(basename $0)rc					# personal config
##############################################################################
# DECLARATION OF VARIABLES

# STRINGS
pkgname=inka-utilities					# package name
lib_inka_std_sh_needed=1.3.6				# standard lib version
conf_file_needed=0.2.2					# conf file version
#----------------------- end of variables to configure -----------------------
version=$(grep "^VERSION" $PROGREG/$pkgname.inf | cut -f 2)	# version
scriptname=$(basename $0)				# name of script
tempfile=$TEMPDIR/$scriptname.$UID.$$.tmp		# temporary file
infolog="logger -p user.info -t $scriptname --"		# log info messages
errlog="logger -p user.err -t $scriptname -- ERROR:"	# log error messages
debuglog="logger -p user.debug -t $scriptname -- DEBUG:" # log debug messages
debug=no						# debug=yes/no
verbose=""						# verbose=""/-q/-v
opt_found=no						# opt_found=yes/no
opt=""							# option
#------------------------- end of standard variables -------------------------
opt_S1=$Src				# source dir
opt_D1=$Dest				# destination dir
opt_F1=$Nfls				# number of files to copy in one step
opt_S=""
opt_D=""
opt_F=""
slist=~/.copybyintermittend/source.list
dfile=~/.copybyintermittend/destination.dat

# NUMBERS
err=0							# exit code
##############################################################################
# FUNCTIONS

function show_help ()
{
# Show help
# Uses: cat
# Return codes: standard

if [ "$debug" == "yes" ]; then				# debug
	echo "DEBUG show_help: $# $@" >&2
	#$debuglog show_help: $# $@
fi

cat <<EOT

Aufruf: $scriptname OPTION... 
Kopiert in Intervallen eine Anzahl von Dateien.

        -b      Quelldatei-Liste und Zielinfo-Datei erstellen
        -s      Quelldatei-Liste anzeigen
        -i      Zielinfo-Datei anzeigen
        -e      Quelldatei-Liste bearbeiten
        -E      Zielinfo-Datei bearbeiten
        -r      Listen loeschen
        -c      Anzahl noch zu kopierender Dateien anzeigen
        -x      kopieren - Intervall-Modus
        -1      kopieren - nur ein Durchgang
 -S QUELLE      mit -b: QUELLE-Verzeichnis anstatt Voreinstellung benutzen
   -D ZIEL      mit -b: ZIEL-Verzeichnis anstatt Voreinstellung benutzen
 -F ANZAHL      mit -x|-1: ANZAHL Dateien pro Intervall anstatt Voreinstellung
-h, --help      Hilfe anzeigen und beenden
 --version      Versionsinformationen anzeigen und beenden
--show-config   Programmkonfiguration anzeigen und beenden
   --debug      Debug-Modus benutzen
        -q      mit wenigen Fehlermeldungen
        -v      mit vielen Meldungen
Ausser -S, -D, -F, --debug, -q/-v kann nur eine Option angegeben werden.
EOT
return
}
#-----------------------------------------------------------------------------
function show_config ()
{
# Show configuration of program
# Uses: cat, cut, grep
# Return codes: standard

if [ "$debug" == "yes" ]; then				# debug
	echo "DEBUG show_config: $# $@" >&2
	#$debuglog show_config: $# $@
fi

cat <<EOT

Quellverzeichnis:
$Src

Zielverzeichnis:
$Dest

Anzahl der Dateien, die pro Intervall kopiert werden:
$Nfls

Anzahl der Sekunden, zwischen den Intervallen:
$Nsec

Audiodatei, die nach jedem Intervall abgespielt wird:
$Endsnd

EOT

return
}
#-----------------------------------------------------------------------------
function copy_intermittend_proc ()
{
# Build list of all files to copy, then copy files in list intermittend.
# Par1: -x, -1
# Uses: aplay, cat, cp, echo, rm, sleep, tree, wc, Erase_Lines, Read_Lines
# Return codes:
# 0 = OK
# 1 = Parameter wrong
# 7 = File $slist not exist

if [ "$debug" == "yes" ]; then				# debug
	echo "DEBUG main_proc: $# $@" >&2
	#$debuglog main_proc: $# $@
fi

local p1 dest l lastline k
p1="$1"		# can be -x or -1
dest=""		# destination dir
l=0		# number of lines to copy in a step
lastline=0	# number of lines of slist
k=0		# loop counter of wait time

dest=$(cat $dfile)					# read aktual destination dir
if ! [ -e $slist ]; then				# source list missing
	if [ "$verbose" != "-q" ]; then
		echo "Fehler - Quelldatei-Liste existiert nicht!"
	else
		$errlog source file missing
	fi
	return 8
elif ! [ -e $dfile ]; then				# dest info file missing
	if [ "$verbose" != "-q" ]; then
		echo "Fehler - Zielinfo-Datei existiert nicht!"
	else
		$errlog destination info file missing
	fi
	return 8
elif ! [ -d $dest ]; then				# dest dir missing
	if [ "$verbose" != "-q" ]; then
		echo "Fehler - Zielverzeichnis existiert nicht!"
	else
		$errlog destination directory missing
	fi
	return 8
fi

# work slist so long it is not empty
lastline=$(cat $slist | wc -l)				# number of lines in slist
while [ $lastline -gt 0 ]; do
	if [ "$verbose" != -q ]; then			# info about number of all files to cp
		echo "Insgeamt noch $lastline Dateien zu kopieren"
	fi
	if [ $lastline -ge $opt_F1 ]; then		# more or equal number of lines in slist as opt_F1
		l=$opt_F1
	else						# less number of lines in slist as opt_F1
		l=$lastline
	fi
	Read_Lines $slist 1 $l > $tempfile		# cp a part of lines to tempfile
	copy_proc $tempfile $dest			# cp all files in tempfile to destination
	rm $tempfile					# rm tempfile
	Erase_Lines $slist 1 $l > $tempfile		# rm lines from slist
	cp $tempfile $slist
	rm $tempfile
	lastline=$(cat $slist | wc -l)			# number of lines in slist
	if [ $lastline -eq 0 ]; then			# if slist empty, rm it and return
		rm $slist
		return 0
	fi
	if [ "$opt" == "-1" ]; then return 0; fi		# only one step wished, return
	# message for end of step of cp files and wait time
	aplay -q $Endsnd				# output sound and message
	echo
	echo "Strg-C druecken um Programm abzubrechen, ansonsten wird weiterkopiert."
	k=$Nsec
	while [ $k -gt 0 ]; do				# message and count seconds
		echo -e "Naechstes Intervall startet in $k Sekunden  \r\c"
		sleep 1s
		let k--
	done
	echo 'Zeit abgelaufen.                            '
	sleep 1s
done

return 0
}
#-----------------------------------------------------------------------------
function copy_proc ()
{
# Copy listed files to destination.
# Par1: list of files to copy
# Par2: destination dir
# Uses: cp, echo, Read_Lines
# Return codes:
# 0 = OK

if [ "$debug" == "yes" ]; then				# debug
	echo "DEBUG main_proc: $# $@" >&2
	#$debuglog main_proc: $# $@
fi

local line p1 p2 lline n
line=""		# file to cp
p1=$1		# list of files to copy
p2=$2		# destination dir
lline=0		# number of lines in p1
n=0		# loop counter

lline=$(cat $p1 | wc -l)
while [ $n -lt $lline ]; do
	let n++
	echo -e "kopiere Datei $n von $lline \r\c"
	line=$(Read_Lines $p1 $n $n)
	cp -P --parents --preserve=all $line $p2
done

return 0
}
##############################################################################
# PARSE COMMANDLINE

# Read all options with args and all additional args into variables.
# Stop parsing after last parameter.
# Try to do a check on all parameters and version numbers.
# Handle options -h, --show-config and --version directly.
# Exit on error.

if [ "$debug" == "yes" ]; then				# debug
	echo "DEBUG Parse Commandline: $# $@" >&2
	#$debuglog Parse Commandline: $# $@
fi

# get options and options with arguments
while [ "${1:0:1}" == "-" ]; do				# get all options
	case "$1" in
	  -h|--help)	opt=-h;;			# option -h
	  --version)	opt=--v;; 			# option --version
	  --show-config) opt=--s;;			# option --show-config
	  --debug)	debug=yes;;			# option --debug
	  -q|--quiet)	verbose=-q;;			# option -q
	  -v|--verbose)	verbose=-v;;			# option -v
#-------------------------- end of standard options --------------------------
	  -b|-s|-i|-e|-E|-r|-c|-x|-1)	opt="$1";;	# option -b,-s,-i,-e,-E,-r,-c,-x,-1
#	  -z)	opt_z=$1;;				# option -z
	  -S)	opt_S=$1				# option -S + 1 arg
		if [ "$#" -gt 1 ] & [ "${2:0:1}" != "-" ]; then	# par2 is 1.arg of opt_S
			opt_S1=$2
			shift				# shift option
		else					# error no arg
			if [ "$verbose" != -q ]; then
				echo "Fehler - Wert fuer Option $1 fehlt!" >&2
			else
				$errlog arg for option $1 is missing
			fi
			exit 1
		fi;;
	  -D)	opt_D=$1				# option -D + 1 arg
		if [ "$#" -gt 1 ] & [ "${2:0:1}" != "-" ]; then	# par2 is 1.arg of opt_D
			opt_D1=$2
			shift				# shift option
		else					# error no arg
			if [ "$verbose" != -q ]; then
				echo "Fehler - Wert fuer Option $1 fehlt!" >&2
			else
				$errlog arg for option $1 is missing
			fi
			exit 1
		fi;;
	  -F)	opt_F=$1				# option -F + 1 arg
		if [ "$#" -gt 1 ] & [ "${2:0:1}" != "-" ]; then	# par2 is 1.arg of opt_F
			opt_F1=$2
			shift				# shift option
		else					# error no arg
			if [ "$verbose" != -q ]; then
				echo "Fehler - Wert fuer Option $1 fehlt!" >&2
			else
				$errlog arg for option $1 is missing
			fi
			exit 1
		fi;;
	  *)	if [ "$verbose" != "-q" ]; then
			echo "Fehler - Option $1 falsch!" >&2	# error
		else
			$errlog unknown option $1
		fi
		exit 1;;
	esac
	shift			# shift option, or last argument for option
	opt_found=yes
done

# handle standard options -h, --v, --s
case "$opt" in
  -h)	show_help; exit 0;;					# show help
  --v)	echo "$scriptname (${pkgname}) $version"; exit 0;;	# show version
  --s)	show_config; exit 0;;					# show config
esac

# check arguments after options
case "$opt" in
#  -x|-y|-z)	if [ $# -eq 1 ]; then		# parameter count ok
#				arg1="$1"
#				shift
#		else				# error in param count
#			if [ "$verbose" != "-q" ]; then
#				echo "Fehler - Parameteranzahl falsch!" >&2
#			else
#				$errlog parameter count wrong
#			fi
#			exit 1
#		fi;;
  *)	if [ $# -ne 0 ]; then				# error in param count
		if [ "$verbose" != "-q" ]; then
			echo "Fehler - Parameteranzahl falsch!" >&2
		else
			$errlog parameter count
		fi
		exit 1
	fi;;
esac

# check options about give together
case "$opt" in
  -s|-i|-e|-E|-r|-c|-x|-1)	# opt_S and opt_D not allowed together with this opts
	if ! [ -z "$opt_S" ] || ! [ -z "$opt_D" ]; then
		if [ "$verbose" != "-q" ]; then
			echo "Fehler - Optionszusammenstellung falsch!" >&2
		else
			$errlog options wrong
		fi
		exit 1
	fi
esac
case "$opt" in
  -b|-s|-i|-e|-E|-r|-c)		# opt_F not allowed together with this opts
	if ! [ -z "$opt_F" ]; then
		if [ "$verbose" != "-q" ]; then
			echo "Fehler - Optionszusammenstellung falsch!" >&2
		else
			$errlog options wrong
		fi
		exit 1
	fi

esac

# check library
Compare_Version $lib_inka_std_sh_needed $Lib_Inka_Std_Sh_Version
ret=$?						# (ret: 0,1,2,9,127)
if [ $ret -eq 1 ]; then				# needed lib-version higher than installed
	if [ "$verbose" != "-q" ]; then
		echo "Fehler - Programm benoetigt neuere Version von lib-inka-std.sh!" >&2
	else
		$errlog newer version of lib-inka-std.sh needed
	fi
	exit 3
elif [ $ret -eq 9 ] || [ $ret -eq 127 ]; then	# other error (version or lib missing)
	if [ "$verbose" != "-q" ]; then
		echo "Fehler - Versionspruefung von lib-inka-std.sh nicht moeglich!"
	else
		$errlog check of version of lib-inka-std.sh impossible
	fi
	exit 3
else						# check ok, reset $ret
	ret=0
fi

# check version of config files			# set config var!
#Compare_Version $conf_file_needed $Program_Conf
Compare_Version $conf_file_needed $Copybyintermittend_Rc
ret=$?						# (ret: 0,1,2,9)
if [ $ret -eq 1 ]; then				# needed config-version higher than installed
	if [ "$verbose" != "-q" ]; then
		echo "Fehler - $scriptname benoetigt neuere Version der Konfig-datei!" >&2
	else
		$errlog newer version of conf file needed
	fi
	exit 2
elif [ $ret -eq 9 ]; then			# other error (version of conffile missing)
	if [ "$verbose" != "-q" ]; then
		echo "Fehler - Versionspruefung der Konfig-datei von $scriptname nicht moeglich!"
	else
		$errlog check of version of conf file impossible
	fi
	exit 2
else						# check ok, reset $ret
	ret=0
fi
##############################################################################
# MAINPROGRAM

if [ "$debug" == "yes" ]; then				# debug
	echo "DEBUG Main: $# $@" >&2
	#$debuglog Main: $# $@
fi

# Check what to do (initial options and args are removed from cmdline)
case "$opt" in
  -b)							# build source list and dest info file
	if ! [ -e $slist ]; then			#   if slist not exist
		tree -afi --noreport $opt_S1 > $slist
		if [ $? -ne 0 ];then err=99;fi
		echo "$opt_D1" > $dfile
		if [ $? -ne 0 ];then err=99;fi
	else						# slist exist - error msg
		echo "Fehler - Quelldatei-Liste existiert bereits!"
		err=7
	fi;;
  -s)							# show source list
	if [ -e $slist ]; then
		cat $slist
	else
		echo "Fehler - Quelldatei-Liste existiert nicht!"
		err=8
	fi;;
  -i)							# show dest info file
	if [ -e $dfile ]; then
		cat $dfile
	else
		echo "Fehler - Zielinfo-Datei existiert nicht!"
		err=8
	fi;;
  -e)							# editing source list
	if [ -e $slist ]; then
		$EDITOR $slist
	else
		echo "Fehler - Quelldatei-Liste existiert nicht!"
		err=8
	fi;;
  -E)							# editing dest info file
	if [ -e $dfile ]; then
		$EDITOR $dfile
	else
		echo "Fehler - Zielinfo-Datei existiert nicht!"
		err=8
	fi;;
  -r)							# rm source list
	rm -f $slist
	err=$?;;
  -c)							# show number of files to copy
	if [ -e $slist ]; then
		cat $slist | wc -l
	else
		if [ "$verbose" != "-q" ]; then
			echo "Fehler - Quelldatei-Liste existiert nicht!"
		else
			$errlog source file not exist
		fi
		err=7
	fi;;
  -x|-1)						# cp - intermittend | only one step
	copy_intermittend_proc $opt
	err=$?;;
  "")							# no opt given
	if [ "$verbose" != "-q" ]; then
		echo "Fehler - Option fehlt!" >&2
	else
		$errlog option missing
	fi
	err=1;;
esac

exit $err
