#!/bin/bash
# cdd script
# Antonio Maschio 2006 <tbin at libero dot it>
#  
# cd.db is my private cd database in text format, with fields separated 
# by $separator; cdd searches through this database.
#
# Type cdd -h to get the command list
# Type cdd -? to get usage only

# Getting custom data
source custom.data

# Constants
PLAIN=0         # plain view is chaotic but complete
FORMATTED=1     # formatted view is very schematic
ALIGNED=2       # aligned view is suitable for long listings
TRUE=1
FALSE=0
RELEASE=1
MAJOR=0
MINOR=0

#####################################
#      FUNCTIONS 
#####################################

# clean-up function: save temporary search file (if not void) to a "standard" 
# file, if an interrupt prevents a regular process ending
function cleanup
{
        if [ -s $tempfile ]; then
                mv $tempfile $deadsearch
        fi
        exit 1
}


# get a line from standard input and print it (formatted or aligned mode)
function printout()
{
		o=$separator 	# separator is too long, after all!
        while read line; do
                artist=${line%%$o*}; line=${line#*$o}
                album=${line%%$o*}; line=${line#*$o}
                year=${line%%$o*}; line=${line#*$o}
                issue=${line%%$o*}
                notes=${line#*$o}
                # aligned mode 
                if [ $view -eq $ALIGNED ]; then
                        printf '%-20.20s %-25.25s %-4.4s %-5.5s %-18.18s\n' "$artist" "$album" "$year" "$issue" "$notes"
                # table mode
                elif [ $view -eq $FORMATTED ]; then
                        echo
                        echo "Artist:   " $artist
                        echo "Album:    " $album
                        echo -n "Issued in:" $year
                        echo "          CD date:  " $issue
                        echo "Notes:    " $notes
                        echo "------------------------------------------------------------------------------"
                fi       
            
        done
}

function versionf {
	printf "cdd - compact disc database maintainer, bash version %d.%d.%d\n"\
		$RELEASE $MAJOR $MINOR
	printf "Antonio Maschio 2006, <tbin at libero dot it>\n\n"
}
# fast usage function
function fusagef {
        versionf
        echo "Usage: $(basename $0) -[aAcCfFhnorsvxy] [pattern]"
        echo "-o, -s and -x options require a|r|y|i|n as parameter (type $(basename $0) -h for help)"
        echo
}

# help function
function helpf {
        versionf
        echo "Usage: $(basename $0) [OPTIONS]... [pattern]

Options:
  -a            print all voices of the database
  -A            align output in fixed-size colunms (may trim fields)
  -c            report total number of records in the database and exit
  -C            after output, report number of records of the search result
  -f <file>     extract info from <file> rather than from cd.db 
  -F            format output in a fixed scheme (may end in a long listing)
  -h            print this help and exit
  -n            prefix file record number to each line of output 
                (not available for aligned or formatted outputs)
  -o a|r|y|i|n  output only selected field (unifying multiple lines)
  -r            reverse sorting
  -s a|r|y|i|n  sort records according to selected field
  -v            printf version and exit
  -x a|r|y|i|n  search only into selected field
  -y            print a note about issue years rules and exit

Notes:
  -s, -x, -o options must be followed by a selector char for field:
          a   artist name,
          r   record title,
          y   year of original record issue (if found),
          i   CD manufacture year, if found (type $(basename $0) -y for info),
          n   notes about the recordings (if any);
  -o selected output has precedence over -A aligned or -F formatter modes;
  -A and -F modes base their precedence on which is the last option of the two.
  
If [pattern] is NULL, all records will be printed.
"
}

# notes function
function notef 
{
        echo "CD manufacture years may report the following marks:
  yyyy> means that, on the record, no issue year has been found, but 
        nonetheless the record is an exact copy of the original
        (the value is _the same_ of the original production year).
  yyyy] means that, on the record, the issue year has been found, and the 
        record is an exact copy of the original (the value is tipically 
        different from the original production year).        
  yyyy  with no signs, it means some differences arise in the track listing,
        excluding bonus tracks (the value is tipically different from the 
        original production year).        
  v.v.  means \"Various years\" (the record is a collection).
     means \"not available or not yet retrieved data\"
"
}

#####################################
#      MAIN 
#####################################

# exit with no parameter
if [ -z $1 ]; then
        exit 0
fi

# trap INT and TERM signals
trap cleanup INT TERM

# set filenames
tempfile="/tmp/tempfile"
deadsearch="~/dead_search"

# set defaults
sorting=a       # if no sorting is specified, the output is ordered by artist
sorttype=0      # artists numeric sort type
count=0         # number of items (both for c and C options)
view=$PLAIN     # if no view is selected, plain view is active
rev=""          # reversion of sorting is disabled by default
numbers=""      # record numbers output is disabled by default
xsearch=$FALSE  # search in a specific field is disabled by default
osearch=$FALSE  # output of a specific field is disabled by default
viewall=$FALSE  # print all records is disabled by default

# parse options
while getopts ":AacCf:Fhno:rs:x:vy" opt; do
        case $opt in
                a  ) viewall=$TRUE ;;
                A  ) view=$ALIGNED ;;
                c  ) count=$(grep $separator -c $filename)
                     echo "There are $count records in the database"
                     exit 0 ;;
                C  ) count=1 ;;
                f  ) filename=$OPTARG ;;
                F  ) view=$FORMATTED ;;
                h  ) helpf
                     exit 0 ;;
                n  ) numbers="-n"
                     if [ -z $1 ]; then
                             exit 0
                     fi ;;
                o  ) osearch=$TRUE
                     ofield=$OPTARG ;;
                r  ) rev="-r" ;;
                s  ) sorting=$OPTARG ;;
                v  ) versionf
                     exit 0 ;;
                x  ) xsearch=$TRUE
                     xfield=$OPTARG ;;
                y  ) notef
                     exit 0 ;;
                *  ) echo && echo "$(basename $0): unrecognized option"
                     fusagef
                     exit 1 ;;
        esac
done
shift $(( $OPTIND - 1 ))

# set sorting type
case $sorting in
        a  ) sorttype=0 ;;
        r  ) sorttype=1 ;;
        y  ) sorttype=2 ;;
        i  ) sorttype=3 ;;
        n  ) sorttype=4 ;;
esac

# set pattern (with -a option, all lines will be printed)
# note: only the first pattern ($1) is kept, capitalized
if [ $viewall -eq $TRUE ]; then
        pattern=$separator
else
        pattern=$(echo $1 | tr '[a-z]' '[A-Z]')
fi

# generate tempfile with grep
if [ $view -gt $PLAIN ]; then
		# grep with no numbering (formatted views)
	    grep $pattern $filename | sort $rev -f -t$separator +$sorttype > $tempfile
else
        # increment sort column reference if numbering has been chosen
		if [ -n "$numbers" ]; then
                sorttype=$((sorttype+1))
        fi
		# grep with numbering (plain view)
		grep $pattern $numbers $filename | sort $rev -f -t$separator +$sorttype | tr "[:digit:]:" "[:digit:]|" > $tempfile
fi

# perform a search into a field only (-x option),
if [ $xsearch -eq $TRUE ]; then
		# determine which column for awk
		case $xfield in
				a  ) xcol=1 ;;
				r  ) xcol=2 ;;
				y  ) xcol=3 ;;
				i  ) xcol=4 ;;
				n  ) xcol=5 ;;
		esac
		# if numbering was active into grep plain view, increment awk columns
		if [ $view -eq $PLAIN ] && [ -n "$numbers" ]; then
				xcol=$((xcol+1))
		fi
        
        # search with awk the correct lines and save them into another tempfile
        awk -F$separator "\$$xcol ~ /$pattern/ { print \$0 }" $tempfile > ${tempfile}x
        # NOTE: awk treats lower and capital letters differently!
		# rewriting tempfile for lines that match
        rm $tempfile
        mv ${tempfile}x $tempfile
        
fi

# show lines
if [ $osearch -eq $TRUE ]; then
        # determine which field for cut
        case $ofield in
				a  ) ocol=1 ;;
				r  ) ocol=2 ;;
				y  ) ocol=3 ;;
				i  ) ocol=4 ;;
				n  ) ocol=5 ;;
		esac
		# output of a single column (this overrides plain/formatted views)
        cat $tempfile | cut -d$separator -f$ocol | uniq
elif [ $view -eq $PLAIN ]; then
		# plain view with (possible) numbers
        tr $separator '\t' < $tempfile
else
		# formatted views (framed or aligned) don't need any numbering action
        printout < $tempfile
fi

# print count of search records
if [ $count -eq 1 ]; then
        # operate with wc upon tempfile to set count
        dummy=$(wc -l $tempfile)
        count=${dummy#/* /}
        c=$(echo $count | awk -F' ' "{print \$1}")
        if [ $c -eq 1 ]; then
                echo "$c record found."
        else
                echo "$c records found."
        fi
fi
        

# clean
rm $tempfile

# wait processes to end and exit
wait
exit 0
