#!/bin/bash
# PATTERN_RENAME : Worker Utility by AArexx AAron
# /usr/local/share/worker/scripts/aa.pattern_rename.sh
#
# Script Version 0.2.3  (2013.10.27)
#   0.2.3 -- changed Pth to only append slash if it is not there already
#   0.2.2 -- changed DEFAULT action choices to Preview and Quit
#   0.2.1 -- added "Preview first 50" feature
# For Worker Version 2.7.0 +
# Release License: GPL
# www.gnu.org/copyleft/gpl.html 
#
# written for portability using bash (2) shell
# (Some bash 2 specific function and syntax employed!) 
# plus stock *niX commands (GNU) expr, mv
#  
# NOTE: Requires a Worker Button be set up to collect
# file lists and name patterns from user selections in
# Worker interface; eg
#
#   ## Get Source File Name Pattern
#    script:
#     [push at stack 1] [{Rs{Enter Match *Pattern* for Renaming:}{*{uf}*}}]
#
#   ## Get Output Replacement String
#    script:
#     [push at stack 2] [{Rs{Enter Replacement String for "{top 1}":}{{top 1}}}]
#
#   ## run this script
#     own command [++ Run In Terminal, Wait For Key ]
#     /usr/local/share/worker/scripts/aa.pattern_rename.sh {p} {top 1} {top 2} {uA}
#     [if flag added then: {dir}/scripts/aa.pattern_rename.sh]
#
#   ## Reload the directory listing in Worker
#    Reload
#
#  Script acts on the SELECTED files and links that match the Source Pattern.
#
#  Script confirms directory write permission, checks File (or Link)
#  type and checks for existing named files before "mv" is attempted.
#
#  Script accepts and properly handles most any file name regardless
#  of white space and unusual characters. The only "reserved" char is
#  the "*" in the pattern definitions, which is allowed at the *ends*
#  of the Match and Replacement strings.
# 
#  This is one of my more involved bash script attempts to
#  date. Improvement ideas, code obfuscations, style tips
#  and feature suggestions welcome:  <aaron@pd.org>

#####============================
##=== Set Error Exit routine...
E_bugout()
{
	echo "============================="
	echo $1
	echo "============================="
   exit $E_err
}

#####============================
## Script flags

E_err=1
Prvw=0

#####
# Check args from Worker...
if [ $# -lt 4 ];
then
	E_bugout "User Cancelled"
fi

#####
# Note the Specs
Pth="$1"
if [ $(expr substr "$Pth" ${#Pth} 1) != "/" ]; then
	Pth="$Pth/"
fi
Lenpth=${#Pth}

Patsrc="$2"
Patout="$3"
Argcnt=$#
Lyncnt=$( expr $Argcnt - 3 )

##=====================================
## Validate DIR write permission.

## test
echo "The path is $Pth"
##

if [ ! -w "$Pth" ]
then
	echo "-- No Write Permission:"
	echo "-- $Pth"
  	E_bugout 'Error: Cannot rename without directory write permission.'
fi

#####
# Validate patterns and formatting
Lenps=${#Patsrc}
Lenpo=${#Patout}
Strsrc=$( echo "$Patsrc" | tr -d "[=*=]" )
Strout=$( echo "$Patout" | tr -d "[=*=]" )
Lensrc=${#Strsrc}
Lenout=${#Strout}
Difps=$( expr $Lenps - $Lensrc )
Difpo=$( expr $Lenpo - $Lenout )

if [ "$Strsrc" == "$Strout" ]
then
	echo "- Pattern Strings: \"$Strsrc\" \"$Strout\""
  	E_bugout 'Error: Source and Replace are identical. Nothing to rename.'
fi
	
if [ $Difps -eq 0 ]
then
	echo "- Source Pattern: \"$Patsrc\""
  	E_bugout 'Error: Need at least 1 "*" wild card at *head, tail* or *both*.'
fi

if [ $Difps -gt 2 ] || [ $Difpo -gt 2 ]
then
	echo "- Patterns: \"$Patsrc\" \"$Patout\""
  	E_bugout 'Error: Max is two "*" wild cards at *head, tail* or *both*.'
fi	


##====================================
##=== Define pattern_type function
##=== Pattyp 1=tail*, 2=*head or 3=*both*
pattern_type ()
{
local i=1
local Tst=0
local Typ=0
local Chr=""
until [ $i -gt $2 ] || [ $Tst -eq $3 ]
do
	Chr=$( expr substr "$1" $i 1 )
	if [ "$Chr" == '*' ]
	then
		let Tst=Tst+1
		if [ $i -ne 1 ] && [ $i -ne $2 ]
     	then
			echo "-n" "99"
			return
		fi
	fi  
	let i=i+1
done
Typ=$( expr $i \<= $2 )
Typ=$( expr $Typ + $3 + $Tst - 1 )
echo "-n" $Typ
}
##### =================================

if [ $Lensrc -ne 0 ]
then
	Pattyp=$( pattern_type "$Patsrc" $Lenps $Difps )
	# Align Patout to match Patsrc
	case $Pattyp in
	1)
		Patout="$Strout"'*'
		;;
	2)
		Patout='*'"$Strout"
		;;
	3)
		Patout='*'"$Strout"'*'
		;;
	99)
		echo "- Pattern: \"Patsrc\" "
  		E_bugout 'Error: Wild card "*" must be at *head, tail* or *both*.'
		;;
	esac
else
	Patsrc='*'
	Pattyp=$( pattern_type "$Patout" $Lenpo $Difpo ) 
	if [ $Pattyp -gt 2 ]
	then
		Pattyp=2
		Patout='*'"$Strout"
	fi		
fi

#####
# Show the full renaming plan and
# get user confirmation or PREVIEW

echo "-------------------------------"
echo "- Rename any of $Lyncnt Selected File Entries from path:"
echo "- \"$Pth\""
echo "- which match source pattern" \""$Patsrc"\"
echo "- so that they match pattern" \""$Patout"\"
echo "-------------------------------"

# bash specific form here...
read -p 'CONTINUE, PREVIEW or QUIT? (c/P/q): ' -n1 RSVP ;
echo ""
echo "-------------------------------"

if [ "$RSVP" = "q" ] || [ "$RSVP" = "Q" ] ;
then
	E_bugout "User Chose to Exit."
fi

if [ "$RSVP" != "c" ] && [ "$RSVP" != "C" ] ;
then
	Prvw=1
fi

#####============================
##=== Main ReName Loop ...
Ref=3
Cnt=0
Lyn=""
while [ $Ref -lt $Argcnt ]
do
	let Ref=Ref+1
	Lyn="${!Ref}"
	Fyl=${Lyn:$Lenpth}


	if [ ! -h "$Lyn" ] && [ ! -f "$Lyn" ]
	then
		echo "-- Not File or Link:"
		echo "-- $Lyn"
		continue
	fi	

	if [ $Lensrc -ne 0 ]
	then
		case $Pattyp in
			1)
				Nuname=${Fyl/#"$Strsrc"/"$Strout"}
				;;
			2)
				Nuname=${Fyl/%"$Strsrc"/"$Strout"}
				;;
			3)
				Nuname=${Fyl/"$Strsrc"/"$Strout"}
				;;
		esac
		# Was pattern matched and replaced?
		if [ "$Nuname" == "$Fyl" ]
		then
			echo "-- Skip No Match: $Fyl"
			continue
		fi
	else
		if [ $Pattyp -eq 2 ]
		then
			Nuname="$Fyl""$Strout"
		else
			Nuname="$Strout""$Fyl"
		fi
	fi

	Nufile="$Pth""$Nuname"

	if [ -e "$Nufile" ]
	then
		echo "-- Skip Existing: $Nufile"
		continue
	fi

	let Cnt=Cnt+1
	
	if [ $Prvw -eq 1 ]
	then

		Newfyl[$Cnt]="$Nufile"
		Oldfyl[$Cnt]="$Lyn"

		if [ $Cnt -lt 51 ]
		then
			echo "$Fyl" ' -->> ' "$Nuname"
		else
			if [ $Cnt -eq 51 ]
			then 
				echo "  ... etcetera ...  "
			fi
		fi
	else
		mv '-f' "$Lyn" "$Nufile"
	fi	
done


if [ $Prvw -eq 1 ] ;
then
	echo "-------------------------------"
	read -p 'CONTINUE or QUIT? (c/Q): ' -n1 RSVP ;
	echo ""
	echo "-------------------------------"

	if [ "$RSVP" != "c" ] && [ "$RSVP" != "C" ] ;
	then
		E_bugout "User Chose to Exit."
	fi

	Ref=0
	while [ $Ref -lt $Cnt ]
	do
		let Ref=Ref+1		
		mv '-f' "${Oldfyl[$Ref]}" "${Newfyl[$Ref]}"
	done
fi

#####
# Note the totals, Clean Up and Exit.
echo "-------------------------------"
echo "- Renamed $Cnt of $Lyncnt Files"
echo "-------------------------------"

exit 0

#------------#
# PS:
#
# One Line Multi Rename xxx.c to xxx.cc
# \ls *.C* | sed 's/\(.*\).C\(.*\)/mv & \1.cc\2/' | sh
#
# I know the general functionality of this script could be
# accomplished in one line via perl or sed or awk, but my
# goal was to make the process a tiny bit more friendly,
# comprehensible and intuitive for the not-a-super-guru
# newby-ish Linux users like myself.
# -- aarexx aaron
