#!/usr/bin/env bash

define() { IFS='\n' read -r -d '' ${1} || true ; }

myname="${0##*/}"

define pod <<"=cut"

=head1 NAME

    xlate - translate CLI front-end for App::Greple::xlate module

=head1 SYNOPSIS

    xlate [ options ] -t lang file [ greple options ]
	-h   help
	-v   show version
	-d   debug
	-n   dry-run
	-a   use API
	-c   just check translation area
	-r   refresh cache
	-s   silent mode
	-e # translation engine (default "deepl")
	-p # pattern to determine translation area
	-w # wrap line by # width
	-o # output format (default "xtxt", or "cm", "ifdef")
	-f # from lang (ignored)
	-t # to lang (required, no default)
	-m # max length per API call
	-l # show library files (XLATE.mk, xlate.el)
        --   terminate option parsing

    Make options
	-M   run make
	-n   dry-run

    Docker options
	-G   mount git top-level directory
	-B   run in non-interactive (batch) mode
	-R   mount read-only
	-E # specify environment variable to be inherited
	-I # specify altanative docker image (default: tecolicom/xlate:version)
#	-T # specify docker image version
#	-L   use the latest version
#	-V # specify directory to be mounted (default: current directory)

	-D * run xlate on the container with the rest parameters
	-C * run following command on the container, or run shell
	N.B. -D/-C terminates option parsing

    Control Files:
	*.LANG    translation languates
	*.FORMAT  translation foramt (xtxt, cm, ifdef)
	*.ENGINE  translation engine (deepl or gpt3)

#	marked as # options are experimental

=head1 VERSION

    Version 0.3101

=cut

my_version=$(awk '$1=="Version"{print $2; exit}' <<< "$pod")

git_topdir() {
    [ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" == true ] || return
    local         dir="$(git rev-parse --show-superproject-working-tree)"
    [ "$dir" ] || dir="$(git rev-parse --show-toplevel)"
    echo -n $dir
}

env_pattern() {
    local name
    while (( $# > 0 ))
    do
	name+="${name:+\\|}$1"
	shift
    done
    echo -n ${name:+"^\\($name\\)="}
}

get_ip() {
    local ip=$(ifconfig 2>/dev/null | awk '/inet /{print $2}' | tail -1)
    echo -n $ip
}

repository=tecolicom/xlate
hostname=xlate
interactive=yes
version=
workdir=/work
mount_mode=rw
read_only=
display=
[ -e ${localtime:=/etc/localtime} ] || localtime=

DEFAULT_ENV="$(sed 's/  */\n/g' <<-EOF
	LANG TZ
	LESS=-cR LESSANSIENDCHARS=mK
	HTTP_PROXY HTTPS_PROXY
	http_proxy https_proxy
	TERM_PROGRAM TERM_BGCOLOR COLORTERM
	DEEPL_AUTH_KEY
	OPENAI_API_KEY
EOF
)"

declare -a ENV

while getopts :${EXOPT:=dBI:V:T:LRE:GCD} OPT
do
    case $OPT in
	d)       debug=yes ; set -x ;;
	B) interactive= ;;
	I)   container="$OPTARG" ;;
	V)      volume="$OPTARG" ;;
	T)     version=:"$OPTARG" ;;
	L)     version=:latest ;;
	R)  mount_mode=ro ;;
	E)
	    DEFAULT_ENV+=$'\n'"$OPTARG" ;;
	G)
	    [ "$XLATE_RUNNING_ON_DOCKER" ] && break
	    if [ "${topdir:=$(git_topdir)}" ]
	    then
		if [ "$topdir" != "${PWD:=$(pwd)}" ]
		then
		    echo "Mount $topdir to $workdir" >&2
		    volume=$topdir
		    cd_path=${PWD#$topdir}
		fi
	    fi
	    ;;
	C|D)
	    [ "$XLATE_RUNNING_ON_DOCKER" ] && break
	    if [ "$DISPLAY" ] && [ "${ip:=$(get_ip)}" ]
	    then
		display="$ip:0"
	    fi
	    if [ ! "$version" ]
	    then
		[[ "$my_version" =~ ^[0-9]+\.[0-9_]+$ ]] && version=":$my_version"
	    fi
	    declare -a command
	    case "$OPT" in
		C) shift $((OPTIND - 1)) ;;
		D) command=(xlate) ;;
	    esac
	    command+=(${1+"$@"})
	    [ ${#ENV[@]} -gt 0 ] && ENV_PATTERN="$(env_pattern ${ENV[@]})"
	    exec docker run --rm \
		 -e XLATE_RUNNING_ON_DOCKER=1 \
		 ${interactive:+-it} \
		 ${read_only:+--read-only} \
		 ${hostname:+--hostname "${hostname}"} \
		 ${localtime:+-v ${localtime}:/etc/localtime:ro} \
		 -v "${volume:-$(pwd)}:${workdir}:${mount_mode}" \
		 -w "${workdir}${cd_path}" \
		 ${display:+-e DISPLAY="$display"} \
		 ${DEFAULT_ENV:+--env-file <(echo "$DEFAULT_ENV")} \
		 ${ENV_PATTERN:+--env-file <(env | grep -e "$ENV_PATTERN")} \
		 ${container:-${repository}${version}} \
		 "${command[@]}"
	    exit;
	    ;;
    esac
done
OPTIND=1

mod="App-Greple-xlate"
share=$(perl -MFile::Share=:all -E "say dist_dir '$mod'")

while getopts "${EXOPT}"'Macrsne:p:w:o:f:t:m:l:hv' OPT
do
    case $OPT in
	[$EXOPT]) : ignore ;;
	M)  run_make=yes ;;
	a)   use_api=yes ;;
	c)     check=yes ;;
	r)   refresh=yes ;;
	s)    silent=yes ;;
	n)    dryrun=yes ;;
	e)    engine="$OPTARG" ;;
	p)   pattern="$OPTARG" ;;
	w)      wrap="$OPTARG" ;;
	o)    format="$OPTARG" ;;
	f) from_lang="$OPTARG" ;;
	t)   to_lang="$OPTARG" ;;
	m)       max="$OPTARG" ;;
	l)
	    file="$share/$OPTARG"
	    if [ -f "$file" ]
	    then
		cat $file
	    else
		echo $share
		ls -1 $share | sed 's/^/\t/'
	    fi
	    exit
	    ;;
	h)
	    sed -r \
		-e '/^$/N' \
		-e '/^\n*#/d' \
		-e 's/^(\n*)=[a-z]+[0-9]* */\1/' \
		-e '/Version/q' \
		<<< "$pod"
	    exit
	    ;;
	v)
	    echo $my_version
	    exit
	    ;;
    esac
done	
shift $((OPTIND - 1))

: run make
if [ "$run_make" == yes ]
then
    declare -a opt
    for m in "$@"
    do
	if [ -f "$m" ]
	then
	    # GNU Make behaves differently in different versions with
	    # respect to double-quoted strings and spaces within them.
	    files="${files:+$files|||}$m"
	else
	    opt+=("$m")
	fi
    done
    unset MAKELEVEL
    exec make -f $share/XLATE.mk \
	 ${dryrun:+-n} \
	 XLATE_LANG=\""$to_lang"\" \
	 XLATE_DEBUG=$debug \
	 XLATE_MAXLEN=$max \
	 XLATE_USEAPI=$use_api \
	 ${engine:+XLATE_ENGINE=\""$engine"\"} \
	 ${format:+XLATE_FORMAT=\""$format"\"} \
	 ${files:+XLATE_FILES=\""$files"\"} \
	 ${opt[@]}
    exit 1
fi

if [ ! "$to_lang" ]
then
    echo "-t option is required."
    exit 1
fi

: ${format:=xtxt}
: ${engine:=deepl}

if [[ "$format" =~ ^(.+)-fold$ ]]
then
    format=${BASH_REMATCH[1]}
    : ${wrap:=76}
fi

declare -a module option

module+=(-Mxlate) 
option+=(--xlate-engine="$engine")
option+=(--xlate-to="$to_lang" --xlate-format="$format" --xlate-cache=yes)
option+=(--all)

[ "$use_api" == yes ] || use_clipboard=yes
[ "$check"   == yes ] || option+=(--xlate${use_clipboard:+-labor})
[ "$wrap"    != ""  ] && option+=(--xlate-fold-line --xlate-fold-width=$wrap)
[ "$debug"   == yes ] && option+=(-dmo)
[ "$refresh" == yes ] && option+=(--cache-clear)
[ "$silent"  == yes ] && option+=(--no-xlate-progress)
[ "$max"     != ""  ] && option+=(--xlate-maxlen="$max")

declare -a area
case $1 in
    *.txt)
	area=(--re '^(.+\n)+')
	;;
    *.md)
	area=(--re '(?x) ^[-+#].*\n | ^[\t ]+\K.*\n | ^(.+\n)+ ')
	;;
    *.pm|*.pod)
	module+=(-Mperl)
	option+=(--pod)
	option+=(--exclude '^=head\d +(VERSION|AUTHOR|LICENSE).*\n(?s:.*?)(?=^=|\z)')
	area=(--re '^(\w.+\n)+')
	;;
    *.doc|*.docx|*.pptx|*.xlsx)
	module+=(-Mmsdoc)
	;&
    *.stxt)
	option+=(--exclude '^\[.*\b(doc|docx|pptx|xlsx)\b.*\]\n')
	area=(--re '^.+\n')
	;;
    *)
	area=(--re '^(.+\n)+')
	;;
esac

if [ "$pattern" ]
then
    option+=(--re "$pattern")
else
    option+=("${area[@]}")
fi

exec=(greple "${module[@]}" "${option[@]}" ${1+"$@"})

if [ "$dryrun" ]
then
    echo "${exec[@]}"
else
    "${exec[@]}"
fi
