#!/bin/bash

set -e

MYVERSION=@VERSION@

# parse invocation name and dir

SCRIPTNAME=$(basename "$0")
ORIGDIR=$(pwd)

# First, try "docclass-2-target", then obsolete "docclass2target"
SINGLEDOCCLASS=${SCRIPTNAME%-2-*}
if [ "$SINGLEDOCCLASS" != "$SCRIPTNAME" ]
then
    TARGETFORMAT=${SCRIPTNAME#${SINGLEDOCCLASS}-2-}
else
    SINGLEDOCCLASS=${SCRIPTNAME%2*}
    TARGETFORMAT=${SCRIPTNAME#${SINGLEDOCCLASS}2}
fi
# if called as sgml2xxx, don't assume a single docclass
#[ "${SINGLEDOCCLASS}" != sgml ] || SINGLEDOCCLASS=


# default values for params

JADE=jade

DEFAULTCONFDIRS="/etc/sgml/sgml2x ~/.sgml2x ./sgml2x-aliases"

DEFAULTVERBOSITY=1
declare -i VERBOSITY=${DEFAULTVERBOSITY}

# stdlib

error()
{
    echo >&2 "ERROR: ${SCRIPTNAME}: $*"
    exit 1
}

warn()
{
    [ $VERBOSITY -lt 1 ] || echo >&2 "Warning: ${SCRIPTNAME}: $*"
}

notice()
{
    [ $VERBOSITY -lt 2 ] || echo >&2 "Notice: ${SCRIPTNAME}: $*"
}

debug()
{
    [ $VERBOSITY -lt 3 ] || echo >&2 "Debug: ${SCRIPTNAME}: $*"
}

version()
{
    echo "sgml2x version ${MYVERSION}"
    exit 0
}

usage()
{
    # ensure the conf has been read
    if [ -z "${BACKENDS}" ]
    then
	readconf
    fi

    local stylefmt='    %15s : %s\n'

    # usage message
    cat <<EOF
Usage: ${SCRIPTNAME} [options] <sgmlfile> [<sgmlfile> ...]
	Options:
    -n|--no-act		print commands instead of running them
    -c|--catalog <catalog>
			use specified SGML catalog
    -C|--confdirs	use (whitespace-separated) list of confdirs
			(cumulative)
			default: \`${DEFAULTCONFDIRS}'
    -r|--remarks	include remarks in document
    -o|--openjade	use openjade to format
    -O|--jadeopts <jade-options>
			pass additionnal options to jade
			(cumulative)
    --jadetexfilter <perl-filter>
			a perl filter, with enough quotes (use -n to check)

    -q|--quiet		set verbosity to 0
    -v|--verbose	increase verbosity (cumulative)
    -V|--version	print the program's version
    --verbosity <N>	set verbosity to <N> (default: ${DEFAULTVERBOSITY})

    -s|--style <style>	select output style

	Standard styles:
EOF
    printf "${stylefmt}" 'local' 'Stylesheet from ./local.dsl'
    printf "${stylefmt}" 'local=<file>' 'Stylesheet from ./<file>.dsl'
    echo

    # FIXME: do something about possible other backends
    for backend in print html
    do
	local styles default style desc
	eval styles=\"\${STYLES_${SINGLEDOCCLASS}_${backend}}\"
	eval default=\"\${DEFAULTSTYLE_${SINGLEDOCCLASS}_${backend}}\"
	echo "Styles for ${SINGLEDOCCLASS} ${backend}:"
	for style in $styles
	do
	    eval desc=\${DESC_${SINGLEDOCCLASS}_${backend}_${style}}
	    printf "${stylefmt}" $style "$desc"
	done
	printf "    Default: ${default}\n\n"
    done

    exit 1
}

# local lib

id2file()
{
    local file=$(ospcat ${CATALOG:+-c $CATALOG} -P "$1" | grep '^<OSFILE' | 
	    sed -e s/'^<OSFILE>'// \
		-e "s%<OSFILE SOIBASE='\([^']*\)/[^/]*'>%\1/%" \
		-e "s%<OSFILE SOIBASE='\([^'/]*\)[^/]*'>%%" )
    [ -r "$file" ] || error "style not found: \`$1'"
    echo "$file"
}

runcmd()
{
    if [ "$NOACT" ]
    then
	echo "$@"
    else
	"$@"
    fi
}

# transform $1 as a path as seen from parent dir
fromparent()
{
    case "$1" in
    "") echo "" ;;
    /*) echo "$1" ;;
    *) echo "../$1" ;;
    esac
}

# list dir entries of type $1 in dir $2
files()
{
    cd "$2"
    find -type "$1" -maxdepth 1 ! -name '.*' -printf '%f\n'
}

## insert $1 in set represented by the array named $2
# prints the command that inserts $1 in set represented by the string named $2
# returns true (0) if insertion was done, 1 if already there
insert()
{
    if ! eval echo \" \${$2} \" | grep " $1 " >/dev/null
    then
	# register backend
	echo $2=\"\${$2} $1\"
    else
	return 1
    fi
}

conffield()
{
    local field="$1"
    grep "^${field}:" "${confdir}/${docclass}/${backend}/${style}" | sed "s/^${field}: *//"
}

# find aliases
readconf()
{
    local confdir backend style id cmd

#    declare -a BACKENDS=()
    BACKENDS=

    for confdir in ${CONFDIRS:-${DEFAULTCONFDIRS}}
    do
	if [ -d "${confdir}" ]
	then
	    notice "reading configuration from dir \`${confdir}'"
	    for docclass in $(files d "${confdir}")
	    do
		[ "$docclass" != CVS ] || continue

		# skip any unwanted docclass
		if [ -n "${SINGLEDOCCLASS}" -a "$docclass" != "${SINGLEDOCCLASS}" ]
		then
		    continue
		fi

		for backend in $(files d "${confdir}/${docclass}")
		do
		    [ "$backend" != CVS ] || continue

		    if cmd=$(insert "${backend}" BACKENDS)
		    then
			eval $cmd
			# ensure its styles list is empty on first occurence of a backend
			eval STYLES_${docclass}_${backend}=
		    fi
		    debug BACKENDS=$BACKENDS
		    eval DEFAULTSTYLE_${docclass}_${backend}=
		    eval local DEFAULTSTYLEPRIO_${docclass}_${backend}=

		    for style in $(files f "${confdir}/${docclass}/${backend}")
		    do
			[ "$style" != CVS ] || continue

			local id=$(conffield Id)

			# ignore styles for which we don't find the stylesheets
			if ! ( set +e; id2file "$id" >/dev/null 2>&1)
			then
			    notice "ignoring style \`$style': file not found"
			    continue
			fi

			local desc=$(conffield Desc)
			if ! cmd=$(insert ${style} STYLES_${docclass}_${backend})
			then
			    warn "overring definition for ${style}, ${confdir} prevails"
			fi
			eval $cmd
			eval PUBID_${docclass}_${backend}_${style}=\"${id}\"
			eval DESC_${docclass}_${backend}_${style}=\"${desc}\"

			local prio=$(conffield Priority)
			local bestprio=$(eval echo \${DEFAULTSTYLEPRIO_${docclass}_${backend}})
			if [ -z "$bestprio" ] || [ "$prio" -gt "$bestprio" ]
			then
			    eval DEFAULTSTYLE_${docclass}_${backend}=${style}
			    eval DEFAULTSTYLEPRIO_${docclass}_${backend}=$prio
			fi
		    done
		done
	    done
	fi
    done
}

# command-line

JADEARGS=
NOACT=
CATALOG=
CONFDIRS=
JADETEXPERLCMD=

while [ $# -gt 0 ] 
do
    case "$1" in
    -n|--no-act) NOACT=noact ;;
    -o|--openjade) JADE=openjade ;;
    -r|--remarks) JADEARGS="$JADEARGS -V%show-comments%" ;;
    -c|--catalog) [ $# -ge 2 ] || usage; CATALOG="$2" ; shift ;;
    -s|--style) [ $# -ge 2 ] || usage; CMDLN_STYLE="$2" ; shift ;;
    -O|--jadeopts) [ $# -ge 2 ] || usage; JADEARGS="$JADEARGS $2" ; shift ;;
    -C|--confdirs) [ $# -ge 2 ] || usage; CONFDIRS="$CONFDIRS $2" ; shift ;;
    --jadetexfilter) [ $# -ge 2 ] || usage; JADETEXPERLCMD="$2"; shift ;;
    -q|--quiet) VERBOSITY=0 ;;
    -v|--verbose) VERBOSITY=${VERBOSITY}+1 ;;
    -V|--version) version ;;
    --verbosity) [ $# -ge 2 ] || usage; VERBOSITY=$2 ; shift ;;
    -*) usage ;;
    *) break ;;
    esac
    shift
done

# FIXME: drop this when feature gets implemented
[ "${SINGLEDOCCLASS}" != sgml ] || error "can't be used with that name yet, use one of the symlinks"

# arguments sanity checks
command -v $JADE >/dev/null

# read the conffile
readconf

# configure jade step

CHANGEDIR=
BACKEND=print
case ${TARGETFORMAT} in
pdf)
    TARGET=tex
    TARGETEXT=jtex
    ;;
ps)
    TARGET=tex
    TARGETEXT=jtex
    JADEARGS="$JADEARGS -V use-eps"
    ;;
fot)
    TARGET=fot 
    TARGETEXT=fot
   ;;
html)
    TARGET=sgml
    TARGETEXT=html
    BACKEND=html
    ISDIR=YES
    ;;
rtf)
    TARGET=rtf
    TARGETEXT=rtf
    ;;
mif)
    TARGET=mif
    TARGETEXT=mif
    ;;
*)
    error "unsupported target format \`${TARGETFORMAT}'"
    ;;
esac

# convert files

[ "$*" ] || error "nothing to convert"

for SRC in "$@"
do
    [ -r "$SRC" ] || error "no such file \`$SRC'"

    FILEJADEARGS="$JADEARGS"
    PREFIXSRC=

    case "${SRC}" in
    /*) ;;
    *) SRC="${ORIGDIR}/${SRC}" ;;
    esac

    case "${SRC}" in
    *.sgml)
	SRCFORMAT=sgml
	NAMEROOT="${SRC%.sgml}"
	;;
    *.xml)
	SRCFORMAT=xml
	# XML files must be prefixed with the XML declaration to be parsed 
	XMLDECL=/usr/lib/sgml/declaration/xml.decl
	[ -r $XMLDECL ] || error "cannot find XML declaration $XMLDECL"
	NAMEROOT="${SRC%.xml}"
	PREFIXSRC=$XMLDECL
	# get XML-specific warnings
	# er, no, finally not - why is XML so dumb ?!
#	FILEJADEARGS="$FILEJADEARGS -wxml"
	;;
    *)
	error "Can't guess what to do without .sgml or .xml suffix: \`$SRC'"
	;;
    esac

    #
    # select stylesheet
    #

    # Look in document
    DOCCLASS_DSL=$(id2file "-//Alcove//DOCUMENT DocBook DocumentClass Stylesheet//EN")
    DOC_STYLE=$(${JADE} ${FILEJADEARGS} ${CATALOG:+-c $CATALOG} -t xml -d "${DOCCLASS_DSL}" ${PREFIXSRC} "${SRC}" | tr 'A-Z' 'a-z')

    # FIXME: should handle jade stylesheet PIs

    # Use default style for document type only if no style given on cmd line
    if [ "$DOC_STYLE" -a -z "$CMDLN_STYLE" ]
    then
	STYLE="$DOC_STYLE"
    else
	[ "$DOC_STYLE" -a "$DOC_STYLE" != "$CMDLN_STYLE" ] &&
	    notice "overriding doctype-derived style from command-line"
	STYLE=${CMDLN_STYLE:-${DEFAULTSTYLE}}
    fi

    # Map STYLE id to SHEET filename
    case $STYLE in
    local)
	SHEET="./local.dsl" ;;
    local=*)
	SHEET="${STYLE#local=}" 
	SHEET="${SHEET%.dsl}.dsl"	# Force .dsl suffix if not given
	;;
    *)
	eval SHEETID=\"\${PUBID_${SINGLEDOCCLASS}_${BACKEND}_${STYLE}}\"
    esac

    if [ -z "$SHEETID" -a -z "$SHEET" ]
    then
	ADDMSG=
	if [ "$STYLE" = "$DOC_STYLE" ]
	then
	    eval DEFSTYLE=\"\${DEFAULTSTYLE_${SINGLEDOCCLASS}_${BACKEND}}\"
	    warn "Unknown style \`$STYLE' - using default ${DEFSTYLE}"
	    STYLE=${DEFSTYLE}
	else
	    error "Unknown style \`$STYLE'"
	fi
    fi
    eval SHEETID=\"\${PUBID_${SINGLEDOCCLASS}_${BACKEND}_${STYLE}}\"
    notice "Converting ${SRCFORMAT} to ${TARGET} using style \`${STYLE}'... "

    SHEET=${SHEET:-$(id2file "$SHEETID")}
    debug "Using stylesheet file \`${SHEET}'"

    #
    # Stylesheet application itself
    #

    NAMEROOT="${NAMEROOT%.alcovebook}"
    DEST="${NAMEROOT}.${TARGETEXT}"
    [ "$NOACT" ] && echo || true
    (
	if [ "$ISDIR" ]
	then
	    runcmd rm -rf "$DEST"
	    runcmd mkdir -p "$DEST"
	    runcmd cd "$DEST"

	    CATALOG=$(fromparent ${CATALOG})
	    SHEET=$(fromparent "${SHEET}")
	fi
	runcmd ${JADE} ${FILEJADEARGS} ${CATALOG:+-c $CATALOG} -t ${TARGET} -d "${SHEET}" -o "${DEST}" ${PREFIXSRC} "${SRC}"
	# FIXME: hack around (open)jade passing raw -- to tex (Samuel Tardieu),
	# improved by Yann Dirson to allow arbitrary additional perl filters
	[ $TARGET != tex ] ||
	    runcmd perl -pi -e "s,--,-\\\\kern\\\\z@-,g; ${JADETEXPERLCMD}" "${DEST}"
    ) || exit $?
    echo "done"

    # postprocessing as needed

    case ${TARGETFORMAT} in
    ps)
	runcmd env LATEXPRG=jadetex rlatex "${DEST}"
	runcmd dvips "$(basename ${NAMEROOT})" -o
	;;
    pdf)
	runcmd env LATEXPRG=pdfjadetex rlatex "${DEST}"
	;;
    esac
done

# Local Variables:
# imenu-generic-expression: ((nil "^\\(\\w+\\) *()" 1) ("vars" "^ *\\(declare +-. +\\)?\\(\\w+\\)=" 2))
# imenu-sort-function: imenu--sort-by-name
# End:
