#!/bin/ksh
# Phone number script
# Author: Perette Barella
# Copyright 1993 - 2018 Devious Fish.  All rights reserved.
VERSION='$Id: pn 45 2018-11-16 17:11:51Z perette $'

readonly arg0=$(basename "$0")
NAMEOPTS=""
USAGE="ef:g"
[[ $(getopts '[-][12:abc]' flag --abc; print -- 0$flag) == "012" ]] &&
        NAMEOPTS="-a $arg0" &&
        USAGE=$'
[-1?'$VERSION$']
[+NAME?\f?\f - Phone/Address book lookup and editor]
[+DESCRIPTION?\b\f?\f\b looks up phone numbers and addresses, and
allows editing the address book.]
[+?Within the document, entries are delineated by blank lines--effectively,
paragraphs.  Searches are case-blind and performed against entire paragraphs,
so criteria need not match on a single line.]
[+?If \bgoobook\b(1) is installed, that address book is searched as well.]
[+?Although \b\f?\f\b was written for address books, it can be repurposed
for other paragraph-oriented or similar files using the \v-g\v and \v-f\v
options and shell \balias\b command to select other files.]
[f:file?Specify the address book file.]:[file]
[e:edit?Edit the address book using the editor specified by the
\vVISUAL\v or \vEDITOR\v environment variables, or \bvi\b(1) by default.]
[g:no-goobook?Suppress searching of \bgoobook\b.]
[+FILES?]
{
  [+phonelist.txt?The default address book.]
}
[+ENVIRONMENT?]
{
  [+PHONELIST?An alternate path for the address book.  Overriden by \v-f\v.]
}
[+SEE ALSO?\bcloud\b(1), \bgoobook\b(1)]

search terms ...

[-author?Perette Barella <perette@deviousfish.com>
'

# Search for text
# Author: Perette Barella
# Copyright 2018 Devious Fish.  All rights reserved.
# $Id: search_for_text 40 2018-10-01 19:56:46Z perette $


# Check if 0 or more patterns match a line of text.
# Comparison is case insensitive.
# $1 - The text to match against.
# $2.. - The patterns.  May be shell patterns.
# Return: 0 if all patterns match, non-0 otherwise.
function text_search_line_matches_all {
	typeset -l pattern line="$1"
	shift
	for pattern
	do
		eval "[[ \$line != *\${pattern}* ]]" && return 1
	done
	return 0
}


# Search input stream for matching text.  Matches are sent to stdout.
# Comparison is case insensitive
# $1 - Method to search by: 'line' or 'paragraph'
# $2 - Paragraph separator.  If "", blank/all whitespace lines.
# $3.. - The patterns.
function search_for_text {
	typeset -r mode="$1" divider="$2"
	shift 2
	if [[ "$mode" != line && "$mode" != paragraph ]]
	then
		print -- "cloud_extract: Assertion: $mode: Must be 'line' or 'paragraph'." 1>&2
		exit 1
	fi

	integer -r paragraph_max=1024
	integer lines=0
	typeset match=false completed=false out
	typeset -a paragraph
	while ! $completed
	do
		IFS="" read -r line || completed=true
		if [[ "$mode" = "paragraph" ]]
		then
			if $completed ||
			   [[ $divider == "" && $line == *([ \t]) ]] ||
			   eval "[[ \"\$divider\" != \"\" && \"\$line\" == \$divider ]]"
			then
				if (( lines > 0 )) &&
				   text_search_line_matches_all "${paragraph[*]}" "$@"
				then
					for out in "${paragraph[@]}"
					do
						print -r -- "$out"
					done
					match=true
				fi
				# Reset the paragraph buffer
				unset paragraph
				typeset -a paragraph
				lines=0
			fi
			if (( lines < paragraph_max ))
			then
				paragraph[lines++]="$line"
			fi
		elif ! $completed && text_search_line_matches_all "$line" "$@"
		then
			match=true
			print -r -- "$line"
		fi
	done
	$match && return 0
	return 255
}



function query_goobook {
	# 99% of the time, the first search criteria is a name that
	# we could pass to goobook.  But if it's part of a street
	# address, goobook misses it.  Trick it into giving us everything,
	# and do the search ourselves.
	goobook dquery "" | search_for_text paragraph "-------*" "$@"
	return $?
}

file=${PHONELIST:-phonelist.txt}
typeset edit=false goobook=true

while getopts $NAMEOPTS "$USAGE" option
do
	case "$option" in
	    f)
		file="$OPTARG"
		;;
	    e)
		edit=true
		;;
	    g)
		goobook=false
		;;
	esac
done
shift $((OPTIND - 1))

if $edit
then
	cloud edit -t -f "$file"
elif [ $# -eq 0 ]
then
	OPTIND=0
	getopts $NAMEOPTS "$USAGE" option --short
	exit 1
else
	# If goobook is installed, query that too.
	if $goobook && whence -q goobook
	then
		query_goobook "$@"
	fi
	cloud extract -f -p "$file" "$@"
fi
exit $?

