<?xml version="1.0" encoding="utf-8"?>

<!--
    Name:       include/defs.xml
    Purpose:    Common declarations for buildbot
    Author:     Mike Wetherell
    Copyright:  (c) 2007 Mike Wetherell
    Licence:    wxWindows licence
-->

<bot xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:exsl="http://exslt.org/common"
     xmlns:func="http://exslt.org/functions"
     xmlns:get="local"
     xsl:extension-element-prefixes="func"
     xsl:version="1.0">

<!--
    Constants
-->
<xsl:template name="SVN_URL">http://svn.wxwidgets.org/svn/wx/wxWidgets/</xsl:template>
<xsl:template name="STABLE_BRANCH">branches/WX_2_8_BRANCH</xsl:template>
<xsl:variable name="STABLE_BRANCH"><STABLE_BRANCH/></xsl:variable>
<xsl:template name="RELEASE_BRANCH">branches/WX_2_9_0_BRANCH</xsl:template>
<xsl:variable name="RELEASE_BRANCH"><RELEASE_BRANCH/></xsl:variable>
<xsl:template name="SNAPSHOT_URL">http://biolpc22.york.ac.uk/pub</xsl:template>

<!--
    disable - comment out a section.

    Usage: <disable>
                e.g. <build> ... etc.
           </disable>

    XML comments can't contain a double hyphen which tends to be used in
    configure commands, so <disable> can be used instead. 
-->
<xsl:template name="disable"/>

<!--
    checkout - build step for source checkout.

    Usage: as <svn> with defaults for <baseURL> and <defaultBranch>

    Typically just:
        <checkout/>
    for the trunk, or:
        <checkout branch="branches/WX_2_8_BRANCH"/>
    to checkout a branch.
-->
<xsl:template name="checkout">
    <xsl:param name="content"/>
    <xsl:param name="branch" select="'trunk'"/>
    <xsl:variable name="nodes" select="exsl:node-set($content)"/>
    <svn>
        <xsl:if test="not($nodes/svnurl)">
            <xsl:if test="not($nodes/baseURL)">
                <baseURL><SVN_URL/></baseURL>
            </xsl:if>
            <xsl:if test="not($nodes/defaultBranch)">
                <defaultBranch><xsl:value-of select="$branch"/></defaultBranch>
            </xsl:if>
        </xsl:if>
        <xsl:copy-of select="$content"/>
    </svn>
</xsl:template>

<!--
    configure - add the options attribute to <configure>

    Usage: <configure options="-with-foobar"/>
-->
<xsl:template name="configure">
    <xsl:param name="content"/>
    <xsl:param name="options"/>
    <configure>
        <copy-with-defaults content="{$content}">
            <command>./configure <xsl:value-of select="normalize-space($options)"/></command>
        </copy-with-defaults>
    </configure>
</xsl:template>

<!--
    make - specify the make command.

    Usage: <make>nmake -f makefile.vc SHARED=1</make>

    Used as a child of <build> to specify the make command used by the
    <compile> elements below, if omitted 'make' is used.
-->
<xsl:template name="make"/>

<!--
    compile - modifiy <compile> to default to the command given by <make>

    Usage: as <compile>

    The <make> element of <build> spcecifies the make command used by all
    compile build steps in the build. If <make> is not given 'make' is used.

    The command for a particular compile build step can be further overridden
    using its <command> element:
        <compile>
            <command>myscript</command>
        </compile>
-->
<xsl:template name="compile">
    <xsl:param name="content"/>
    <compile>
        <copy-with-defaults content="{$content}">
            <command><get name="make" default="make"/></command>
        </copy-with-defaults>
    </compile>
</xsl:template>

<!--
    Adds build steps to compile the library and the usual subdirectories.

    Usage: as <compile> with the additional attributes below.

    Usually the attributes default to suitable values, so typical usage
    is just <compile-all/>.

    <compile-all [ gui = 'true'|'false' ]
                 [ msw = 'true'|'false' ]
                 [ wx = 'true'|'false' ]
                 [ samples = 'true'|'false' ]
                 [ utils = 'true'|'false' ]
                 [ demos = 'true'|'false' ]
                 [ contrib = 'true'|'false' ]
                 [ tests = 'true'|'false' ] />

    gui     - if 'true' then build fully the subdirectories specified,
              otherwise only the wxBase subset of the directories are built.
    msw     - if 'true' then build the directory 'build/msw' when building the
              library instead of the root.
    wx      - build the library itself.
    samples, utils, demos, contrib, tests
            - build subdirectories.
-->
<xsl:template name="compile-all">
    <xsl:param name="content"/>

    <xsl:param name="gui"><is-gui/></xsl:param>
    <xsl:param name="msw"><is-msw/></xsl:param>

    <xsl:param name="wx" select="'true'"/>
    <xsl:param name="samples" select="'true'"/>
    <xsl:param name="utils" select="'true'"/>
    <xsl:param name="demos" select="$gui"/>
    <xsl:param name="contrib"><has-contrib/></xsl:param>
    <xsl:param name="tests"><has-tests/></xsl:param>

    <xsl:param name="wx-dirs">
        <get-dirs wx="{$wx}" gui="{$gui}" msw="{$msw}"/>
    </xsl:param>
    <xsl:param name="sample-dirs">
        <get-dirs samples="{$samples}" gui="{$gui}" msw="{$msw}"/>
    </xsl:param>
    <xsl:param name="util-dirs">
        <get-dirs utils="{$utils}" gui="{$gui}" msw="{$msw}"/>
    </xsl:param>
    <xsl:param name="demo-dirs">
        <get-dirs demos="{$demos}" gui="{$gui}" msw="{$msw}"/>
    </xsl:param>
    <xsl:param name="contrib-dirs">
        <get-dirs contrib="{$contrib}" gui="{$gui}" msw="{$msw}"/>
    </xsl:param>
    <xsl:param name="test-dirs">
        <get-dirs tests="{$tests}" gui="{$gui}" msw="{$msw}"/>
    </xsl:param>

    <compile-subdirs dirs="{$wx-dirs}" halt="true">
        <xsl:copy-of select="$content"/>
    </compile-subdirs>
    <compile-subdirs name="samples" dirs="{$sample-dirs}">
        <xsl:copy-of select="$content"/>
    </compile-subdirs>
    <compile-subdirs name="utils" dirs="{$util-dirs}">
        <xsl:copy-of select="$content"/>
    </compile-subdirs>
    <compile-subdirs name="demos" dirs="{$demo-dirs}">
        <xsl:copy-of select="$content"/>
    </compile-subdirs>
    <compile-subdirs name="contrib" dirs="{$contrib-dirs}">
        <xsl:copy-of select="$content"/>
    </compile-subdirs>
    <compile-subdirs name="tests" dirs="{$test-dirs}" halt="true">
        <xsl:copy-of select="$content"/>
    </compile-subdirs>
</xsl:template>

<!--
    Helper for compile-all.
    Returns the directories that need to be built for the various components:
    wx (the library itself), samples, utils, demos, contrib and tests.
-->
<xsl:template name="get-dirs">
    <xsl:param name="contents"/>

    <xsl:param name="gui"/>
    <xsl:param name="msw"/>

    <xsl:param name="wx"/>
    <xsl:param name="samples"/>
    <xsl:param name="utils"/>
    <xsl:param name="demos"/>
    <xsl:param name="contrib"/>
    <xsl:param name="tests"/>

    <xsl:if test="$wx = 'true'">
        <xsl:choose>
            <xsl:when test="$msw = 'true'">build/msw</xsl:when>
            <xsl:otherwise>.</xsl:otherwise>
        </xsl:choose>
        <xsl:text> </xsl:text>
    </xsl:if>

    <xsl:if test="$samples = 'true'">
        <xsl:choose>
            <xsl:when test="$gui = 'true'">samples</xsl:when>
            <xsl:otherwise>samples/console</xsl:otherwise>
        </xsl:choose>
        <xsl:text> </xsl:text>
    </xsl:if>

    <xsl:if test="$utils = 'true' and $gui = 'true'">utils </xsl:if>

    <xsl:if test="$demos = 'true' and $gui = 'true'">demos </xsl:if>

    <xsl:if test="$contrib = 'true' and $gui = 'true'">contrib </xsl:if>

    <xsl:if test="$tests = 'true'">tests</xsl:if>
</xsl:template>

<!--
    compile-subdir - build step to compile a subdirectory.

    Usage: as <compile> plus the following attributes,
           <compile-subdir dir="foobar" [ halt="true" ]/>

    Compiles the named subdirectory 'foobar'. Continues with the next build
    step on failure, unless the optional attibute 'halt="true"' is given.
    The make command used is as described for the compile step above.
-->
<xsl:template name="compile-subdir">
    <xsl:param name="content"/>
    <xsl:param name="dir"/>
    <xsl:param name="halt" select="'false'"/>
    <compile-subdirs name="{$dir}" dirs="{$dir}" halt="{$halt}">
        <xsl:copy-of select="$content"/>
    </compile-subdirs>
</xsl:template>

<!--
    compile-subdirs - adds a compile build step for each directory in a list.

    Usage: as <compile> plus the following attributes,
           <compile-subdir dirs="foobar1 foobar2"
                           [ name="foobars" ]
                           [ sep=" " ]
                           [ halt="true" ]/>

    Compiles the named subdirectories. Continues with the next build
    step on failure, unless the optional attibute 'halt="true"' is given.
    The make command used is as described for the compile step above.
    The 'name' attribute can be used to give a collective name for the
    subdirectories, and the 'sep' attibute can be used to specify the
    separator in the 'dirs' list (defaults to space).
-->
<xsl:template name="compile-subdirs">
    <xsl:param name="content"/>
    <xsl:param name="name"/>
    <xsl:param name="dirs"/>
    <xsl:param name="sep" select="' '"/>
    <xsl:param name="halt" select="'false'"/>
    <xsl:if test="translate($dirs, $sep, '')">
        <compile>
            <defaults content="{$content}">
                <name>
                    <xsl:value-of select="normalize-space(concat('compile ', $name))"/>
                </name>
                <description>
                    <xsl:value-of select="normalize-space(concat('compiling ', $name))"/>
                </description>
                <descriptionDone>
                    <xsl:value-of select="normalize-space(concat('compile ', $name))"/>
                </descriptionDone>
                <haltOnFailure>
                    <xsl:value-of select="$halt"/>
                </haltOnFailure>
                <warnOnFailure/>
            </defaults>
            <copy-with-defaults content="{$content}">
                <command>
                    <compile-subdirs-cmd dirs="{$dirs}" sep="{$sep}"/>
                </command>
            </copy-with-defaults>
        </compile>
    </xsl:if>
</xsl:template>

<xsl:template name="compile-subdirs-cmd">
    <xsl:param name="content"/>
    <xsl:param name="dirs"/>
    <xsl:param name="sep"/>
    <xsl:choose>
        <xsl:when test="contains($dirs, $sep)">
            <xsl:variable name="before" select="substring-before($dirs, $sep)"/>
            <xsl:variable name="after" select="substring-after($dirs, $sep)"/>

            <xsl:call-template name="compile-subdirs-cmd">
                <xsl:with-param name="dirs" select="$before"/>
                <xsl:with-param name="sep" select="$sep"/>
            </xsl:call-template>

            <xsl:if test="$after and substring($after, 1, 1) != ' '">
                <xsl:text> &amp;&amp; </xsl:text>
            </xsl:if>

            <xsl:call-template name="compile-subdirs-cmd">
                <xsl:with-param name="dirs" select="$after"/>
                <xsl:with-param name="sep" select="$sep"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:when test="string($dirs)">
            <xsl:if test="$dirs != '.'">cd <xsl:value-of select="$dirs"/> &amp;&amp; </xsl:if>
            <get name="make" default="make"/>
        </xsl:when>
    </xsl:choose>
</xsl:template>

<!--
    run-tests - build step to run the test suites.

    Usage: as <test>

    Typically just:
        <run-tests/>
-->
<xsl:template name="run-tests">
    <xsl:param name="content"/>
    <xsl:param name="options" select="'-t'"/>
    <xsl:param name="guioptions" select="$options"/>
    <xsl:param name="msw"><is-msw/></xsl:param>
    <test>
        <defaults content="{$content}">
            <description>running tests</description>
            <descriptionDone>run tests</descriptionDone>
            <warnOnFailure/>
        </defaults>
        <copy-with-defaults content="{$content}">
            <command>
                <xsl:choose>
                    <xsl:when test="$msw = 'true'">
                        <run-tests-win options="{$options}" guioptions="{$guioptions}"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <run-tests-unix options="{$options}" guioptions="{$guioptions}"/>
                    </xsl:otherwise>
                </xsl:choose>
            </command>
        </copy-with-defaults>
    </test>
</xsl:template>

<xsl:template name="run-tests-win">
    <xsl:param name="options"/>
    <xsl:param name="guioptions"/>
<normalize-space>
cd tests &amp;&amp; runtests.bat
</normalize-space>
</xsl:template>

<xsl:template name="run-tests-unix">
    <xsl:param name="options"/>
    <xsl:param name="guioptions"/>
ERR=0
cd tests || exit 0
ulimit -c unlimited

try()
{
    rm -f core
    echo Running: "$@"
    "$@" || ERR=$?

    if [ -f core -a -x "`which gdb`" ]; then
        echo Crashed, attempting to display backtrace:
        gdb -batch -c core -ex 'set pagination off' -ex bt "$1"
    fi

    echo
}

try ./test <xsl:value-of select="normalize-space($options)"/>

test -x test_gui || exit $ERR

if [ -z "$DISPLAY" ]; then
    echo '$DISPLAY is not set, skipping GUI tests.'
    exit $ERR
fi

echo 'Checking window manager:'
WINDOW_MANAGER=$(xprop -root 32x '\n$0\n' _NET_SUPPORTING_WM_CHECK | grep ^0x)

if [ -z "$WINDOW_MANAGER" ]; then
    echo 'Window manager not present, skipping GUI tests.'
    exit $ERR
fi

xprop -id $WINDOW_MANAGER 8s _NET_WM_NAME
echo

try ./test_gui <xsl:value-of select="normalize-space($guioptions)"/>

exit $ERR
</xsl:template>

<!--
    defaults - supply default content for an element.

    Usage: <defaults content="{$content}">
               <foo>foo</foo>
               <bar>bar</bar>
           </defaults>

    Copies those child elements that do not already exist in $content.
-->
<xsl:template name="defaults">
    <xsl:param name="defaults"/>
    <xsl:param name="content"/>

    <xsl:variable name="def-nodes" select="exsl:node-set($defaults)"/>
    <xsl:variable name="cont-nodes" select="exsl:node-set($content)"/>

    <xsl:for-each select="$def-nodes/*">
        <xsl:if test="not($cont-nodes/*[name() = name(current())])">
            <xsl:copy-of select="."/>
        </xsl:if>
    </xsl:for-each>
</xsl:template>

<!--
    copy-with-defaults - copy elements supplying defaults for any that are
                         missing or empty.

    Usage: <copy-with-defaults content="{$content}">
               <foo>foo</foo>
               <bar>bar</bar>
           </copy-with-defaults>

    Copies $content plus any child elements that do not exist in $content,
    substituting empty elements in $content with any child elements of the
    same name.
-->
<xsl:template name="copy-with-defaults">
    <xsl:param name="defaults"/>
    <xsl:param name="content"/>

    <xsl:variable name="def-nodes" select="exsl:node-set($defaults)"/>
    <xsl:variable name="cont-nodes" select="exsl:node-set($content)"/>

    <xsl:for-each select="$def-nodes/*">
        <xsl:if test="not($cont-nodes/*[name() = name(current())])">
            <xsl:copy-of select="."/>
        </xsl:if>
    </xsl:for-each>

    <xsl:for-each select="$cont-nodes/*">
        <xsl:choose>
            <xsl:when test="not(node())">
                <xsl:copy-of select="$def-nodes/*[name() = name(current())]"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy-of select="."/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:for-each>
</xsl:template>

<!--
    get - gets the text from a child element of the current build.

    Usage: <get name="foobar" [ default="value" ]/>

    Gets the text from the <foobar> element of the current build, or returns
    $default if there is not such element.
-->
<xsl:template name="get">
    <xsl:param name="content"/>
    <xsl:param name="build" select="get:build()"/>
    <xsl:param name="name"/>
    <xsl:param name="default"/>
    <xsl:variable name="property" select="get:property($name, $build)"/>
    <strip>
        <xsl:choose>
            <xsl:when test="$property">
                <xsl:apply-templates select="$property/node()"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$default"/>
            </xsl:otherwise>
        </xsl:choose>
    </strip>
</xsl:template>

<!--
    Accessors to get builds and their fields. XSLT code should use these
    instead of traversing the input tree directly.
-->
<func:function name="get:build">
    <func:result select="ancestor-or-self::build[last()]"/>
</func:function>

<func:function name="get:all-builds">
    <func:result select="//build[not(ancestor::*[name() != name(/*)])]"/>
</func:function>

<func:function name="get:preceding-builds">
    <func:result select="get:build()/preceding-sibling::build"/>
</func:function>

<func:function name="get:property">
    <xsl:param name="name"/>
    <xsl:param name="build" select="get:build()"/>
    <func:result select="$build/*[name() = $name]"/>
</func:function>

<func:function name="get:step">
    <xsl:param name="name"/>
    <xsl:param name="build" select="get:build()"/>
    <func:result select="get:property('steps', $build)/*[name() = $name]"/>
</func:function>

<!--
    Returns true if this is an msw build.
-->
<xsl:template name="is-msw">
    <xsl:param name="content"/>
    <xsl:param name="build" select="get:build()"/>
    <xsl:value-of select="not(get:step('configure', $build))"/>
</xsl:template>

<!--
    Returns true if this a gui build.
-->
<xsl:template name="is-gui">
    <xsl:param name="content"/>
    <xsl:param name="build" select="get:build()"/>
    <xsl:variable name="make"><get name="make" build="{$build}"/></xsl:variable>
    <xsl:variable name="configure"><xsl:apply-templates select="get:step('configure', $build)"/></xsl:variable>
    <xsl:value-of select="not(contains($make, 'USE_GUI=0') or contains($configure, '--disable-gui'))"/>
</xsl:template>

<!--
    Returns true if the branch we're building has a contrib subdirectory.
-->
<xsl:template name="has-contrib">
    <xsl:param name="content"/>
    <xsl:param name="build" select="get:build()"/>
    <xsl:variable name="checkout"><xsl:apply-templates select="get:step('checkout', $build)"/></xsl:variable>
    <xsl:value-of select="contains($checkout, 'WX_2_') and not(contains($checkout, 'WX_2_9_'))"/>
</xsl:template>

<!--
    Returns true if the build should build the test suite.
-->
<xsl:template name="has-tests">
    <xsl:param name="content"/>
    <xsl:param name="build" select="get:build()"/>
    <xsl:variable name="configure"><xsl:apply-templates select="get:step('configure', $build)"/></xsl:variable>
    <xsl:value-of select="get:step('run-tests', $build) or contains($configure, '--host=')"/>
</xsl:template>

<!--
    strip - strips leading and trailing whitespace

    Usage: <strip>
               foobar
           </strip>

    Converts to text and strips leading and trailing whitespace.
-->
<xsl:template name="strip">
    <xsl:param name="content"/>
    <xsl:variable name="len" select="string-length($content)"/>
    <xsl:variable name="norm" select="normalize-space($content)"/>
    <xsl:variable name="normlen" select="string-length($norm)"/>
    <xsl:choose>
        <xsl:when test="substring($content, 1, 1) != substring($norm, 1, 1)">
            <xsl:call-template name="strip">
                <xsl:with-param name="content" select="substring($content, 2)"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:when test="substring($content, $len, 1) != substring($norm, $normlen, 1)">
            <xsl:call-template name="strip">
                <xsl:with-param name="content" select="substring($content, 1, $len - 1)"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$content"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<!--
    normalize-space - normalises whitespace.

    Usage: <normalize-space>
               foobar
           </normalize-space>

    Converts to text, strips leading and trailing whitespace and replaces
    sequences of whitespace characters by a single space.
-->
<xsl:template name="normalize-space">
    <xsl:param name="content"/>
    <xsl:value-of select="normalize-space($content)"/>
</xsl:template>

<!--
    lower-case - converts to lower case.

    Usage: <lower-case>FooBar</lower-case>
-->
<xsl:template name="lower-case">
    <xsl:param name="content"/>
    <xsl:variable name="lower">abcdefghijklmnopqrstuvwxyz</xsl:variable>
    <xsl:variable name="upper">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>
    <xsl:value-of select="translate($content, $upper, $lower)"/>
</xsl:template>

<!--
    Helpers to convert between day numbers and names.
-->
<xsl:template name="day-number">
    <xsl:param name="content"/>
    <xsl:param name="name"/>
    <xsl:choose>
        <xsl:when test="$name = 'monday'">0</xsl:when>
        <xsl:when test="$name = 'tuesday'">1</xsl:when>
        <xsl:when test="$name = 'wednesday'">2</xsl:when>
        <xsl:when test="$name = 'thursday'">3</xsl:when>
        <xsl:when test="$name = 'friday'">4</xsl:when>
        <xsl:when test="$name = 'saturday'">5</xsl:when>
        <xsl:when test="$name = 'sunday'">6</xsl:when>
    </xsl:choose>
</xsl:template>

<xsl:template name="day-name">
    <xsl:param name="content"/>
    <xsl:param name="number"/>
    <xsl:choose>
        <xsl:when test="$number = '0'">monday</xsl:when>
        <xsl:when test="$number = '1'">tuesday</xsl:when>
        <xsl:when test="$number = '2'">wednesday</xsl:when>
        <xsl:when test="$number = '3'">thursday</xsl:when>
        <xsl:when test="$number = '4'">friday</xsl:when>
        <xsl:when test="$number = '5'">saturday</xsl:when>
        <xsl:when test="$number = '6'">sunday</xsl:when>
    </xsl:choose>
</xsl:template>

<!--
    Helpers to convert between time in the format 'hhmm' and an integer
    count of the minutes since midnight.
-->
<xsl:template name="time-minutes">
    <xsl:param name="content"/>
    <xsl:param name="hhmm"/>
    <xsl:if test="string-length($hhmm) = 4 and format-number($hhmm, '0000') = $hhmm">
        <xsl:variable name="hour" select="substring($hhmm, 1, 2)"/>
        <xsl:variable name="min" select="substring($hhmm, 3, 2)"/>
        <xsl:if test="$hour >= 0 and $hour &lt; 24 and $min >= 0 and $min &lt; 60">
            <xsl:value-of select="$hour * 60 + $min"/>
        </xsl:if>
    </xsl:if>
</xsl:template>

<xsl:template name="time-hhmm">
    <xsl:param name="content"/>
    <xsl:param name="minutes"/>
    <xsl:value-of select="format-number(floor($minutes div 60) * 100 + $minutes mod 60, '0000')"/>
</xsl:template>

<!--
    Create schedulers.
-->
<xsl:template name="nightly-schedulers">
    <xsl:param name="content"/>
    <xsl:param name="name"/>
    <xsl:param name="day"><day-number name="{$name}"/></xsl:param>
    <xsl:param name="hour" select="0"/>
    <xsl:param name="minute" select="0"/>
    <xsl:param name="step" select="30"/>

    <xsl:if test="$hour &lt; 24">
        <nightly>
            <name>
                <xsl:value-of select="concat($name, '_', format-number($hour, '00'), format-number($minute, '00'))"/>
            </name>
            <hour>
                <xsl:value-of select="$hour"/>
            </hour>
            <minute>
                <xsl:value-of select="$minute"/>
            </minute>
            <xsl:if test="$day != ''">
                <dayOfWeek>
                    <xsl:value-of select="$day"/>
                </dayOfWeek>
            </xsl:if>
        </nightly>
        <xsl:variable name="next" select="$hour * 60 + $minute + $step"/>
        <xsl:call-template name="nightly-schedulers">
            <xsl:with-param name="name" select="$name"/>
            <xsl:with-param name="day" select="$day"/>
            <xsl:with-param name="hour" select="floor($next div 60)"/>
            <xsl:with-param name="minute" select="$next mod 60"/>
            <xsl:with-param name="step" select="$step"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

<!--
    scheduler - provide default for the <scheduler> build element.
-->
<xsl:template name="scheduler">
    <xsl:param name="content"/>
    <xsl:param name="previous" select="get:property('scheduler', get:preceding-builds()[last()])"/>
    <xsl:param name="step" select="60"/>

    <xsl:choose>
        <xsl:when test="exsl:node-set($content)/node()">
            <scheduler>
                <xsl:copy-of select="$content"/>
            </scheduler>
        </xsl:when>
        <xsl:otherwise>
            <xsl:for-each select="$previous">
                <xsl:variable name="text">
                    <xsl:apply-templates select="."/>
                </xsl:variable>
                <scheduler>
                    <scheduler-subst text="{$text}" step="{$step}"/>
                </scheduler>
            </xsl:for-each>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template name="scheduler-subst">
    <xsl:param name="content"/>
    <xsl:param name="text"/>
    <xsl:param name="step"/>

    <xsl:variable name="name" select="substring-before($text, '_')"/>
    <xsl:variable name="hhmm" select="substring-after($text, '_')"/>
    <xsl:variable name="day"><day-number name="{$name}"/></xsl:variable>
    <xsl:variable name="mins"><time-minutes hhmm="{$hhmm}"/></xsl:variable>

    <xsl:choose>
        <xsl:when test="$mins = ''">
            <xsl:value-of select="$text"/>
        </xsl:when>
        <xsl:when test="$day = ''">
            <xsl:value-of select="$name"/>
            <xsl:text>_</xsl:text>
            <time-hhmm minutes="{$mins + $step}"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:variable name="day-mins" select="24 * 60"/>
            <xsl:variable name="week-mins" select="7 * $day-mins"/>
            <xsl:variable name="tmp" select="($day + 1) * $day-mins + $mins"/>
            <xsl:variable name="next" select="$tmp mod $week-mins + floor($tmp div $week-mins) * $step"/>
            <day-name number="{floor($next div $day-mins)}"/>
            <xsl:text>_</xsl:text>
            <time-hhmm minutes="{$next mod $day-mins}"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<!--
    email - substitute '@' for ' -at- ' in email addresses.
-->
<xsl:template name="emailfield">
    <xsl:param name="content"/>
    <xsl:param name="addr"/>
    <xsl:variable name="at"> -at- </xsl:variable>
    <xsl:choose>
        <xsl:when test="contains($addr, $at)">
            <xsl:value-of select="substring-before($addr, $at)"/>
            <xsl:text>@</xsl:text>
            <xsl:value-of select="substring-after($addr, $at)"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$addr"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template name="email">
    <xsl:param name="content"/>
    <xsl:param name="id"/>
    <email id="{$id}"><emailfield addr="{$content}"/></email>
</xsl:template>

<xsl:template name="fromaddr">
    <xsl:param name="content"/>
    <fromaddr><emailfield addr="{$content}"/></fromaddr>
</xsl:template>

<xsl:template name="extraRecipient">
    <xsl:param name="content"/>
    <extraRecipient><emailfield addr="{$content}"/></extraRecipient>
</xsl:template>

<!--
    mailnotifier - add a default value for <fromaddr> to <mailnotifier>
-->
<xsl:template name="mailnotifier">
    <xsl:param name="content"/>
    <mailnotifier>
        <defaults content="{$content}">
            <fromaddr>noreply -at- wxsite.net</fromaddr>
        </defaults>
        <xsl:copy-of select="$content"/>
    </mailnotifier>
</xsl:template>

</bot>
