#!/bin/bash
#
# File: /usr/local/bin/numfiles
#
# Change file names to names they have number at first.
#
#    Copyright (C) 2015  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.6
#
# Exit codes:
# 0 = OK
# 1 = Error in parameters
# 2 = Error in configfile, configfile old or not found
# 3 = Library old or not found
# 8 = Error in other file or other file not found
# 9 = Other file exist
# 10= Wished number of cifers to small
# 20= Another instance of program is running
# 99= Other error
##############################################################################
# SOURCE STANDARD FILES

. /usr/local/etc/main-inka-sh.conf			# main config
. $LLIBDIR/lib-inka-std.sh				# functions standard
#test -e /usr/local/etc/x.conf && . /usr/local/etc/x.conf	# global config
#test -e ~/.$(basename $0)rc && . ~/.$(basename $0)rc	# personal config
test -e ~/.numfilesrc && . ~/.numfilesrc		# local 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.4.0					# 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 -------------------------
destdir="$Destdir"	# destination dir
opt_d=""		# wish destination dir
opt_d1=""		# wished destination dir
opt_e=""		# wish manuel sorting
opt_n=""		# wish number of cifer
opt_s=""		# wish start number

# NUMBERS
err=0			# exit code
opt_n1=0		# wished number of cifer
opt_s1=0		# wished start of numbering
startnum=1		# start of numbering
##############################################################################
# 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]... QUELLDATEI... | -f LISTE
Stellt den Namen von Dateien eine fortlaufende Nummer voran und
verschiebt sie in ein anderes (konfiguriertes) Verzeichnis

  -f LISTE      Datei, die Namen der umzubenennenden Dateien enthaelt,
                  wird nicht automatisch sortiert
-d VERZEICHNIS  Verzeichniss, in das die Dateien verschoben werden
-n STELLEN      Anzahl Stellen der Nummern in den neuen Dateinamen
 -s NUMMER      Start der Nummerierung
        -e      Laden der Dateiliste in Editor zur manuellen Nachsortierung
-h, --help      Hilfe anzeigen und beenden
--show-config   Programmkonfiguration anzeigen und beenden
 --version      Versionsinformationen anzeigen und beenden
   --debug      Debug-Modus benutzen
        -q      ohne Meldungen
        -v      mit vielen Meldungen

Es werden die Namen der Dateien im aktuellen Verzeichnis geaendert.
Ohne -d werden Dateien in das konfigurierte Verzeichnis verschoben.

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

Verzeichnis, in das Dateien bei fehlender Angabe von -d verschoben werden:
$destdir

EOT

return
}

#-----------------------------------------------------------------------------
function main_proc ()
{
# Move files to another directory and write continous number at beginning of
# file names.
# Par1: file names separated by whitespace.
# Uses: cat, clear, cp, echo, mv, rm, test, wc
# Return codes:
# 0 = OK
# 1 = Parameter error
# 8 = Directory not found
# 9 = Directory content regular files

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


local cmd line tfile1 tfile2 wfiles err l lline m n
cmd=""			# comand for reading keyboard
line=""			# line (file name) in list
tfile1=$tempfile-1.tmp	# temporary file
tfile2=$tempfile-2.tmp	# temporary file
wfiles=""		# maybe content files in destdir
err=0			# error code
l=0			# continous number with leading 0
lline=0			# number of lines in file list
m=0			# continous number
n=0			# loop counter

if [ -n "$opt_d" ]; then				# opt_d exist
	destdir=$opt_d1					# change destdir
fi
if ! [ -d $destdir ]; then				# directory destdir not exist - return
	if [ "$verbose" != -q ]; then
		echo "Fehler - Verzeichnis $destdir existiert nicht!" >&2
	else
		$errlog directory $destdir not exist
	fi
	return 8
fi
wfiles=$(ls $destdir)					# read destdir
for i in $wfiles; do
	if [ -f "$destdir/$i" ]; then			# test in destir for regular files
		err=1
	fi
done
if [ $err -ne 0 ]; then					# regular files exist - give message and return
	if [ "$verbose" != -q ]; then
		echo "Fehler - Verzeichnis $destdir enthaelt regulaere Dateien!" >&2
	else
		$errlog directory $destdir content regular files
	fi
	return 9
fi

if [ "$opt" == "-f" ]; then				# -f given, use extern created list
	cp $1 $tfile1
else							# -f not given, create list
	cp /dev/null $tfile1
	for i in "$@"; do				# make list
		echo "$i" >> $tfile1
	done
	cat $tfile1 | sort > $tfile2			# sort list
	cp $tfile2 $tfile1				#  and write back
fi

lline=$(cat $tfile1 | wc -l)				# number of files

cifnum=${#lline}					# min. no. of cifers
if [ -n "$opt_n" ]; then				# opt_n given (wished no. of cifers)
	if ! [ $opt_n1 -gt 0 ] 2> /dev/null; then
		if [ "$verbose" != -q ]; then
			echo "Fehler - Wert fuer Option -n fehlt!" >&2
		else
			$errlog arg for option -n is missing
		fi
		rm -f $tempfile $tfile1 $tfile2
		return 1
	fi
	if [ $opt_n1 -lt $cifnum ]; then		# opt_n1 smaller then needed cifer numbers - return
		if [ "$verbose" != -q ]; then
			echo "Fehler - Gewuenschte Stellenanzahl zu klein!" >&2
		else
			$errlog wished cifer numbers to small
		fi
		rm -f $tempfile $tfile1 $tfile2
		return 10
	elif [ $opt_n1 -gt $cifnum ]; then		# opt_n1 bigger then needed cifer numbers - take it
		cifnum=$opt_n1
	fi
fi

if [ -n "$opt_s" ]; then				# opt_s given (wished start number) - take it
	if ! [ $opt_s1 -gt 0 ] 2> /dev/null; then
		if [ "$verbose" != -q ]; then
			echo "Fehler - Wert fuer Option -s fehlt!" >&2
		else
			$errlog arg for option -s is missing
		fi
		rm -f $tempfile $tfile1 $tfile2
		return 1
	fi
	startnum=$opt_s1
fi

if [ -n "$opt_e" ]; then				# opt_e given (wished manuel sorting)
	$EDITOR $tfile1
	while [ "$cmd" != "o" ] && [ "$cmd" != "n" ]; do
		clear
		echo -e "Sollen Dateien in der angegebenen Reihenfolge benummert werden? (o)k, (n)ein \c"
		read cmd
	done
	if [ "$cmd" == "n" ]; then				# work not wished - return
		echo "Durch Benutzer abgebrochen!"
		rm -f $tempfile $tfile1 $tfile2
		return 0
	fi
fi

m=$startnum
let m--
while [ $n -lt $lline ]; do
	let n++
	let m++
	Trim_Number_0 $cifnum $m
	Pop_Stack l
	line=$(Read_Lines $tfile1 $n $n)		# read line
	if [ "$verbose" != -q ]; then
		echo "${l}_$line"
	fi
	mv $line $destdir/${l}_$line			# move file and number it
done

rm -f $tempfile $tfile1 $tfile2
return
}
##############################################################################
# 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, -C and -V 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 --------------------------
	  -f)	opt="$1";;				# option -f
	  -e)	opt_e=$1;;				# option -e
	  -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;;
	  -n)	opt_n=$1				# option -n + 1 arg
		if [ "$#" -gt 1 ] & [ "${2:0:1}" != "-" ]; then	# par2 is 1.arg of opt_n
			opt_n1=$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;;
	  -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;;
	  *)	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
  -f)	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			
		arg1=$@
	else					# error in param count
		if [ "$verbose" != "-q" ]; then
			echo "Fehler - Parameteranzahl falsch!" >&2
		else
			$errlog parameter count
		fi
		exit 1
	fi;;
esac
##############################################################################
# CHECK LIBRARY AND CONFIG

# 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 and program name!
#Compare_Version $conf_file_needed $Program_Conf
Compare_Version $conf_file_needed $Numfiles_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 conf file 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
  *)							# no opt given
	main_proc $arg1
	err=$?;;
esac

exit $err
