#!/bin/bash
# sortBracketed.sh
# Version 1.5.3 (June 6 2011)
# Author: Vincent Tassy <photo@tassy.net>
# Site: http://linuxdarkroom.tassy.net
# This script is released under a CC-GNU GPL License

# A bash script to sort bracketed images in specific folders

# Changelog
#
# Version 1.0
#	first public release
# Version 1.1
#       - changed header to user /bin/bash instead of /bin/sh to avoid problems on ubuntu
# Version 1.2
#	- Changed tag used to determine Exposure Compensation in the bracket
#	- Added a second way to determine if AEB has been used to support images produced by a Canon 50D - Thanks to TJantunen for providing the test pictures.
#	- Added support for Canon 50D
# Version 1.3
#	- Added test on camera make and model to test the appropriate parameters
#	- Refactored the testing of parameters
#	- Added support for Nikon NEF files
#	- Added support for Nikon D90
#	- Added support for Nikon D50
# Version 1.4
#	- Added support for KDE based invocation with kdialog progress indicator
# Version 1.5
#	- fixed rm error when not using kdialog
#	- Added support for Canon 7D
# Version 1.5.1
#	- Added support for Canon 60D
# Version 1.5.2
#	- Added support for Canon 550D (Thanks to Daniel Siegel)
# Version 1.5.3
#	- Added support for Canon 5D MKII (Thanks to Jonas Karlsson)


SELF=`basename $0`	# Ouselve
DIR=""
DRYRUN=N		# no dry run by default
USEKDE=0		# command line invocation by default
VERBOSE=0		# not too verbose by default
QUIET=0			# not too quiet either ;-)
DIRPREFIX="HDR"		# created directories prefix, i.e. HDR1, HDR2, ...
SupportedFileTypes=("JPG" "CR2" "NEF")

# function processFileType() takes file extension as a param (case insensitive)
processFileType() {
	extension=$1
	if [ $USEKDE = 1 ]; then
		qdbus $dbusRef setLabelText "Processing $extension files"
		echo "Analyzing $extension files" >>$tmpfile
	fi
	if [ $QUIET = 0 ]; then
		echo "Analyzing $extension files"
	fi
	declare -a bracketed
	for file in `find $DIR -maxdepth 1 -type f -iname "*.$extension" -print | sort`; do # find files with the right extension in specified directory and sort names
		isbracketed="NO"
		make=`exiftool -n -S -EXIF:Make $file | cut -d ' ' -f 2-` # retrieve make from EXIF
		camera=`exiftool -n -S -EXIF:Model $file | cut -d ' ' -f 2-` # retrieve camera model from EXIF
		if [ $VERBOSE = 1 ]; then
			echo Camera make: $make        Camera model: $camera
		fi
		if [ $VERBOSE = 1 ]; then
			echo -n "Checking if file `basename $file` is bracketed ... "
		fi
		if [ "$make" = "NIKON CORPORATION" -a "$camera" = "NIKON D90" ] || [ "$make" = "NIKON CORPORATION" -a "$camera" = "NIKON D50" ]; then
			shootingMode=`exiftool -n -S -MakerNotes:ShootingMode $file | awk '{print $2}'` # retrieve shooting mode from MakerNotes
			let "shootingMode = $shootingMode & 16"
			if [ $shootingMode = 16 ]; then
				bracketed=( "${bracketed[@]}" $file )
				isbracketed="YES"
			fi
		elif [ "$make" = "Canon" -a "$camera" = "Canon EOS 50D" ] || [ "$make" = "Canon" -a "$camera" = "Canon EOS 7D" ] || [ "$make" = "Canon" -a "$camera" = "Canon EOS 60D" ] || [ "$make" = "Canon" -a "$camera" = "Canon EOS 550D" ] || [ "$make" = "Canon" -a "$camera" = "Canon EOS 5D Mark II" ]; then
			bracketMode=`exiftool -n -S -MakerNotes:BracketMode $file | awk '{print $2}'` # retrieve Bracket mode from MakerNotes -- Added because EXIF:ExposureMode didn't work on files from Canon 50D
			if [ $bracketMode = 1 ]; then
				bracketed=( "${bracketed[@]}" $file )
				isbracketed="YES"
			fi
		elif [ "$make" = "Canon" -a "$camera" = "Canon EOS 400D DIGITAL" ]; then
			expoMode=`exiftool -n -S -EXIF:ExposureMode $file | awk '{print $2}'` # retrieve exposure mode from EXIF
			if [ $expoMode = 2 ]; then # 2 is the value for Auto Bracketed, file should be looked at
				bracketed=( "${bracketed[@]}" $file )
				isbracketed="YES"
			fi
		fi
		if [ $VERBOSE = 1 ]; then
			echo $isbracketed
		fi
	done
	element_count=${#bracketed[@]}
	if [ $VERBOSE = 1 ]; then
		echo "$element_count bracketed images found"
	fi
	index=0 # counter for looping in the array of files
	while [ $index -lt  $(($element_count-2)) ];do # have to have at least 3 files left
		image_number1=`basename ${bracketed[$index]} | sed "s/\..*//g" | sed "s/[^0-9]//g"` # retrieve image name without path and without extension
		# make sure the file number sequence is continuous and that they belong to the same bracket
		image_number2=`basename ${bracketed[$(($index+1))]} | sed "s/\..*//g" | sed "s/[^0-9]//g"`
		image_number3=`basename ${bracketed[$(($index+2))]} | sed "s/\..*//g" | sed "s/[^0-9]//g"`
		if [ $VERBOSE = 1 ]; then
			echo -n "Checking if images $image_number1 $image_number2 $image_number3 go together ... "
		fi
		if [ $((10#$image_number2)) = $((10#$image_number1+1)) ] && [ $((10#$image_number3)) = $((10#$image_number1+2)) ]; then
			if [ "$make" = "NIKON CORPORATION" -a "$camera" = "NIKON D90" ] || [ "$make" = "NIKON CORPORATION" -a "$camera" = "NIKON D50" ]; then
				exp_comp1=`exiftool -n -S -MakerNotes:ExposureBracketValue ${bracketed[$index]} | awk '{print $2}'`
				exp_comp2=`exiftool -n -S -MakerNotes:ExposureBracketValue ${bracketed[$(($index+1))]} | awk '{print $2}'`
				exp_comp3=`exiftool -n -S -MakerNotes:ExposureBracketValue ${bracketed[$(($index+2))]} | awk '{print $2}'`
			elif [ "$make" = "Canon" -a "$camera" = "Canon EOS 50D" ] || [ "$make" = "Canon" -a "$camera" = "Canon EOS 400D DIGITAL" ] || [ "$make" = "Canon" -a "$camera" = "Canon EOS 7D" ] || [ "$make" = "Canon" -a "$camera" = "Canon EOS 60D" ] || [ "$make" = "Canon" -a "$camera" = "Canon EOS 550D" ] || [ "$make" = "Canon" -a "$camera" = "Canon EOS 5D Mark II" ]; then
				exp_comp1=`exiftool -n -S -MakerNotes:AEBBracketValue ${bracketed[$index]} | awk '{print $2}'`
				exp_comp2=`exiftool -n -S -MakerNotes:AEBBracketValue ${bracketed[$(($index+1))]} | awk '{print $2}'`
				exp_comp3=`exiftool -n -S -MakerNotes:AEBBracketValue ${bracketed[$(($index+2))]} | awk '{print $2}'`
			fi
			if [ `echo "($exp_comp1 - $exp_comp2) == ($exp_comp3 - $exp_comp1)" | bc -q` = 1 ]; then
				if [ $VERBOSE = 1 ]; then
					echo "YES"
				fi
				let "folderIndex = $folderIndex + 1" # increment folder index
				currentDir=$DIR/$DIRPREFIX$folderIndex
				if [ $QUIET = 0 ]; then
					echo "`basename ${bracketed[$index]}`  \\"
					echo "`basename ${bracketed[$(($index+1))]}`   |> $DIRPREFIX$folderIndex - Exposures: $exp_comp2 $exp_comp1 $exp_comp3"
					echo "`basename ${bracketed[$(($index+2))]}`  /"
					echo
				fi
				if [ $USEKDE = 1 ]; then
					echo "`basename ${bracketed[$index]}`  \\" >>$tmpfile
					echo "`basename ${bracketed[$(($index+1))]}`   |> $DIRPREFIX$folderIndex - Exposures: $exp_comp2 $exp_comp1 $exp_comp3" >>$tmpfile
					echo "`basename ${bracketed[$(($index+2))]}`  /" >>$tmpfile
					echo
				fi
				if [ "$DRYRUN" = "N" ]; then # if for real
					mkdir $currentDir # create directory
					mv ${bracketed[$index]} ${bracketed[$(($index+1))]} ${bracketed[$(($index+2))]} $currentDir # move files inside
				fi
				let "index = $index + 3"
			else
				if [ $VERBOSE = 1 ]; then
					echo "NO"
				fi
				let "index = $index + 1"
			fi
		else
			if [ $VERBOSE = 1 ]; then
				echo "NO"
			fi
			let "index = $index + 1"
		fi
	done
}

displayHelp() {
	echo "Sort bracketed images into dedicated folders."
	echo
	echo "Usage: $SELF [OPTION] DIR"
	echo -e "  --quiet   -q\tQuiet"
	echo -e "  --verbose -v\tVerbose"
	echo -e "  --dry-run -d\tAnalyze but don't actually move the files"
	echo -e "  --kde       \tDisplay progress with kdialog"
	echo
	echo "Report bugs to <photo@tassy.net>"
}

# test params
while [ "$1" != "" ]; do
	case "$1" in
		"--help" | "-h")
			displayHelp
			exit
			;;
		"--kde")
			USEKDE=1
			;;
		"--dry-run" | "-d")
			DRYRUN=Y
			;;
		"--quiet" | "-q")
			QUIET=1
			;;
		"--verbose" | "-v")
			VERBOSE=1
			;;
		*)
			DIR=$1
			;;
	esac
	shift
done
if [ -z $DIR ]; then
	displayHelp
	exit
fi
#If verbose and quiet are passed as params, quiet takes precedence
if [ $QUIET = 1 ]; then
	VERBOSE=0
fi
if [ $USEKDE = 1 ]; then
	VERBOSE=0
	QUIET=1
	tmpfile=`mktemp`
	dbusRef=`kdialog --title "Sort Bracketed Images" --progressbar "Initialising" ${#SupportedFileTypes[@]}`
fi
if [ ! -d "$DIR" ]; then
	echo "$DIR is not a valid directory"
	displayHelp
	exit
fi
DIR=$(cd "$DIR" && pwd) #transform to absolute path

# check if there are already foldrers matching our pattern so we start our counter above
folderIndex=`find $DIR -maxdepth 1 -name HDR* -type d -exec basename {} \; | tail -n 1 | sed "s/[^0-9]//g"`
if [ -z $folderIndex ]; then 
	folderIndex=0
fi
let "count = 1"
for filetype in ${SupportedFileTypes[@]}; do
	processFileType $filetype
	if [ $USEKDE = 1 ]; then
		qdbus $dbusRef Set "" "value" $count;
	fi
	let "count = $count + 1"
done
if [ $USEKDE = 1 ]; then
	qdbus $dbusRef close
	kdialog --title "Sort Bracketed Images" --textbox $tmpfile
	rm $tmpfile
fi
