#!/bin/bash
set -e
APP_SVNID='$HeadURL: http://dione.no-ip.org/svn/ade/tags/1.7.6/bin/ade-app-config.sh $ $LastChangedRevision: 5436 $'
PROGNAME=`basename $0`

#  Option processing
FORMAT=plain
DIRECT=true

VARS="PREFIX LIB_PREFIX DOC_PREFIX BIN_PREFIX INCLUDE_PREFIX MAN_PREFIX MAN1_PREFIX MAN2_PREFIX MAN3_PREFIX MAN4_PREFIX MAN5_PREFIX MAN6_PREFIX MAN7_PREFIX MAN8_PREFIX ETC_PREFIX STATE_PREFIX LOCK_PREFIX LOG_PREFIX SPOOL_PREFIX"

#  Mini functions
error() { echo "$PROGNAME: ERROR: $1">&2; exit 1; }
usage() { echo "Usage: $PROGNAME [ -d <level> | --debug=<level> | -v | --verbose ] [ --format=<format> ] [ --[in]direct ] [ -a <appname> | --app-name=<appname> ] [ <variable> ... ]" >&2; exit 2; }
debug() { [ $ADE_MSG_VERBOSELEVEL -lt $1 ] || echo "$PROGNAME: DEBUG[$1]: $2">&2; }
debug_dump_vars() { for VAR in $VARS; do eval "debug 10 \"${UC_APP_NAME}_$VAR=\$${UC_APP_NAME}_$VAR\""; done; }

main()
{
    local OUTFILE

    #  Defaults for options
    APP_NAME=app
    ADE_MSG_VERBOSELEVEL=2

    #  Option processing
    while [ "X$1" != X ]; do
        case $1 in 
            --format=*)     FORMAT=${1#*=} ;;
            --direct)       DIRECT=true ;;
            --indirect)     DIRECT=false ;;
            -a)             APP_NAME=$2; shift ;;
            --app-name=*)   APP_NAME=${1#*=} ;;
            --debug=*)      ADE_MSG_VERBOSELEVEL=${1#*=} ;;
            -d)             ADE_MSG_VERBOSELEVEL=$2; shift ;;
            -v|--verbose)   ADE_MSG_VERBOSELEVEL=3 ;;
            --)             shift; break ;;
            -*)             usage ;;
            *)              break ;;
        esac
        shift
    done
    UC_APP_NAME=$(echo $APP_NAME | tr '[a-z]' '[A-Z]')
    LC_APP_NAME=$(echo $APP_NAME | tr '[A-Z]' '[a-z]')

    #  Argument processing (supplied arguments are the settings to
    #  be displayed; if none are supplied we want all, but what "all"
    #  means we don't know yet).
    [ "X$1" = X ] || DESIRED_VARS="$@"

    #  Stash the passed settings to accomplish two things:
    #  1) get an ordered list of variable names
    #  2) record but do not apply any values supplied
    SUPPLIEDS=(`cat`)
    for SUPPLIED in "${SUPPLIEDS[@]}"; do
        debug 10 "main: $SUPPLIED (recorded but not applied)"
    done
    
    #  If no arguments were supplied then *now* we *do* know what
    #  "all" means. 
    [ "X$1" != X ] || {
        for SUPPLIED in "${SUPPLIEDS[@]}"; do
            DESIRED_VARS="$DESIRED_VARS ${SUPPLIED%%=*}"
        done
    }
    debug 10 "main: DESIRED_VARS=\"$DESIRED_VARS\" (extracted from stdin/env)"


    #  Loop over the *names* of the supplied variables in the order
    #  they are supplied. 
    for SUPPLIED in "${SUPPLIEDS[@]}"; do
        VAR=${SUPPLIED%%=*}
        debug 10 "main: $VAR"

        #  If <APP>_<WHATEVER>_PREFIX is already in the enviroment
        #  then we don't need to put it there.
        
        #  If still not set and a setting is supplied then apply it.
        eval "[ \"X\$$VAR\" != X ] || $SUPPLIED"

        #  If still not set then use sensible internal defaults. (Note
        #  that this obviously can't set application-specific perculiar
        #  values (e.g. FAD_SORT_CMD) - see the final clause in the case
        #  for what we do with those.)
        eval "[ \"X\$$VAR\" != X ]" || case $VAR in
            ${UC_APP_NAME}_PREFIX)         eval "${UC_APP_NAME}_PREFIX=\${${UC_APP_NAME}_PREFIX:-/usr}" ;;
            ${UC_APP_NAME}_LIB_PREFIX)     eval "${UC_APP_NAME}_LIB_PREFIX=\${${UC_APP_NAME}_LIB_PREFIX:-\$${UC_APP_NAME}_PREFIX/lib/${LC_APP_NAME}}" ;;
            ${UC_APP_NAME}_DOC_PREFIX)     eval "${UC_APP_NAME}_DOC_PREFIX=\${${UC_APP_NAME}_DOC_PREFIX:-\$${UC_APP_NAME}_PREFIX/share/doc/${LC_APP_NAME}}" ;;
            ${UC_APP_NAME}_BIN_PREFIX)     eval "${UC_APP_NAME}_BIN_PREFIX=\${${UC_APP_NAME}_BIN_PREFIX:-\$${UC_APP_NAME}_PREFIX/bin}" ;;
            ${UC_APP_NAME}_INCLUDE_PREFIX) eval "${UC_APP_NAME}_INCLUDE_PREFIX=\${${UC_APP_NAME}_INCLUDE_PREFIX:-\$${UC_APP_NAME}_PREFIX/include/${LC_APP_NAME}}" ;;
            ${UC_APP_NAME}_MAN_PREFIX)     eval "${UC_APP_NAME}_MAN_PREFIX=\${${UC_APP_NAME}_MAN_PREFIX:-\$${UC_APP_NAME}_PREFIX/share/man}" ;;
            ${UC_APP_NAME}_MAN1_PREFIX)    eval "${UC_APP_NAME}_MAN1_PREFIX=\${${UC_APP_NAME}_MAN1_PREFIX:-\$${UC_APP_NAME}_MAN_PREFIX/man1}" ;;
            ${UC_APP_NAME}_MAN2_PREFIX)    eval "${UC_APP_NAME}_MAN2_PREFIX=\${${UC_APP_NAME}_MAN2_PREFIX:-\$${UC_APP_NAME}_MAN_PREFIX/man2}" ;;
            ${UC_APP_NAME}_MAN3_PREFIX)    eval "${UC_APP_NAME}_MAN3_PREFIX=\${${UC_APP_NAME}_MAN3_PREFIX:-\$${UC_APP_NAME}_MAN_PREFIX/man3}" ;;
            ${UC_APP_NAME}_MAN4_PREFIX)    eval "${UC_APP_NAME}_MAN4_PREFIX=\${${UC_APP_NAME}_MAN4_PREFIX:-\$${UC_APP_NAME}_MAN_PREFIX/man4}" ;;
            ${UC_APP_NAME}_MAN5_PREFIX)    eval "${UC_APP_NAME}_MAN5_PREFIX=\${${UC_APP_NAME}_MAN5_PREFIX:-\$${UC_APP_NAME}_MAN_PREFIX/man5}" ;;
            ${UC_APP_NAME}_MAN6_PREFIX)    eval "${UC_APP_NAME}_MAN6_PREFIX=\${${UC_APP_NAME}_MAN6_PREFIX:-\$${UC_APP_NAME}_MAN_PREFIX/man6}" ;;
            ${UC_APP_NAME}_MAN7_PREFIX)    eval "${UC_APP_NAME}_MAN7_PREFIX=\${${UC_APP_NAME}_MAN7_PREFIX:-\$${UC_APP_NAME}_MAN_PREFIX/man7}" ;;
            ${UC_APP_NAME}_MAN8_PREFIX)    eval "${UC_APP_NAME}_MAN8_PREFIX=\${${UC_APP_NAME}_MAN8_PREFIX:-\$${UC_APP_NAME}_MAN_PREFIX/man8}" ;;
            ${UC_APP_NAME}_ETC_PREFIX)     if eval "[ \"X\$${UC_APP_NAME}_PREFIX\" = X/usr ]"; then
                                               eval "${UC_APP_NAME}_ETC_PREFIX=\${${UC_APP_NAME}_ETC_PREFIX:-/etc/${LC_APP_NAME}}"
                                           else
                                               eval "${UC_APP_NAME}_ETC_PREFIX=\${${UC_APP_NAME}_ETC_PREFIX:-\$${UC_APP_NAME}_PREFIX/etc/${LC_APP_NAME}}"
                                           fi ;;
            ${UC_APP_NAME}_STATE_PREFIX)   if eval "[ \"X\$${UC_APP_NAME}_PREFIX\" = X/usr ]"; then
                                               eval "${UC_APP_NAME}_STATE_PREFIX=\${${UC_APP_NAME}_STATE_PREFIX:-/var/lib/${LC_APP_NAME}}"
                                           else
                                               eval "${UC_APP_NAME}_STATE_PREFIX=\${${UC_APP_NAME}_STATE_PREFIX:-\$${UC_APP_NAME}_PREFIX/var}"
                                           fi ;;
            ${UC_APP_NAME}_LOCK_PREFIX)    if eval "[ \"X\$${UC_APP_NAME}_PREFIX\" = X/usr ]"; then
                                               eval "${UC_APP_NAME}_LOCK_PREFIX=\${${UC_APP_NAME}_LOCK_PREFIX:-/var/run}"
                                           else
                                               eval "${UC_APP_NAME}_LOCK_PREFIX=\${${UC_APP_NAME}_LOCK_PREFIX:-\$${UC_APP_NAME}_STATE_PREFIX/var/run}"
                                           fi ;;
	    ${UC_APP_NAME}_LOG_PREFIX)     if eval "[ \"X\$${UC_APP_NAME}_PREFIX\" = X/usr ]"; then
                                               eval "${UC_APP_NAME}_LOG_PREFIX=\${${UC_APP_NAME}_LOG_PREFIX:-/var/log/${LC_APP_NAME}}"
                                           else
                                               eval "${UC_APP_NAME}_LOG_PREFIX=\${${UC_APP_NAME}_LOG_PREFIX:-\$${UC_APP_NAME}_STATE_PREFIX/log}"
                                           fi ;;
	    ${UC_APP_NAME}_SPOOL_PREFIX)   if eval "[ \"X\$${UC_APP_NAME}_PREFIX\" = X/usr ]"; then
                                               eval "${UC_APP_NAME}_SPOOL_PREFIX=\${${UC_APP_NAME}_SPOOL_PREFIX:-/var/spool/${LC_APP_NAME}}"
                                           else
                                               eval "${UC_APP_NAME}_SPOOL_PREFIX=\${${UC_APP_NAME}_SPOOL_PREFIX:-\$${UC_APP_NAME}_STATE_PREFIX/spool}"
                                           fi ;;
            *)                             error "$VAR: no definition found either in environment or settings file" ;;
        esac
    done
       
    #  Sanity checks
    #  Encapsulated-make format cannot be used indirectly.
    [ $FORMAT != encapsulated-make ] || $DIRECT || error "$FORMAT: only available in 'direct' format"
    
    #
    #  Output prologue
    #
    
    if ! $DIRECT; then
        TMPFILE=$(mktemp -t $PROGNAME.XXXXXXXX)
    elif [ $FORMAT = encapsulated-make ]; then
        echo '$(foreach PACKED_ASSIGNMENT,'
    fi
    
    #
    #  Output body 
    #
    
    #  Because there are error() calls in this loop, we cannot
    #  pipe the loop's output into an if (because an exit
    #  in the error() will not exit). This means we need to
    #  direct the loop's output *directly* to where we 
    #  want it to go (or use a temp file which I really don't
    #  want to do in such an often called script. Ha! {varname}
    #  comes to the rescue.
    if $DIRECT; then
        #  Unfortunately '&1' in a variable is not interpreted 
        #  correctly. One solution would be to use eval. Another
        #  to use /dev/stdout. But that is probably Linux
        #  specific. Actually, no; Solaris has it too.
        FD=1
    else
        #  Search bash man page for '{varname}' for an explanation of this.
        exec {FD}> $TMPFILE
    fi
    for DESIRED_VAR in $DESIRED_VARS; do
        UC_VAR=$(echo $DESIRED_VAR | tr '[a-z]' '[A-Z]')
        LC_VAR=$(echo $DESIRED_VAR | tr '[A-Z]' '[a-z]')
        eval "VALUE=\$$UC_VAR"
        #  All *_PREFIX settings must be defined. Others (e.g.
        #  FAD_SORT_CMD) are allowed not to be defined.
        ! [[ $DESIRED_VAR =~ _PREFIX$ ]] || [ "X$VALUE" != X ] || error "$DESIRED_VAR: not defined (is this really the right name?)"
        case $FORMAT in
            shell)             echo "$UC_VAR=$VALUE" ;;
            perl)              echo "\$$LC_VAR = \"$VALUE\";" ;;
            man)               echo ".ds $LC_VAR $VALUE" ;;
            plain)             echo "$VALUE" ;;
            make)              echo "$UC_VAR = $VALUE" ;;
    	    encapsulated-make) echo "$UC_VAR = $VALUE" | sed 's/ /@/g' ;;
            cpp)               echo "#define $UC_VAR \"$VALUE\"" ;;
            *)                 error "$FORMAT: invalid format" ;;
        esac
    done >&$FD
    [ $FD = 1 ] || exec {FD}<&-
    
    #
    #  Output epilogue
    #
    
    if ! $DIRECT; then
        case $FORMAT in
            shell) echo ". $TMPFILE" ;;
            perl)  echo "require '$TMPFILE';" ;;
            man)   echo ".so $TMPFILE" ;;
            plain) echo "$TMPFILE" ;;
            make)  echo "include $TMPFILE" ;;
            cpp)   echo "#include \"$TMPFILE\"" ;;
        esac
    elif [ $FORMAT = encapsulated-make ]; then
        echo ',$(eval $(subst @, ,$(PACKED_ASSIGNMENT))))'
    fi
}

main "$@"
