#!/bin/sh -efu

# http://developer.mozilla.org/en/docs/install.rdf
# http://developer.mozilla.org/en/docs/Toolkit_version_format
# http://developer.mozilla.org/en/docs/Enhanced_Extension_Installation
# http://kb.mozillazine.org/Install.rdf

. shell-args
. shell-error
. shell-regexp

show_help() {
	cat <<-EOF
	Usage: $PROG [Options] install.rdf

	Options:

	  -q, --query=STRING      query value in install.rdf info;
	  -t, --target[=STRING]   show product rpm requires;
	  -i, --info              show common info from the install.rdf;
	  -H, --human             show product name instead UID;
	  -v, --verbose           print a message for each action;
	  -V, --version           print program version and exit;
	  -h, --help              show this text and exit.

	Report bugs to gladkov.alexey@gmail.com

EOF
	exit
}

print_version() {
	cat <<EOF
$PROG version $PROG_VERSION
Written by Alexey Gladkov <gladkov.alexey@gmail.com>

Copyright (C) 2008  Alexey Gladkov <gladkov.alexey@gmail.com>
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
EOF
	exit
}


TEMP=`getopt -n $PROG -o H,q:,t::,i,v,V,h -l human,info,target::,query:,verbose,version,help -- "$@"` ||
	show_usage
eval set -- "$TEMP"

param=
mode=
show_human=

while :; do
	case "$1" in
	    -q|--query) shift
		param="$1"
		mode='query'
		;;
	    -t|--target) shift
		param="$1"
		show_human=1
		mode='target'
		;;
	    -i|--info) mode='info'
		;;
	    -H|--human) show_human=1
		;;
	    -v|--verbose) verbose=-v
		;;
	    -V|--version) print_version
		;;
	    -h|--help) show_help
		;;
	    --) shift; break
		;;
	    *) fatal "Unrecognized option: $1"
		;;
	esac
	shift
done

if [ "$#" -eq 0 ]; then
	fatal 'Not enough arguments.'
elif [ "$#" -gt 1 ]; then
	fatal 'Too many arguments.'
fi

installrdf="$(readlink -ev "$1")"
out="$(rapper "$installrdf" 2>/dev/null)"

urn='<urn:mozilla:install-manifest>'
url='http://www.mozilla.org/2004/em-rdf'

targetapp="$(quote_sed_regexp "$urn <$url#targetApplication>")"
app="$(quote_sed_regexp "$urn <$url")"

uidtbl='
{ec8030f7-c20a-464f-9b0e-13a3a9e97384} firefox
{3550f703-e582-4d05-9a08-453d09bdfdc6} tanderbird
{136c295a-4a5a-41cf-bf24-5cee526720d5} nvu
{86c18b42-e466-45a9-ae7a-9b95ba6f5640} mozilla
{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a} seamonkey
{718e30fb-e89b-41dd-9da7-e25a45638b28} sunbird
{3db10fab-e461-4c80-8b97-957ad5f8ea47} netscape
{a463f10c-3994-11da-9945-000d60ca027b} flock
'

uid3tbl='
toolkit@mozilla.org firefox
'

rdf_query() {
	local value
	value="$(quote_sed_regexp "$1")"
	printf '%s\n' "$out" |
		sed -n -e "s@^$app#$value> \"\([^\"]\+\)\" \.@\1@p"
}

human_type() {
	case "$1" in
		2)  echo 'Extension' ;;
		4)  echo 'Theme' ;;
		8)  echo 'Locale' ;;
		32) echo 'Multiple Item Package' ;;
	esac
}

uid2name() {
	local uid="`printf %s "$1" |tr '[A-Z]' '[a-z]'`"
	printf '%s\n' "$uidtbl$uid3tbl" |
		grep "^$uid " |
		cut -d\  -f2
}

name2uid() {
	local name="`printf %s "$1" |tr '[A-Z]' '[a-z]'`"
	printf '%s\n' "$uidtbl" |
		grep " $name\$" |
		cut -d\  -f1
}

rdf_info() {
	printf '%s\n' "$out" |
		sed -n -e "s@^$app#\(id\|version\|type\|name\|description\|creator\|contributor\|developer\|translator\|homepageURL\|updateInfoURL\)> \"\([^\"]\+\)\" \.@\1 \2@p" |
	while read -r param value; do
		if [ "$param" = 'type' ]; then
			[ -n "$show_human" ] &&
				printf '%s\t%s\n' "$param" "`human_type $value`" ||
				printf '%s\t%s\n' "$param" "$value"
		else
			printf '%s\t%s\n' "$param" "$value"
		fi
	done
}

round_min() {
	min_cmp='>='
	min_version=

	local n= p=	
	for p in `printf '%s\n' "$1" | sed -e 's/^\([0-9\.]\+\).*/\1/' -e 's/[.[:space:]]\+/ /g'`; do
		if n="$(printf '%g' "$p" 2>/dev/null)"; then
			[ "$n" -ge 0 ] || n=0
			p="$n"
		fi
		min_version="$min_version.$p"
	done
	min_version="${min_version#\.}"
}

round_max() {
	max_cmp='<='
	max_version=

	local n= p= prev=
	for p in `printf '%s\n' "$1" |tr '.' ' '`; do
		if   printf '%s' "$p" |egrep -qs '^[0-9]+(\+|[A-Za-z]+)'; then
			max_cmp='<'
			n="${p%%'+'*}"
			n="${p%%[A-Za-z]*}"
			max_version="$max_version.$(($n+1))"
			break
		elif printf '%s' "$p" |egrep -qs '^[0-9]+\*'; then
			max_cmp='<'
			n="${p%%'*'*}"
			max_version="$max_version.$(($n+1))"
			break
		elif printf '%s' "$p" |egrep -qs '^(\+|\*|[A-Za-z]+)$'; then
			max_cmp='<'
			max_version="${max_version%\.*}.$(($prev+1))"
			break
		elif n="$(printf '%g' "$p" 2>/dev/null)"; then
			max_version="$max_version.$n"
			prev="$n"
		fi
	done	
	max_version="${max_version#\.}"
}

show_requires() {
	local rc min_version min_cmp max_version max_cmp

	round_min "$min"
	round_max "$max"

	if [ "$min_version" != "$max_version" ]; then
		rc="$(rpmevrcmp "$max_version" "$min_version")"
		
		case "$rc" in
			1)
				verbose "$p minVersion=[$min], maxVersion=[$max]: [$p $min_cmp $min_version], [$p $max_cmp $max_version]"
				printf 'Requires: %s\n' "$p $min_cmp $min_version"
				printf 'Requires: %s\n' "$p $max_cmp $max_version"
				;;
			0)
				verbose "$p minVersion=[$min], maxVersion=[$max]: [$p = $min_version]"
				printf 'Requires: %s\n' "$p = $min_version"
				;;
			*)
				fatal "Error: $p: minVersion=$min_version > maxVersion=$max_version"
				;;			
		esac
	else
		verbose "$p minVersion=[$min], maxVersion=[$max]: [$p = $min_version]"
		printf 'Requires: %s\n' "$p = $min_version"
	fi
}

rdf_target() {
	local uid
	[ -z "${1-}" ] ||
		uid="`name2uid "$1"`"

	printf '%s\n' "$out" |
		sed -n -e "s@^$targetapp \([^ ]\+\) \.@\1@p" |
	while read -r id; do
		id="$(quote_sed_regexp "$id")"

		printf '%s\n' "$out" |
			sed -n -e "s@^$id <$url#\(id\|minVersion\|maxVersion\)> \"\([^\"]\+\)\" \.@\1 \2@p" |
		while read -r param value; do
			case "$param" in
				id)
					id="$value"
					[ -n "$show_human" ] &&
						p="`uid2name "$id"`" ||
						p="$id"
					;;
				minVersion) min="$value" ;;
				maxVersion) max="$value" ;;
			esac

			if [ -n "${p-}" -a -n "${min-}" -a -n "${max-}" ]; then
				if [ -n "$uid" -a "$uid" != "$id" ]; then
					p= id= min= max=
					continue
				fi
				show_requires
				p= id= min= max=
			fi
		done
	done
}

case "$mode" in
	info)   rdf_info ;;
	target) rdf_target "$param" ;;
	query)  rdf_query "$param" ;;
esac

exit
# Add missing requires
rapper -v
rpmevrcmp