#!/bin/bash

#########################################
# Name: undup
#
# Summary: remove duplicate lines from 
#          a text file
#
# Description: brain-dead sort and remove
# duplicates
#
# Author: kheadley
#
# Copyright MBARI 2014
#
#########################################

#########################################
# Script configuration defaults
# casual users should not need to change
# anything below this section
#########################################
description="Sort and remove duplicate text records"

#################################
# Script variable initialization
#################################
VERBOSE="FALSE"
unset INFILE
unset TEST_MODE

#################################
# Function Definitions
#################################
#################################
# name: sigTrap
# description: signal trap callback
# will interrupt 
# args: none
#################################
sigTrap(){
    exit 0;
}

#################################
# name: printUsage
# description: print use message
# args: none
#################################
printUsage(){
    echo
    echo "Description: $description"
    echo
    echo "usage: `basename $0` [options]"
	echo "Options:"
    echo "-f <file> : verbose output          [$VERBOSE]"
    echo "-t        : test, show duplicates, don't change"
    echo "-v        : verbose output          [$VERBOSE]"
    echo "-h        : print use message"
    echo ""
    echo
}

########################################
# name: vout
# description: print verbose message to stderr
# args:
#     msg: message
########################################
vout(){
    if [ "$VERBOSE" == "TRUE" ]
    then
	echo "$1" >&2
    fi
}

########################################
# name: imsg
# description: echos with indent
# args:
#     msg: message
#  indent: indent level
########################################
imsg(){
  OIFS=$IFS
  IFS=""
  msg_pad="                                        "
  let "msg_indent=${1}"
  shift
  all="${@}"
  printf "%s%s\n" ${msg_pad:0:${msg_indent}} ${all}
  IFS=$OIFS
}

########################################
# name: msg
# description: echos with default indent
# args:
#     msg: message
########################################
msg(){
 imsg $MSG_INDENT "${*}"
}

########################################
# name: exitError
# description: print use message to stderr
# args:
#     msg:        error message
#     returnCode: exit status to return
########################################
exitError(){
    echo >&2
    echo "`basename $0`: error - $1" >&2
    echo >&2
    exit $2
}

########################################
# name: processCmdLine
# description: do command line processsing
# args:
#     args:       positional paramters
#     returnCode: none
########################################
processCmdLine(){
	OPTIND=1
	vout "`basename $0` all args[$*]"

	while getopts f:htv Option
	do
		vout "processing $Option[$OPTARG]"
		case $Option in
			f ) INFILE=$OPTARG
			;;
			t ) TEST_MODE="Y"
			;;
			v ) VERBOSE="TRUE"
			;;
			h)printUsage
				exit 0
			;;
			*) exit 0 # getopts outputs error message
			;;
		esac
	done
}

##########################
# Script main entry point
##########################


# Argument processing
# Accepts arguments from command line 
# or pipe/file redirect
# Comand line settings override config
# file settings

if [ -t 0 ]
then
	if [ "$#" -eq 0 ];then
		printUsage
		exit -1
	else
		processCmdLine $*
		let "i=$OPTIND-1"
		#while [ "${i}" -gt 0  ]
		#do
		#	shift
		#	let "i-=1"
		#done
	fi
else	
	declare -a cline_args
	let "i=1"
	while [ "$i" -le "$#" ]
	do
		cline_args[$i]="${@:$i:1}"
		let "i+=1"
	done

  	declare -a arg_array
	let "z=0"
	while read line ; do
		IFS=" " read opt val <<< $line
		if [ "${opt}" ] && [[ $opt != \#* ]]
		then
		    vout "opt $opt $z"
			arg_array[$z]=${opt}
			let "z+=1"
			if [ "${val}" ]
			then
				vout "val $val $z"
				arg_array[$z]=${val}
				let "z+=1"
			fi
		else 
			vout "skipping line $line"
		fi
	done
	
	# set default delimiter to 
	# newline for parsing/setting
	# positional parameters
	# [must restore after processing]
	IFSO=$IFS
	IFS=`echo` 
	set - ${arg_array[*]}
	
	# apply config file settings
	processCmdLine ${arg_array[*]}

	# apply command line settings
	# (override config file options)
	set - ${cline_args[*]}	
	processCmdLine ${cline_args[*]}

	# restore default delimiter
	IFS=$IFSO
	
	#let "i=$OPTIND-1"
	#while [ "${i}" -gt 0  ]
	#do
	#shift
	#let "i-=1"
	#done		
fi

vout "X_ARG   : $X_ARG"
vout "VERBOSE : $VERBOSE"
vout "INFILE  : $INFILE"
vout "TEST    : $TEST_MODE"

# call sigTrap on INT,TERM or EXIT
# trap sigTrap INT TERM EXIT

# reset trapped signals
# trap - INT TERM EXIT

if [ ! -f "${INFILE}" ]
then
	exitError "Can't find file [$INFILE]" -1
fi

last_line=""
#let "line_num=0"

# sort the file (puts identical lines together)
sort $INFILE > $INFILE.sort

# read sorted file
while read line
do
	#let "line_num+=1"
	
	if [ "${TEST_MODE}" ]
	then
		if [ "$line" == "$last_line" ]
		then
			# show duplicate
			#echo "$line_num: $line"
			echo "$line"
		fi
	else
		# if this line doesn't match last
		if [ "$line" != "$last_line" ]
		then
			# write it to new file
			echo $line >> $INFILE.new
		fi 
	fi
	# make this the last line read
	last_line=$line
done < $INFILE.sort

# clean up
if [ -f "$INFILE.sort" ]
then
	rm $INFILE.sort
fi

if [ -f "$INFILE.new" ] && [ ! "${TEST_MODE}" ]
then
	mv $INFILE $INFILE.orig
	mv $INFILE.new $INFILE
fi
