#!/bin/sh

# Constants
PRGN="${0##*/}"
LICENSOR_CACHE="${XDG_CACHE_HOME:-$HOME/.cache}/licensor"
# Configuration
: "${LICENSE_REPO_VERSION:=3.17}"
: "${LICENSE_REPO_URL:=https://github.com/spdx/license-list-data/archive/refs/tags/v$LICENSE_REPO_VERSION.tar.gz}"
: "${LICENSE_REPO_PATH:=license-list-data-$LICENSE_REPO_VERSION/template}"
: "${LICENSOR_LICENSE:=MIT}"
: "${LICENSOR_OUTPUT_FILE:=COPYING}"

usage() {
	cat <<EOF
$PRGN: easily provide a license for a project
USAGE:	$PRGN [-h|-l|-L]
	$PRGN -s QUERY
	$PRGN [FLAGS] [OPTIONS] [LICENSE]

FLAGS:
 -h	Display this help and exit.
 -l	List available licenses and exit.
 -L	List available licenses, disregarding cache.
	This flag will re-download the license repo.

 -f	Overwrite existing license.
 -q	Be quiet (don't log anything).
 -z	Fold output to $__width characters (see -w).
 -Z	Disable folding of output.
 -p	Include "optional" license content.
 -P	Don't include "optional" content.

OPTIONS:
 -s QUERY	Search for a license matching QUERY.
		Only license titles are searched.

 -y YEARS	Set copyright date(s) to YEARS.
		Default: \$(date +%Y).
 -a AUTHORS	Set copyright holder(s) to AUTHOR.
		Default: use the first of
			- git config --get user.name
			- getent password \$USER
			- \$USER
 -e EMAILS	Set AUTHOR's EMAIL address.
		Default: \$(git config --get user.email),
		or stay blank.
 -c COPYRIGHT	Set the entire COPYRIGHT string to print.
		By default, it's built from the above information:
		"Copyright (C) <year> <author> <email>".
 -w WIDTH	Fold the output to WIDTH characters.
		Default: $__width.
 -o FILE	Output the fetched license to FILE.
		Default: \$PWD/$LICENSOR_OUTPUT_FILE.

PARAMETERS:
 LICENSE	The license to use.
		Default: $LICENSOR_LICENSE.
EOF
	exit ${1:-0}
}

main() {
	_force=false
	_quiet=false
	_fold=1
	_optional=0
	__width=70
	__output="$LICENSOR_OUTPUT_FILE"
	__year="$(date +%Y)"
	__author="$(guess_author)"
	__email="$(guess_email)"

	while getopts hlLs:fzZpPqy:a:e:o:w:c: opt; do
		case "$opt" in
		# commands
		h) usage ;;
		l) list_licenses && exit || exit $? ;;
		L) list_licenses -f && exit || exit $? ;;
		s) search_licenses "$OPTARG" ;;
		# flags
		f) _force=true ;;
		z) _fold=1 ;;
		Z) _fold=0 ;;
		p) _optional=1 ;;
		P) _optional=0 ;;
		q) _quiet=true ;;
		# options
		y) __year="$OPTARG" ;;
		a) __author="$OPTARG" ;;
		e) __email="$OPTARG" ;;
		o) __output="$OPTARG" ;;
		w) __width="$OPTARG" ;;
		c) __copyright="$OPTARG" ;;
		*) usage 1 ;;
		esac
	done
	shift $((OPTIND - 1))
	__license="${1:-$LICENSOR_LICENSE}"

	if [ -e "$__output" ] && ! $_force; then
		log "File exists: $__output"
		exit 3
	fi

	if [ "x$__output" = x- ]; then
		__output=/dev/stdout
	fi

	if [ -z "$__copyright" ]; then
		__copyright="Copyright (C) $__year $__author <$__email>"
	fi

	license_file="$(get_license "$__license")" || exit $?
	license_convert <"$LICENSOR_CACHE/$license_file.template.txt" \
		"$__copyright" "$_optional" "$_fold" "$__width" >"$__output"
	[ "$__output" != /dev/stdout ] && log "$__license license written to $__output."
}

get_licenses() {
	# Get licenses from cache, or download them
	if ! [ -d "$LICENSOR_CACHE" ] || [ "x$1" = "x-f" ]; then
		log "Downlading licenses from $LICENSE_REPO_URL..."
		mkdir -p "$LICENSOR_CACHE"
		tmpfile="/tmp/licenses.tar.gz"
		if ! [ -f "$tmpfile" ]; then
			curl -o "$tmpfile" -L "$LICENSE_REPO_URL" >/dev/null 2>&1 ||
				return 1
		fi
		log "Extracting licenses to $LICENSOR_CACHE..."
		if tar -C "$LICENSOR_CACHE" \
			-xvf "$tmpfile" --strip-components=2 \
			"$LICENSE_REPO_PATH" >/dev/null 2>&1; then
			rm "$tmpfile"
		else
			return 1
		fi
	fi
}

get_license() {
	list_licenses | grep -iE '^'"$1"'$' || {
		log "Can't find license \"$1\"."
		exit 1
	}
}

list_licenses() {
	get_licenses "$1" || exit 1

	find "$LICENSOR_CACHE" -iname '*.template.txt' |
		sort |
		xargs basename -s .template.txt
}

search_licenses() {
	list_licenses | grep -iE "$1"
	exit $?
}

guess_author() {
	author="$(git config --get user.name)"
	if [ -z "$author" ]; then
		author="$(getent passwd "$USER" | awk -F: '{sub(/,+/,"",$5);print $5}')"
	fi
	if [ -z "$author" ]; then author="$USER"; fi
	put "$author"
}

guess_email() {
	email="$(git config --get user.email)"
	put "$email"
}

put() { printf '%s\n' "$*"; }
log() { $_quiet || put "$PRGN: $*" >&2; }

license_convert() {
	copyright="$1"          # "Copyright (C) 2022 Case Duckworth <acdw@acdw.net>"
	show_optional="${2:-0}" # 0
	fold_output="${3:-1}"   # 1
	fold_width="${4:-70}"   # 70
	awk '
BEGIN {
	foldOutput = '"$fold_output"'
	foldWidth = '"$fold_width"'
	showOptional = '"$show_optional"'
	copyright = "'"$copyright"'"
}
{ buf = buf "\n" $0 }
END {
	split(buf, b, "")
	c = 1
	out = ""
	optstr = ""
	opt = 0
	while (c <= length(b)) {
		if (b[c] == "<" && b[c + 1] == "<") {
			tok = ""
			c += 2
			closed = 0
			while (! closed) {
				tok = tok b[c++]
				if (b[c] == ">" && b[c + 1] == ">") {
					closed++
					c += 2
				}
			}
			if (tok ~ /^beginOptional/) {
				opt = 1
			} else if (tok == "endOptional") {
				if (showOptional) {
					out = out optstr
				}
				opt = 0
				optstr = ""
			} else if (tok ~ /^var/) {
				split(tok, ta, ";")
				name = ""
				original = ""
				for (a in ta) {
					if (ta[a] ~ "^name") {
						match(ta[a], /=".*/)
						name = substr(ta[a], RSTART + 2, RLENGTH - 3)
					} else if (ta[a] ~ "^original") {
						match(ta[a], /=".*/)
						original = substr(ta[a], RSTART + 2, RLENGTH - 3)
					} else if (ta[a] ~ "^match") {
						# currently not used
					}
				}
				if (name == "copyright") {
					out = out copyright
				} else {
					out = out original
				}
			}
			continue
		}
		if (opt) {
			optstr = optstr b[c++]
		} else {
			out = out b[c++]
		}
	}
	# "Fold" the output
	if (foldOutput) {
		split(out, oa, "\n")
		out = ""
		for (l in oa) {
			split(oa[l], la, FS)
			lc = 0
			for (w in la) {
				lc += length(la[w]) + 1
				if (lc >= foldWidth) {
					out = out "\n" la[w] " "
					lc = length(la[w]) + 1
				} else {
					out = out la[w] " "
				}
			}
			out = out "\n"
		}
	}
	print out
}
'
}

main "$@"