#!/bin/bash
#
# File: /usr/local/bin/linkfile
#
# Program create links to files (f.e. to show pictures in the same
# directory they are saved in different directories).
#
#    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.5
#
# Exit codes:
# 0 = OK
# 1 = Error in parameters
# 3 = Library old or not found
# 8 = Error in other file or other file not found
# 11= Wrong pattern
# 18= Error in editing
# 99= Other error
##############################################################################
# SOURCE STANDARD FILES

. /usr/local/etc/main-inka-sh.conf			# main config
. $LLIBDIR/lib-inka-std.sh				# functions standard
#. /usr/local/etc/x.conf				# global config
#. ~/.$(basename $0)rc					# personal config
#. ~/.xrc						# 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.0.1					# 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_s=""						# "" or -s (option)

# 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]... -f DATEI | -d WORT
        $scriptname [OPTION]... [-o DATEI] -l WORT | -t PFAD WORT
Erstellen von Links im aktuellen Verzeichnis (interaktiv).

        -f      Links erstellen, dabei Datei-Inhalt benutzen
        -l      Links erstellen, dabei locate benutzen
        -t      Links erstellen, dabei tree benutzen
        -d      einige Links bei Angabe eines Suchworts entfernen
        -s      nur Anzeige der Suchergebnisse, keine weitere Aktion
        -o      anstatt Links erstellen, Auswahl in Datei schreiben
-h, --help      Hilfe anzeigen und beenden
 --version      Versionsinformationen anzeigen und beenden
   --debug      Debug-Modus benutzen
        -q      ohne Meldungen
        -v      mit vielen Meldungen

DATEI           Dateinamen enthaltende Datei
PFAD            Pfad des Verzeichnisses, in dem die Suche starten soll 
WORT            Zeichen, die in den Dateinamen vorkommen sollen

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

var-Erklaerung:
$var

Programm wird zu folgenden Zeiten aufgerufen:
EOT
grep "&&" /etc/cron.d/xyz.cron | cut -f 1

return
}
#-----------------------------------------------------------------------------
function delete_proc ()
{
# Searchs for given pattern in links (or files) in aktual directory, show
# them in editor, ask for confirm the selection, remove the selected links.
# Par1: Pattern to search.
# Uses: cat, echo, grep, rm, wc
# Return codes:
# 0 = OK
# 11= Wrong pattern
# 18= Error in editing

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

local cmd p1 line nol n err
cmd=""		# command to read
p1=$1		# word to search
line=""		# line of selected link
err=0		# return code
n=0		# counter
nol=0		# number of lines

# suche nach links, in denen suchwort ist:
if [ -n "$opt_s" ]; then 				# only show founded links and return
	ls | grep $p1
	return 0
fi

ls | grep $p1 > $tempfile				# save founded links in tempfile
if [ $? -ne 0 ]; then					# no links found
	echo "Keine Links gefunden."
	err=11
fi

$EDITOR $tempfile					# edit founded links
while :; do
	clear
	echo -e "Ausgewaehlte Links entfernen? (o)k | (n)ein: \c"
	read cmd
	case "$cmd" in
	  o)						# ok - remove it
		nol=$(cat $tempfile | wc -l)
		while [ $n -lt $nol ]; do		# work tempfile
			let n++
			line=$(Read_Lines $tempfile $n $n)	# read link
			if [ "$verbose" == "-v" ]; then
				echo "Entferne $line"
			fi
			rm $line			# remove link
			if [ $? -ne 0 ]; then
				err=18
			fi
		done
		break;;
	  n)						# no - do not remove
		break;;
	esac
done

rm -f $tempfile
return $err
}
#-----------------------------------------------------------------------------
function file_proc ()
{
# Read file names from a file and make links to them in aktual directory.
# Par1: File name
# Uses: cat, echo, ln, rm, wc
# Return codes:
# 0 = OK
# 1 = Wrong file name
# 8 = Wrong file name to create link in other file
# 99= Creating link not possible

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

local line p1 nol n err
line=""		# line of file
p1=$1		# file that contains file names to create links
err=0		# return code
n=0		# counter
nol=0		# number of lines in file

if ! [ -e "$p1" ]; then					# file not exist
	if [ "$verbose" != "-q" ]; then
		echo "Fehler - Datei existiert nicht!" >&2
	else
		$errlog file not exist
	fi
	return=1
fi

if [ -n "$opt_s" ]; then				# only show content of file and return
	cat $p1
	return 0
fi

nol=$(cat $p1 | wc -l)					# number of lines
while [ $n -lt $nol ]; do				# work on file
	let n++
	line=$(Read_Lines $p1 $n $n)			# read file to create link
	if [ "$verbose" == "-v" ]; then
		echo "$line"
	fi
	if [ -e $line ]; then				# file exist
		ln -s $line 2> /dev/null		# create link
		if [ $? -ne 0 ]; then			# create link failed
			if [ "$verbose" != "-q" ]; then
				echo "Fehler - Link $line konnte nicht angelegt werden!" >&2
			else
				$errlog create link $line not possible
			fi
			err=99
		fi
	else						# file not exist
		if [ "$verbose" != "-q" ]; then
			echo "Fehler - $line existiert nicht!" >&2
		else
			$errlog $line not exist
		fi
		err=8
	fi
done

#rm -f $tempfile
return $err
}
#-----------------------------------------------------------------------------
function locate_proc ()
{
# Search by using locate for files to create links to them.
# Par1: Pattern to search.
# Uses: cat, clear, echo, ln, locate, rm, wc
# Return codes:
# 0 = OK
# 11= Wrong pattern
# 18= Error in editing
# 99= Creating link not possible

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

local cmd fname line p1 nol n
cmd=""		# command to read
fname=""	# file name for saving
p1=$1		# pattern for searching
line=""		# line of file to create link
err=0		# return code
n=0		# counter
nol=0		# number of lines

locate $p1 > $tempfile					# search for pattern
if [ $? -ne 0 ]; then					# file not found
	if [ "$verbose" != "-q" ]; then
		echo "Keine Datei gefunden." >&2
	else
		$errlog files not exist
	fi
	rm -f $tempfile
	return 11
fi

if [ -n "$opt_s" ]; then				# only show found files
	cat $tempfile
	rm -f $tempfile
	return 0
fi

$EDITOR $tempfile					# edit found files

if [ -n "$opt_o" ]; then				# only save file names in file
	cat $tempfile >> $opt_o1
	rm -f $tempfile
	return 0
fi

while :; do
	clear
	echo -e "Fuer ausgewaehlte Dateien Links erstellen? (o)k | (n)ein: \c"
	echo
	read cmd
	case "$cmd" in
	  o)						# link them - create links
		nol=$(cat $tempfile | wc -l)		# number of lines
		while [ $n -lt $nol ]; do		# work on file
			let n++
			line=$(Read_Lines $tempfile $n $n)	# read file to create link
			if [ "$verbose" == "-v" ]; then
				echo "$line"
			fi
			if [ -e $line ]; then		# file to create link exist
				ln -s $line		# create link
				if [ $? -ne 0 ]; then	# create link failed
					err=99
				fi
			else				# file to create link not exist
				echo "Fehler - $line existiert nicht!" >&2
				err=18
			fi
		done
		break;;
	  n)						# cancel - do nothing
		break;;
	esac
done

rm -f $tempfile
return $err
}
#-----------------------------------------------------------------------------
function tree_proc ()
{
# Search for pattern recursive in a directory by using tree.
# Par1: Path of start directory.
# Par2: Pattern to search.
# Uses: cat, clear, echo, grep, ln, ls, rm, tree, wc
# Return codes:
# 0 = OK
# 1 = Wrong path name
# 11= Wrong pattern
# 18= Error in editing
# 99= Creating link not possible

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

local cmd fname line p1 p2 nol n
cmd=""		# command to read
fname=""	# file name for saving
line=""		# line of file to create link
p1=$1		# path of start directory
p2=$2		# pattern to search
err=0		# return code
n=0		# counter
nol=0		# number of lines


ls $p1 > /dev/null 2>&1					# test start directory exist
if [ $? -ne 0 ]; then					# start directory not exist
	if [ "$verbose" != "-q" ]; then
		echo "Fehler - keine Berechtigung oder Verzeichnis nicht gefunden!" >&2
	else
		$errlog not permitted or directory not found
	fi
	return 1
fi

tree -l -f --noreport -i -n $p1 | grep $p2 > $tempfile	# search for pattern
if [ $? -ne 0 ]; then					# pattern not found
	if [ "$verbose" != "-q" ]; then
		echo "Keine Datei gefunden." >&2
	else
		$errlog files not exist
	fi
	return 11
fi

if [ -n "$opt_s" ]; then				# only show found files
	cat $tempfile
	rm -f $tempfile
	return 0
fi

$EDITOR $tempfile					# edit found files

if [ -n "$opt_o" ]; then				# only save file names in file
	cat $tempfile >> $opt_o1
	rm -f $tempfile
	return 0
fi

while :; do
	clear
	echo -e "Fuer ausgewaehlte Dateien Links erstellen? (o)k | (n)ein: \c"
	echo
	read cmd
	case "$cmd" in
	  o)						# link them - create links
		nol=$(cat $tempfile | wc -l)		# number of lines
		while [ $n -lt $nol ]; do		# work on file
			let n++
			line=$(Read_Lines $tempfile $n $n)	# read file to create link
			if [ "$verbose" == "-v" ]; then
				echo "$line"
			fi
			if [ -e $line ]; then		# file to create link exist
				ln -s $line		# create link
				if [ $? -ne 0 ]; then	# create link failed
					err=99
				fi
			else				# file to create link not exist
				echo "Fehler - $line existiert nicht!" >&2
				err=18
			fi
		done
		break;;
	  n)						# cancel - do nothing
		break;;
	esac
done

rm -f $tempfile
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 --------------------------
	  -d|-f|-l|-t)	opt="$1";;			# option -d,-f,-l,-t
	  -s)	opt_s=$1;;				# option -s
	  -o)	opt_o=$1				# option -o + 1 arg
		if [ "$#" -gt 1 ] & [ "${2:0:1}" != "-" ]; then	# par2 is 1.arg of opt_z
			opt_o1=$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
  -d|-f|-l)	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;;
  -t)	if [ $# -eq 2 ]; then		# parameter count ok
				arg1="$1"
				arg2="$2"
				shift 2
		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 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 $Program_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
  -d)							# opt -d
	delete_proc $arg1
	err=$?;;
  -f)							# opt -f
	file_proc $arg1
	err=$?;;
  -l)							# opt -l
	locate_proc $arg1
	err=$?;;
  -t)							# opt -t
	tree_proc $arg1 $arg2
	err=$?;;
  "")							# no opt given
	if [ "$verbose" != "-q" ]; then
		echo "Fehler - Option fehlt!" >&2
	else
		$errlog option missing
	fi
	err=1;;
esac

exit $err
