#!/bin/bash
#
# Copyright (C) 2012-2015 SUSE Linux GmbH
#
# Author:
# Thomas Schraitle <toms at opensuse dot org>
# Frank Sundermeyer <fsundermeyer at opensuse dot org>
#
# Script to change DocBook 4 source to version 5
#

# Name of this script:
ME="$(basename "$0")"

# TODO: Make it configurable by ~/.daps/config or ~/.config/daps/dapsrc
# [[ -f ~/.daps/config ]] && source ~/.daps/config
# [[ -f ~/.config/daps/dapsrc ]] && source ~/.config/daps/dapsrc

# Contains the stylesheet to migrate DocBook 4 -> 5:
MIGRATE_XSLT=${MIGRATE_XSLT:-/usr/share/xml/docbook/stylesheet/upgrade/db4-upgrade.xsl}

# File extension
EXT=${EXT:-.xml}

# Where to write all xsl:message outputs from xsltproc:
XSLTPROCLOG=${XSLTPROCLOG:-/tmp/daps-migrate.log}

# Holds XSLT parameters which is passed to the XSLT processor
declare -A PARAMS
PARAMS=()

# Verbosity
# VERBOSE=0

# replacement string for root element in header file
ROOTREPLACE=@RE@

## Functions
function exit_on_error {
    echo -e "ERROR: $1" >&2
    exit 1;
}

function dump {
    if [[ -n "$VERBOSE" ]]; then
        echo "$1"
    fi
    echo "$1" >> "$XSLTPROCLOG" 2>&1
}

function get_rootelement {
    #
    # input: XML file name
    # output: root element
    #
    local FILE
    FILE=$1
    if [[ -x /usr/bin/xmlstarlet ]]; then
        XMLSTARLET=/usr/bin/xmlstarlet
    elif [[ -x /usr/bin/xml ]]; then
        XMLSTARLET=/usr/bin/xml
    else
        exit_on_error "Cannot find xmlstarlet"
    fi

    ROOTELEMENT=$($XMLSTARLET sel -t -v "local-name(/*)" "$FILE") || exit_on_error "Cannot get root element from $FILE"

}

# Help function to preserve readability of the while loop
function usage {
    cat <<EOF_helptext
Usage: $ME [OPTIONS] INPUTDIR OUTPUTDIR

Wrapper script to convert a set of DocBook documents

Options:
  --header       Path to a file containing a DocBook header. If specified,
                 this header will be written to each file that is generated.
                 The header needs to contain the placeholder "$ROOTREPLACE" in
                 place of the root element
  -l LOGFILE, --log=LOGFILE
                 Write all outputs of xsltproc to LOGFILE
                 (default: $XSLTPROCLOG)
  -p, --param="XSLPARAM=VALUE"
                 Defines parameter-value pair for the XSLT processor;
                 can be used more than once
  -s XSLT, --stylesheet=XSLT
                 Use stylesheet for transformation
                 (default: $MIGRATE_XSLT)
  -h, --help     Print this help
  -v, --verbose  Be verbose

Mandatory arguments:
   INPUTDIR      Searches for all XML file in this directory
   OUTPUTDIR     Write all XML file into the OUT directory
EOF_helptext
}

function parse_param {
    # Syntax: parse_param "PARAMETER_AND_VALUE"
    # Extract parameter and value, syntax $1="param=value"
    local _PARAM=$1
    [[ "$_PARAM" == *"="* ]] || exit_on_error "Option -p must adhere to the syntax PARAMETER=VALUE"
    p=${_PARAM%=*}
    v=${_PARAM#*=}
    # Define associative array:
    PARAMS["$p"]="$v"
}

## START
#
# TODO: getopts
export POSIXLY_CORRECT=1
ARGS=$(getopt -o "hvl:s:p:" -l "header:,help,verbose,log:,stylesheet:,param:" -n "$ME" -- "$@")

eval set -- "$ARGS"

while true; do
    case "$1" in
        --header)
            if [[ -f $2 ]]; then
                if grep -q "$ROOTREPLACE" "$2" >/dev/null 2>&1; then
                    HEADERFILE="$2"
                else
                    exit_on_error "Header file does not contain the replacement string $ROOTREPLACE for the root element"
                fi
            else
                exit_on_error "$2 is not a regular file"
            fi
            shift 2
            ;;
        -h|--help)
            usage
            exit 1
            shift
            ;;
        -l|--log)
            XSLTPROCLOG="$2"
            shift 2
            ;;
        -p|--param)
            parse_param "$2"
            shift 2
            ;;
        -s|--stylesheet)
            MIGRATE_XSLT="$2"
            shift 2
            ;;
        -v|--verbose)
            VERBOSE=1
            shift
            ;;
        --)
            shift
            break;;
        *) exit_on_error "Internal error!" ;;
    esac
done

unset POSIXLY_CORRECT

## Check for errors
if [[ $# -eq 0 ]]; then
    usage
    exit 1
fi

INPUTDIR=$1
OUTPUTDIR=$2

[[ $# -lt 2 ]] && exit_on_error "Missing arguments: Need both input and output directory!"
[[ -d $INPUTDIR ]] || exit_on_error "First argument '$1' is not a directory"
if [[ ! -d $OUTPUTDIR ]]; then
    mkdir -p "$OUTPUTDIR"
fi

[[ -e $XSLTPROCLOG ]] && rm "$XSLTPROCLOG"

dump "** Starting DocBook Transformation **"
dump "** Using stylesheet $MIGRATE_XSLT"
p=""
for i in "${!PARAMS[@]}"; do
    p="$i=${PARAMS[$i]} $p"
done
dump "** Parameters: $p"

p=""
for i in "${!PARAMS[@]}"; do
    p="--stringparam $i ${PARAMS[$i]} $p"
done

dump "** Command line: xsltproc --output FILE ${p} $MIGRATE_XSLT XMLINPUT"

for xmlin in ${INPUTDIR}/*$EXT; do
    xmlout="$OUTPUTDIR/$(basename "$xmlin")"
    dump "$xmlin -> $xmlout"
    if [[ -n $HEADERFILE ]]; then
        cp "$HEADERFILE" "$xmlout"
        get_rootelement "$xmlin"
        sed -i "s/$ROOTREPLACE/$ROOTELEMENT/" "$xmlout"
        xsltproc --nonet ${p} "$MIGRATE_XSLT" "$xmlin" >> "$xmlout" 2>> "$XSLTPROCLOG"
    else
        xsltproc --nonet --output "$xmlout" ${p} "$MIGRATE_XSLT" "$xmlin" 2>> "$XSLTPROCLOG"
    fi
    #   ERRCODE=$?
    dump "--------------------------------------------------"
done

dump "** Finished, see $XSLTPROCLOG for more information **"
dump ""

# EOF
