#!/bin/bash
set -e

trap cleanup EXIT

cd "$( dirname "${BASH_SOURCE[0]}" )"

readonly LOCALS_DIR="$(pwd)/$1"
readonly MODULE_NAME=$2
readonly PREFIX=$3
BB_HOSTID=$4
if [ -z $BB_HOSTID ]; then
    BB_HOSTID=$BB_HOST_ID
fi

readonly DEST_CONFIG_NAME="$MODULE_NAME.daemon"

readonly XSLT_FILE=fastcgi.xsl.$$
readonly TEMP_INCLUDE=fastcgi.template.$$
readonly TEMP_GENERATED=fastcgi.generated.$$
readonly TEMP_FINAL=fastcgi.final.$$
readonly XMLLINT_ERR=xmllint.err.$$


# this function is called on exit, to clean up all intermediate files
cleanup() {
    if [ $? -gt 0 ]; then
        mv ${LOCALS_DIR}/${XSLT_FILE} ${LOCALS_DIR}/${XSLT_FILE}.failed
        mv ${LOCALS_DIR}/${TEMP_INCLUDE} ${LOCALS_DIR}/${TEMP_INCLUDE}.failed
        mv ${LOCALS_DIR}/${TEMP_GENERATED} ${LOCALS_DIR}/${TEMP_GENERATED}.failed
        mv ${LOCALS_DIR}/${TEMP_FINAL} ${LOCALS_DIR}/${TEMP_FINAL}.failed
    else
        rm -f ${LOCALS_DIR}/{$XSLT_FILE,$TEMP_INCLUDE,$TEMP_GENERATED,$TEMP_FINAL,$XMLLINT_ERR} 2> /dev/null
    fi
}


# HOSTID value must be specified in the environment (it is exported by Make)
if [ -z "$BB_HOSTID" ]; then
    echo Undefined BB_HOSTID
    exit 1
fi

# Remember current directory and change to the specified one
if [ -z "$LOCALS_DIR" ]; then
    echo "Directory containing fastcgi.locals.* must be specified"
    exit 1
fi
if [ ! -d "$LOCALS_DIR" ]; then
    echo "Directory $LOCALS_DIR doesn't exist!"
    exit 1
fi

pushd "$LOCALS_DIR" >/dev/null

# Include file with local settings
. "fastcgi.locals.$MODULE_NAME"

if [ "$PREFIX" != "" ]; then
PREFIX_VAR=$PREFIX"-"
POSTFIX_VAR="-"$PREFIX
fi

PORTS=(
'{daemon-port}'=="${BLACKBOX_DAEMON_PORT:-10080}" \
'{monitoring-port}'=="${BLACKBOX_MONITORING_PORT:-3334}" \
'{passportdb-port}'=="${BLACKBOX_PASSPORTDB_PORT:-3306}" \
'{kolmogor-port}'=="${BLACKBOX_KOLMOGOR_PORT:-11080}" \
'{sesskill-port}'=="${BLACKBOX_SESSKILL_PORT:-8080}" \
'{passport-port}'=="${BLACKBOX_PASSPORT_PORT:-80}" \
'{tvm-port}'=="${BLACKBOX_TVM_PORT:-443}" \
)

MISC=(
'{root-directory}'=="$BLACKBOX_ROOT_DIRECTORY" \
'{logs-directory}'=="${BLACKBOX_LOGS_DIRECTORY:-${BLACKBOX_ROOT_DIRECTORY}/opt/sezam-logs${POSTFIX_VAR}}" \
'{config-directory}'=="${BLACKBOX_CONFIG_DIRECTORY:-${BLACKBOX_ROOT_DIRECTORY}/etc/fastcgi2/available}" \
'{geobase-directory}'=="${BLACKBOX_GEOBASE_DIRECTORY:-${BLACKBOX_ROOT_DIRECTORY}/var/cache/passport-sezam-geobase-checker}" \
'{prefix}'=="$PREFIX_VAR" \
'{postfix}'=="$POSTFIX_VAR" \
'{instance}'=="$MODULE_NAME" \
'{host-id}'=="$BB_HOSTID" \
'{keys-dbname}'=="${KEYS_DB_NAME:-passportdbcentral}" \
)

# Start generating config

# Process xi:include in template
xmllint --xinclude "$OLDPWD/template-$MODULE_NAME.conf" > "$TEMP_INCLUDE"

# Generate XSLT script to apply all XPath-based patches
#
# Create stylesheet prologue
cat <<EOF >"$XSLT_FILE"
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="node() | @*">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template>
EOF

# Create templates for XPath-based substitutions
for i in "${PATHS[@]}"; do
cat <<EOF >>"$XSLT_FILE"
<xsl:template match="${i/==*/}">
    <xsl:choose>
        <xsl:when test="text()">
            <xsl:copy>
                <xsl:apply-templates select="@*"/>
                <xsl:value-of select="'${i/*==/}'"/>
            </xsl:copy>
        </xsl:when>
        <xsl:otherwise>
            <xsl:attribute name="{name()}">
                <xsl:value-of select="'${i/*==/}'"/>
            </xsl:attribute>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>
EOF
done

# Create templates for xinclude's
for i in "${INCLUDES[@]}"; do
cat <<EOF >>"$XSLT_FILE"
<xsl:template match="${i/==*/}">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
        <xsl:element name="include" namespace="http://www.w3.org/2001/XInclude">
            <xsl:attribute name="href">${i/*==/}</xsl:attribute>
        </xsl:element>
    </xsl:copy>
</xsl:template>
EOF
done

for i in "${REMOVES[@]}"; do
cat <<EOF >>"$XSLT_FILE"
<xsl:template match="$i"/>
EOF
done


# Create sharded db templates
cat <<EOF >>"$XSLT_FILE"
<xsl:template match="sharded_db_conf">
    <xsl:element name="include" namespace="http://www.w3.org/2001/XInclude">
        <xsl:attribute name="href">shards.conf</xsl:attribute>
    </xsl:element>
</xsl:template>
EOF

# Create OAuth shards db templates
cat <<EOF >>"$XSLT_FILE"
<xsl:template match="oauth_db_conf">
    <xsl:element name="include" namespace="http://www.w3.org/2001/XInclude">
        <xsl:attribute name="href">oauth_shards.conf</xsl:attribute>
    </xsl:element>
</xsl:template>
EOF

# Create BadauthDB templates
if [ -f kolmogor.conf ]; then
cat <<EOF >>"$XSLT_FILE"
<xsl:template match="kolmogor_settings/local_settings">
    <xsl:element name="include" namespace="http://www.w3.org/2001/XInclude">
        <xsl:attribute name="href">kolmogor.conf</xsl:attribute>
        <xsl:attribute name="xpointer">xpointer(/kolmogor_settings/*)</xsl:attribute>
    </xsl:element>
</xsl:template>
EOF
    # If text "db_host" exists in kolmogor.conf, assume db_host includes from kolmogor.conf,
    # so delete 'kolmogor_settings/db_host' element from template
    if fgrep -q "db_host" kolmogor.conf; then
cat <<EOF >>"$XSLT_FILE"
<xsl:template match="kolmogor_settings/db_host"/>
EOF
fi
else
cat <<EOF >>"$XSLT_FILE"
<xsl:template match="kolmogor_settings/local_settings"/>
EOF
fi

# Create Perimeter templates
# If perimeter.conf exists, replace 'perimeter/local_settings' element with config, otherwise delete 'perimeter' element
if [ -f perimeter.conf ]; then
cat <<EOF >>"$XSLT_FILE"
<xsl:template match="perimeter/local_settings">
    <xsl:element name="include" namespace="http://www.w3.org/2001/XInclude">
        <xsl:attribute name="href">perimeter.conf</xsl:attribute>
        <xsl:attribute name="xpointer">xpointer(/perimeter/*)</xsl:attribute>
    </xsl:element>
</xsl:template>
EOF
    # If text "db_host" exists in perimeter.conf, assume db_host includes from perimeter.conf,
    # so delete 'perimeter/db_host' element from template
    if fgrep -q "db_host" perimeter.conf; then
cat <<EOF >>"$XSLT_FILE"
<xsl:template match="perimeter/db_host"/>
EOF
fi
else
cat <<EOF >>"$XSLT_FILE"
<xsl:template match="perimeter"/>
EOF
cat <<EOF >>"$XSLT_FILE"
<xsl:template match="staff_fetcher"/>
EOF
fi

# Create SessKill templates
# If sess_kill.conf exists, replace 'sess_kill/local_settings' element with config, otherwise delete 'sess_kill/local_settings' element
if [ -f sess_kill.conf ]; then
cat <<EOF >>"$XSLT_FILE"
<xsl:template match="sess_kill/local_settings">
    <xsl:element name="include" namespace="http://www.w3.org/2001/XInclude">
        <xsl:attribute name="href">sess_kill.conf</xsl:attribute>
        <xsl:attribute name="xpointer">xpointer(/sess_kill/*)</xsl:attribute>
    </xsl:element>
</xsl:template>
EOF
    # If text "db_host" exists in sess_kill.conf, assume db_host includes from sess_kill.conf,
    # so delete 'sess_kill/db_host' element from template
    if fgrep -q "db_host" sess_kill.conf; then
cat <<EOF >>"$XSLT_FILE"
<xsl:template match="sess_kill/db_host"/>
EOF
fi
else
cat <<EOF >>"$XSLT_FILE"
<xsl:template match="sess_kill/local_settings"/>
EOF
fi

# Create stylesheet epilogue
cat <<EOF >>"$XSLT_FILE"

</xsl:stylesheet>
EOF

# Apply the stylesheet
xsltproc -o "$TEMP_GENERATED" "$XSLT_FILE" "$TEMP_INCLUDE"

# Create sed commands for all substitution rules. The use sed to make substitutions.
SEDSUBS=()
for i in "${MISC[@]}" "${PORTS[@]}" "${SUBS[@]}"; do
    SEDSUBS=("${SEDSUBS[@]}" "-e s~${i/==*/}~${i/*==/}~g")
done

# Final XML touch: pretty-format, process includes, replace variables
xmllint --format --xinclude "${TEMP_GENERATED}" 2> ${XMLLINT_ERR} | sed "${SEDSUBS[@]}" | grep -v BUILD-STUB > ${TEMP_FINAL}
if [ -s ${XMLLINT_ERR} ]; then
    echo "Errors in xmllint:"
    cat ${XMLLINT_ERR}
    exit 1
fi

# Check for unreplaced templates
if grep -E "\{[a-z-]+\}" ${TEMP_FINAL}; then
    echo "Some unreplaced templates found ^^^ in $(pwd)/${TEMP_FINAL}"
    exit 1
fi

mv ${TEMP_FINAL} ${OLDPWD}/${DEST_CONFIG_NAME}

# Return to the original directory
popd >/dev/null

# Fix generated config permissions
if [ "$EUID" -eq 0 ]; then
    chmod 0440 "$DEST_CONFIG_NAME"
    chown blackbox:blackbox "$DEST_CONFIG_NAME"
fi

exit 0
