<?xml version="1.0" encoding="UTF-8"?>
<!-- TODO
  
* add support for atoms
  - similar mechanism to elements, since they must also be
    self-contained, but complex stuff around overlap because
    they count as content
  
* add datatype support
  - buffer text to test against specified datatype

-->
<xsl:stylesheet version="2.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns:test="http://www.jenitennison.com/xslt/unit-test"
                exclude-result-prefixes="xs test"
                xmlns:pat="http://www.lmnl.org/schema/pattern"
                xmlns:mem="http://www.lmnl.org/schema/pattern/memo"
                xmlns:ev="http://www.lmnl.org/event">
  
<xsl:import href="compile-creole.xsl" />  
  
<xsl:function name="pat:valid" as="xs:boolean">
  <xsl:param name="events" as="element()*" />
  <xsl:param name="patterns" as="element()+" />
  <xsl:variable name="validated" as="element()+" 
    select="pat:validate($events, $patterns)" />
  <xsl:if test="not(pat:nullable($validated))">
    <xsl:message>
      final pattern: <xsl:value-of select="$patterns[1]/@name" />
      grammar: <xsl:copy-of select="$patterns" copy-namespaces="no" />
    </xsl:message>
  </xsl:if>
  <xsl:sequence select="pat:nullable($validated)" />
</xsl:function>  
  
<xsl:function name="pat:validate" as="element()+">
  <xsl:param name="events" as="element()*" />
  <xsl:param name="patterns" as="element()+" />
  <xsl:choose>
    <xsl:when test="empty($events)">
      <xsl:sequence select="$patterns" />
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="deriv" as="element()+" 
        select="pat:derivative($events[1], $patterns)" />
        <!--
      <xsl:message>
        event:   <xsl:copy-of select="$events[1]" copy-namespaces="no" />
        pattern: <xsl:copy-of select="$patterns[1]" copy-namespaces="no" />
        deriv:   <xsl:copy-of select="$deriv[1]" copy-namespaces="no" />
        grammar: <xsl:copy-of select="$deriv" copy-namespaces="no" />
      </xsl:message>
        -->
      <xsl:choose>
        <xsl:when test="$deriv[1]/@name = '#notAllowed'">          
          <xsl:message>
            validation error occured at event:
            event:   <xsl:copy-of select="$events[1]" copy-namespaces="no" />
            pattern: <xsl:value-of select="$patterns[1]/@name" />
            deriv:   <xsl:value-of select="$deriv[1]/@name" />
            grammar: <xsl:copy-of select="$deriv" copy-namespaces="no" />
          </xsl:message>
          <xsl:sequence select="$deriv" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:sequence select="pat:validate($events[position() > 1], $deriv)" />
        </xsl:otherwise>
      </xsl:choose>      
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>  

<!-- *** pat:derivative() *** -->  
  
<xsl:function name="pat:derivative" as="element()+">
  <xsl:param name="event" as="element()" />
  <xsl:param name="name" as="xs:string" />
  <xsl:param name="patterns" as="element()+" />
  <xsl:variable name="pattern" as="element()" select="pat:pattern($name, $patterns)" />
  <xsl:sequence select="pat:derivative($event, ($pattern, $patterns except $pattern))" />
</xsl:function>  
  
<xsl:function name="pat:derivative" as="element()+">
  <xsl:param name="event" as="element()" />
  <xsl:param name="patterns" as="element()+" />
  <xsl:apply-templates select="$event" mode="pat:derivative">
    <xsl:with-param name="patterns" select="$patterns" />
  </xsl:apply-templates>
</xsl:function>  
  
<!-- ** Event-based derivatives ** -->  
  
<xsl:template match="ev:text" mode="pat:derivative" as="element()+">
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:choose>
    <xsl:when test="not(pat:allows-text($patterns))">
      <xsl:choose>
        <xsl:when test="@ws = 'true'">
          <xsl:sequence select="$patterns" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:variable name="notAllowed" as="element()" select="$patterns[@name = '#notAllowed']" />
          <xsl:sequence select="$notAllowed, $patterns except $notAllowed" />
        </xsl:otherwise>
      </xsl:choose>      
    </xsl:when>
    <xsl:otherwise>
      <xsl:apply-templates select="$patterns[1]" mode="pat:text-derivative">
        <xsl:with-param name="event" select="." />
        <xsl:with-param name="patterns" select="$patterns" />
      </xsl:apply-templates>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
  
<xsl:template match="ev:start-tag" mode="pat:derivative" as="element()+">
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:apply-templates select="$patterns[1]" mode="pat:start-tag-derivative">
    <xsl:with-param name="event" select="." />
    <xsl:with-param name="patterns" select="$patterns" />
  </xsl:apply-templates>
</xsl:template>
  
<xsl:template match="ev:end-end-tag" mode="pat:derivative" as="element()+">
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:apply-templates select="$patterns[1]" mode="pat:end-tag-derivative">
    <xsl:with-param name="event" select="." />
    <xsl:with-param name="patterns" select="$patterns" />
  </xsl:apply-templates>
</xsl:template>
  
<xsl:template match="ev:start-element" mode="pat:derivative" as="element()+">
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:apply-templates select="$patterns[1]" mode="pat:start-element-derivative">
    <xsl:with-param name="event" select="." />
    <xsl:with-param name="patterns" select="$patterns" />
  </xsl:apply-templates>
</xsl:template>  
  
<xsl:template match="ev:start-range" mode="pat:derivative" as="element()+">
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:apply-templates select="$patterns[1]" mode="pat:start-range-derivative">
    <xsl:with-param name="event" select="." />
    <xsl:with-param name="patterns" select="$patterns" />
  </xsl:apply-templates>
</xsl:template>  
  
<xsl:template match="ev:start-annotation" mode="pat:derivative" as="element()+">
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:apply-templates select="$patterns[1]" mode="pat:start-annotation-derivative">
    <xsl:with-param name="event" select="." />
    <xsl:with-param name="patterns" select="$patterns" />
  </xsl:apply-templates>
</xsl:template>  
  
<xsl:template match="ev:end-end-annotation" mode="pat:derivative" as="element()+">
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:apply-templates select="$patterns[1]" mode="pat:end-annotation-derivative">
    <xsl:with-param name="event" select="." />
    <xsl:with-param name="patterns" select="$patterns" />
  </xsl:apply-templates>
</xsl:template>  
  
<!-- ignore other kinds of events -->
<xsl:template match="ev:*" mode="pat:derivative" as="element()+">
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:sequence select="$patterns" />
</xsl:template>
  
<!-- ** Pattern-based derivatives ** -->  

<test:tests>
  <test:title>Validating Defines</test:title>
  <test:test>
    <test:title>Text against text</test:title>
    <test:context select="$pat:text" />
    <test:param name="event">
      <ev:text chars="..." ws="false" hash="text(false)" />
    </test:param>
    <test:param name="patterns" select="$pat:text, $pat:empty, $pat:notAllowed" />
    <test:expect>
      <pat:define name="#text" hash="#text" nullable="true" allows-text="true">
        <pat:text />
        <mem:deriv event="text(false)" pattern="#text" />
      </pat:define>
      <pat:define name="#empty" hash="#empty" nullable="true" allows-text="false">
        <pat:empty />
      </pat:define>
      <pat:define name="#notAllowed" hash="#notAllowed" nullable="false" allows-text="false">
        <pat:notAllowed />
      </pat:define>
    </test:expect>
  </test:test>
  <test:test>
    <test:title>Start tag against element</test:title>
    <test:context>
      <pat:define name="d33e0" hash="element d32e0 {#text}" nullable="false" allows-text="false">
        <pat:element>
          <pat:ref name="d32e0"/>
          <pat:ref name="#text"/>
        </pat:element>
      </pat:define>
    </test:context>
    <test:param name="event">
      <ev:start-tag ns="" name="foo" hash="start-tag('','foo','')" />            
    </test:param>
    <test:param name="patterns">
      <pat:define name="#notAllowed" hash="#notAllowed" nullable="false" allows-text="false">
        <pat:notAllowed/>
      </pat:define>
      <pat:define name="#empty" hash="#empty" nullable="true" allows-text="false">
        <pat:empty/>
      </pat:define>
      <pat:define name="#text" hash="#text" nullable="true" allows-text="true">
        <pat:text/>
      </pat:define>
      <pat:define name="d32e0" hash="{}foo" nullable="false" allows-text="false">
        <pat:name name="foo" ns=""/>
      </pat:define>
      <pat:define name="d36e3" hash="(#text,d36e0)" nullable="false" allows-text="true">
        <pat:group>
          <pat:ref name="#text"/>
          <pat:ref name="d36e0"/>
        </pat:group>
      </pat:define>
      <pat:define name="d36e0" hash="end-tag d32e0=" nullable="false" allows-text="false">
        <pat:end-tag id="">
          <pat:ref name="d32e0"/>
        </pat:end-tag>
      </pat:define>
      <pat:define name="d38e0" hash="after{d36e3,#empty}" nullable="false" allows-text="true">
        <pat:after>
          <pat:ref name="d36e3"/>
          <pat:ref name="#empty"/>
        </pat:after>
      </pat:define>
      <pat:define name="d33e0" hash="element d32e0 {#text}" nullable="false" allows-text="false">
        <pat:element>
          <pat:ref name="d32e0"/>
          <pat:ref name="#text"/>
        </pat:element>
      </pat:define>
    </test:param>
    <test:expect>
      <pat:define name="d38e0" hash="after{d36e3,#empty}" nullable="false" allows-text="true">
        <pat:after>
          <pat:ref name="d36e3"/>
          <pat:ref name="#empty"/>
        </pat:after>
      </pat:define>
      <pat:define name="#notAllowed" hash="#notAllowed" nullable="false" allows-text="false">
        <pat:notAllowed/>
      </pat:define>
      <pat:define name="#empty" hash="#empty" nullable="true" allows-text="false">
        <pat:empty/>
      </pat:define>
      <pat:define name="#text" hash="#text" nullable="true" allows-text="true">
        <pat:text/>
      </pat:define>
      <pat:define name="d32e0" hash="{}foo" nullable="false" allows-text="false">
        <pat:name name="foo" ns=""/>
      </pat:define>
      <pat:define name="d36e3" hash="(#text,d36e0)" nullable="false" allows-text="true">
        <pat:group>
          <pat:ref name="#text"/>
          <pat:ref name="d36e0"/>
        </pat:group>
      </pat:define>
      <pat:define name="d36e0" hash="end-tag d32e0=" nullable="false" allows-text="false">
        <pat:end-tag id="">
          <pat:ref name="d32e0"/>
        </pat:end-tag>
      </pat:define>
      <pat:define name="d33e0" hash="element d32e0 {#text}" nullable="false" allows-text="false">
        <pat:element>
          <pat:ref name="d32e0"/>
          <pat:ref name="#text"/>
        </pat:element>
        <mem:deriv xmlns:mem="http://www.lmnl.org/schema/pattern/memo"
          event="start-tag('','foo','')" pattern="d38e0"/>
      </pat:define>
    </test:expect>
  </test:test>
</test:tests>
<xsl:template match="pat:define" as="element()+"
              mode="pat:text-derivative
                    pat:start-tag-derivative 
                    pat:end-tag-derivative
                    pat:start-element-derivative
                    pat:start-range-derivative
                    pat:start-annotation-derivative
                    pat:end-annotation-derivative">
  <xsl:param name="event" as="element()" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:variable name="mem-deriv" as="element(mem:deriv)?" 
    select="mem:deriv[@event = $event/@hash]" />
  <xsl:choose>
    <xsl:when test="exists($mem-deriv)">
      <xsl:variable name="deriv" as="element()" select="pat:pattern($mem-deriv/@pattern, $patterns)" />
      <xsl:sequence select="$deriv, $patterns except $deriv" />
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="deriv" as="element()+">
        <xsl:apply-templates select="pat:*[1]" mode="#current">
          <xsl:with-param name="event" select="$event" />
          <xsl:with-param name="patterns" select="$patterns" />
        </xsl:apply-templates>
      </xsl:variable>
      <xsl:variable name="new-define" as="element()">
        <pat:define>
          <xsl:copy-of select="@*" />
          <xsl:copy-of select="pat:*" />
          <xsl:copy-of select="mem:*" />
          <mem:deriv event="{$event/@hash}" pattern="{$deriv[1]/@name}" />
        </pat:define>
      </xsl:variable>

      <xsl:choose>
        <xsl:when test="$deriv[1]/@name = @name">
          <xsl:sequence select="$new-define, $deriv[position() > 1]" />          
        </xsl:when>
        <xsl:otherwise>
          <xsl:sequence select="$deriv[1], $deriv[position() > 1][@name != current()/@name], $new-define" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>  
  
<xsl:template match="pat:ref" as="element()+"
              mode="pat:text-derivative
                    pat:start-tag-derivative 
                    pat:end-tag-derivative
                    pat:start-element-derivative
                    pat:start-range-derivative
                    pat:start-annotation-derivative
                    pat:end-annotation-derivative">
  <xsl:param name="event" as="element()" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:apply-templates select="pat:pattern(@name, $patterns)" mode="#current">
    <xsl:with-param name="event" select="$event" />
    <xsl:with-param name="patterns" select="$patterns" />
  </xsl:apply-templates>
</xsl:template>  
  
<!-- *** Generic behaviour for constructs *** -->  
  
<xsl:template match="pat:choice" as="element()+" 
              mode="pat:text-derivative
                    pat:start-tag-derivative 
                    pat:end-tag-derivative
                    pat:start-element-derivative
                    pat:start-range-derivative
                    pat:start-annotation-derivative
                    pat:end-annotation-derivative">
  <xsl:param name="event" as="element()" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:variable name="deriv1" as="element()+"
    select="pat:derivative($event, pat:ref[1]/@name, $patterns)" />
  <xsl:variable name="deriv2" as="element()+"
    select="pat:derivative($event, pat:ref[2]/@name, $deriv1)" />
  <xsl:call-template name="pat:choice">
    <xsl:with-param name="pattern1" select="$deriv1[1]/@name" />
    <xsl:with-param name="pattern2" select="$deriv2[1]/@name" />
    <xsl:with-param name="patterns" select="$deriv2" />
  </xsl:call-template>
</xsl:template>  
  
<xsl:template match="pat:group | pat:after" as="element()+" 
              mode="pat:text-derivative
                    pat:end-tag-derivative
                    pat:start-range-derivative
                    pat:end-annotation-derivative">
  <xsl:param name="event" as="element()" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  
  <xsl:variable name="deriv1" as="element()+"
    select="pat:derivative($event, pat:ref[1]/@name, $patterns)" />  
  <xsl:variable name="group" as="element()+">
    <xsl:choose>
      <xsl:when test="self::pat:group">
        <xsl:call-template name="pat:group">
          <xsl:with-param name="pattern1" select="$deriv1[1]/@name" />
          <xsl:with-param name="pattern2" select="pat:ref[2]/@name" /> 
          <xsl:with-param name="patterns" select="$deriv1" />
        </xsl:call-template>
      </xsl:when>
      <xsl:when test="self::pat:after">
        <xsl:call-template name="pat:after">
          <xsl:with-param name="pattern1" select="$deriv1[1]/@name" />
          <xsl:with-param name="pattern2" select="pat:ref[2]/@name" /> 
          <xsl:with-param name="patterns" select="$deriv1" />
        </xsl:call-template>
      </xsl:when>
    </xsl:choose>
  </xsl:variable>
  
  <xsl:choose>
    <xsl:when test="pat:nullable(pat:ref[1], $deriv1)">
      <xsl:variable name="deriv2" as="element()+"
        select="pat:derivative($event, pat:ref[2]/@name, $group)" />      
      <xsl:call-template name="pat:choice">
        <xsl:with-param name="pattern1" select="$group[1]/@name" />
        <xsl:with-param name="pattern2" select="$deriv2[1]/@name" />
        <xsl:with-param name="patterns" select="$deriv2" />
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="$group" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="pat:interleave" as="element()+" 
              mode="pat:text-derivative
                    pat:end-tag-derivative
                    pat:start-range-derivative
                    pat:end-annotation-derivative">
  <xsl:param name="event" as="element()" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />

  <xsl:variable name="deriv1" as="element()+"
    select="pat:derivative($event, pat:ref[1]/@name, $patterns)" />
  <xsl:variable name="interleave1" as="element()+">
    <xsl:call-template name="pat:interleave">
      <xsl:with-param name="pattern1" select="$deriv1[1]/@name" />
      <xsl:with-param name="pattern2" select="pat:ref[2]/@name" /> 
      <xsl:with-param name="patterns" select="$deriv1" />
    </xsl:call-template>
  </xsl:variable>
      
  <xsl:variable name="deriv2" as="element()+"
    select="pat:derivative($event, pat:ref[2]/@name, $interleave1)" />
  <xsl:variable name="interleave2" as="element()+">
    <xsl:call-template name="pat:interleave">
      <xsl:with-param name="pattern1" select="pat:ref[1]/@name" />
      <xsl:with-param name="pattern2" select="$deriv2[1]/@name" /> 
      <xsl:with-param name="patterns" select="$deriv2" />
    </xsl:call-template>
  </xsl:variable>
  
  <xsl:call-template name="pat:choice">
    <xsl:with-param name="pattern1" select="$interleave1[1]/@name" />
    <xsl:with-param name="pattern2" select="$interleave2[1]/@name" />
    <xsl:with-param name="patterns" select="$interleave2" />
  </xsl:call-template>
</xsl:template>  
  
<xsl:template match="pat:overlap" as="element()+" 
              mode="pat:end-tag-derivative
                    pat:start-range-derivative
                    pat:end-annotation-derivative">
  <xsl:param name="event" as="element()" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />

  <xsl:variable name="deriv1" as="element()+"
    select="pat:derivative($event, pat:ref[1]/@name, $patterns)" />
  <xsl:variable name="overlap1" as="element()+">
    <xsl:call-template name="pat:overlap">
      <xsl:with-param name="pattern1" select="$deriv1[1]/@name" />
      <xsl:with-param name="pattern2" select="pat:ref[2]/@name" /> 
      <xsl:with-param name="patterns" select="$deriv1" />
    </xsl:call-template>
  </xsl:variable>
      
  <xsl:variable name="deriv2" as="element()+"
    select="pat:derivative($event, pat:ref[2]/@name, $overlap1)" />
  <xsl:variable name="overlap2" as="element()+">
    <xsl:call-template name="pat:overlap">
      <xsl:with-param name="pattern1" select="pat:ref[1]/@name" />
      <xsl:with-param name="pattern2" select="$deriv2[1]/@name" /> 
      <xsl:with-param name="patterns" select="$deriv2" />
    </xsl:call-template>
  </xsl:variable>
  
  <xsl:variable name="either" as="element()+">
    <xsl:call-template name="pat:choice">
      <xsl:with-param name="pattern1" select="$overlap1[1]/@name" />
      <xsl:with-param name="pattern2" select="$overlap2[1]/@name" />
      <xsl:with-param name="patterns" select="$overlap2" />
    </xsl:call-template>
  </xsl:variable>
  <xsl:sequence select="$either" />
</xsl:template>  

<xsl:template match="pat:overlap" as="element()+" 
              mode="pat:text-derivative">
  <xsl:param name="event" as="element()" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />

  <xsl:variable name="deriv1" as="element()+"
    select="pat:derivative($event, pat:ref[1]/@name, $patterns)" />
      
  <xsl:variable name="deriv2" as="element()+"
    select="pat:derivative($event, pat:ref[2]/@name, $deriv1)" />
  
  <xsl:call-template name="pat:overlap">
    <xsl:with-param name="pattern1" select="$deriv1[1]/@name" />
    <xsl:with-param name="pattern2" select="$deriv2[1]/@name" />
    <xsl:with-param name="patterns" select="$deriv2" />
  </xsl:call-template>
</xsl:template>
  
<xsl:template match="pat:oneOrMore" as="element()+"
              mode="pat:text-derivative
                    pat:end-tag-derivative
                    pat:start-range-derivative
                    pat:end-annotation-derivative">
  <xsl:param name="event" as="element()" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:variable name="deriv" as="element()+"
    select="pat:derivative($event, pat:ref[1]/@name, $patterns)" />
  <xsl:variable name="choice" as="element()+">
    <xsl:call-template name="pat:choice">
      <xsl:with-param name="pattern1" select="parent::pat:define/@name" />
      <xsl:with-param name="pattern2" select="'#empty'" />
      <xsl:with-param name="patterns" select="$deriv" />
    </xsl:call-template>
  </xsl:variable>
  <xsl:call-template name="pat:group">
    <xsl:with-param name="pattern1" select="$deriv[1]/@name" />
    <xsl:with-param name="pattern2" select="$choice[1]/@name" />
    <xsl:with-param name="patterns" select="$choice" />    
  </xsl:call-template>
</xsl:template>  

<xsl:template match="pat:overlapOneOrMore" as="element()+"
              mode="pat:text-derivative
                    pat:end-tag-derivative
                    pat:start-range-derivative
                    pat:end-annotation-derivative">
  <xsl:param name="event" as="element()" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:variable name="deriv" as="element()+"
    select="pat:derivative($event, pat:ref[1]/@name, $patterns)" />
  <xsl:variable name="choice" as="element()+">
    <xsl:call-template name="pat:choice">
      <xsl:with-param name="pattern1" select="parent::pat:define/@name" />
      <xsl:with-param name="pattern2" select="'#text'" />
      <xsl:with-param name="patterns" select="$deriv" />
    </xsl:call-template>
  </xsl:variable>
  <xsl:call-template name="pat:overlap">
    <xsl:with-param name="pattern1" select="$deriv[1]/@name" />
    <xsl:with-param name="pattern2" select="$choice[1]/@name" />
    <xsl:with-param name="patterns" select="$choice" />    
  </xsl:call-template>
</xsl:template>  
  
<xsl:template match="pat:empty | pat:notAllowed" as="element()+"
              mode="pat:text-derivative
                    pat:start-tag-derivative
                    pat:start-element-derivative
                    pat:start-range-derivative
                    pat:end-tag-derivative
                    pat:end-annotation-derivative">
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:variable name="notAllowed" as="element()" select="$patterns[@name = '#notAllowed']" />
  <xsl:sequence select="$notAllowed, $patterns except $notAllowed" />
</xsl:template>  
  
<!-- *** pat:start-element-derivative mode *** -->
  
<xsl:template match="pat:group" as="element()+"
              mode="pat:start-element-derivative">
  <xsl:param name="event" as="element()" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:variable name="deriv" as="element()+"
    select="pat:derivative($event, pat:ref[1]/@name, $patterns)" />  
  <xsl:variable name="after" as="element()+">
    <xsl:call-template name="pat:apply-after">
      <xsl:with-param name="construct" select="'group'" />
      <xsl:with-param name="arg2" select="pat:ref[2]/@name" /> 
      <xsl:with-param name="pattern" select="$deriv[1]/@name" />
      <xsl:with-param name="patterns" select="$deriv" />
    </xsl:call-template>
  </xsl:variable>
  <xsl:choose>
    <xsl:when test="pat:nullable(pat:ref[1], $after)">
      <xsl:variable name="deriv2" as="element()+"
        select="pat:derivative($event, pat:ref[2]/@name, $after)" />      
      <xsl:call-template name="pat:choice">
        <xsl:with-param name="pattern1" select="$deriv[1]/@name" />
        <xsl:with-param name="pattern2" select="$after[1]/@name" />
        <xsl:with-param name="patterns" select="$after" />
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="$after" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
  
<xsl:template match="pat:interleave" as="element()+" 
              mode="pat:start-element-derivative
                    pat:start-annotation-derivative">
  <xsl:param name="event" as="element()" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />

  <xsl:variable name="deriv1" as="element()+"
    select="pat:derivative($event, pat:ref[1]/@name, $patterns)" />
  <xsl:variable name="after1" as="element()+">
    <xsl:call-template name="pat:apply-after">
      <xsl:with-param name="construct" select="'interleave'" />
      <xsl:with-param name="pattern" select="$deriv1[1]/@name" />
      <xsl:with-param name="arg2" select="pat:ref[2]/@name" /> 
      <xsl:with-param name="patterns" select="$deriv1" />
    </xsl:call-template>
  </xsl:variable>
      
  <xsl:variable name="deriv2" as="element()+"
    select="pat:derivative($event, pat:ref[2]/@name, $after1)" />
  <xsl:variable name="after2" as="element()+">
    <xsl:call-template name="pat:apply-after">
      <xsl:with-param name="construct" select="'interleave'" />
      <xsl:with-param name="arg1" select="pat:ref[1]/@name" />
      <xsl:with-param name="pattern" select="$deriv2[1]/@name" /> 
      <xsl:with-param name="patterns" select="$deriv2" />
    </xsl:call-template>
  </xsl:variable>
  
  <xsl:call-template name="pat:choice">
    <xsl:with-param name="pattern1" select="$after1[1]/@name" />
    <xsl:with-param name="pattern2" select="$after2[1]/@name" />
    <xsl:with-param name="patterns" select="$after2" />
  </xsl:call-template>
</xsl:template>  
  
<xsl:template match="pat:overlap" as="element()+" 
              mode="pat:start-element-derivative
                    pat:start-annotation-derivative">
  <xsl:param name="event" as="element()" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />

  <xsl:variable name="deriv1" as="element()+"
    select="pat:derivative($event, pat:ref[1]/@name, $patterns)" />
  <xsl:variable name="after1" as="element()+">
    <xsl:call-template name="pat:apply-after">
      <xsl:with-param name="construct" select="'overlap'" />
      <xsl:with-param name="pattern" select="$deriv1[1]/@name" />
      <xsl:with-param name="arg2" select="pat:ref[2]/@name" /> 
      <xsl:with-param name="patterns" select="$deriv1" />
    </xsl:call-template>
  </xsl:variable>
      
  <xsl:variable name="deriv2" as="element()+"
    select="pat:derivative($event, pat:ref[2]/@name, $after1)" />
  <xsl:variable name="after2" as="element()+">
    <xsl:call-template name="pat:apply-after">
      <xsl:with-param name="construct" select="'overlap'" />
      <xsl:with-param name="arg1" select="pat:ref[1]/@name" />
      <xsl:with-param name="pattern" select="$deriv2[1]/@name" /> 
      <xsl:with-param name="patterns" select="$deriv2" />
    </xsl:call-template>
  </xsl:variable>
    
  <xsl:variable name="either" as="element()+">
    <xsl:call-template name="pat:choice">
      <xsl:with-param name="pattern1" select="$after1[1]/@name" />
      <xsl:with-param name="pattern2" select="$after2[1]/@name" />
      <xsl:with-param name="patterns" select="$after2" />
    </xsl:call-template>
  </xsl:variable>
  <xsl:sequence select="$either" />
</xsl:template>  
  
<xsl:template match="pat:oneOrMore" as="element()+"
              mode="pat:start-element-derivative
                    pat:start-annotation-derivative">
  <xsl:param name="event" as="element()" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:variable name="deriv" as="element()+"
    select="pat:derivative($event, pat:ref[1]/@name, $patterns)" />
  <xsl:variable name="choice" as="element()+">
    <xsl:call-template name="pat:choice">
      <xsl:with-param name="pattern1" select="parent::pat:define/@name" />
      <xsl:with-param name="pattern2" select="'#empty'" />
      <xsl:with-param name="patterns" select="$deriv" />
    </xsl:call-template>
  </xsl:variable>
  <xsl:call-template name="pat:apply-after">
    <xsl:with-param name="construct" select="'group'" />
    <xsl:with-param name="arg2" select="$choice[1]/@name" />
    <xsl:with-param name="pattern" select="$deriv[1]/@name" />
    <xsl:with-param name="patterns" select="$choice" />
  </xsl:call-template>
</xsl:template>
  
<xsl:template match="pat:overlapOneOrMore" as="element()+"
              mode="pat:start-element-derivative
                    pat:start-annotation-derivative">
  <xsl:param name="event" as="element()" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:variable name="deriv" as="element()+"
    select="pat:derivative($event, pat:ref[1]/@name, $patterns)" />
  <xsl:variable name="choice" as="element()+">
    <xsl:call-template name="pat:choice">
      <xsl:with-param name="pattern1" select="parent::pat:define/@name" />
      <xsl:with-param name="pattern2" select="'#text'" />
      <xsl:with-param name="patterns" select="$deriv" />
    </xsl:call-template>
  </xsl:variable>
  <xsl:call-template name="pat:apply-after">
    <xsl:with-param name="construct" select="'overlap'" />
    <xsl:with-param name="arg2" select="$choice[1]/@name" />
    <xsl:with-param name="pattern" select="$deriv[1]/@name" />
    <xsl:with-param name="patterns" select="$choice" />
  </xsl:call-template>
</xsl:template>  
  
<xsl:template match="pat:after" as="element()+"
              mode="pat:start-element-derivative
                    pat:start-annotation-derivative">
  <xsl:param name="event" as="element()" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:variable name="deriv" as="element()+"
    select="pat:derivative($event, pat:ref[1]/@name, $patterns)" />
  <xsl:call-template name="pat:apply-after">
    <xsl:with-param name="construct" select="'after'" />
    <xsl:with-param name="arg2" select="pat:ref[2]/@name" />
    <xsl:with-param name="pattern" select="$deriv[1]/@name" />
    <xsl:with-param name="patterns" select="$deriv" />
  </xsl:call-template>
</xsl:template>
  
<xsl:template match="pat:element" as="element()+" 
              mode="pat:start-element-derivative">
  <xsl:param name="event" as="element()" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:apply-templates select="." mode="pat:start-tag-derivative">
    <xsl:with-param name="event" select="$event" />
    <xsl:with-param name="patterns" select="$patterns" />
  </xsl:apply-templates>
</xsl:template>  
    
<!-- *** pat:start-tag-derivative mode *** -->
  
<xsl:template match="pat:oneOrMore | 
                     pat:overlapOneOrMore |
                     pat:group |
                     pat:interleave |
                     pat:overlap |
                     pat:after" as="element()+"
              mode="pat:start-tag-derivative">
  <xsl:param name="event" as="element()" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:variable name="start-element-event" as="element(ev:start-element)">
    <ev:start-element name="{$event/@name}" id="{$event/@id}"
      hash="start-element('{$event/@ns}','{$event/@name}','{$event/@id}')" />
  </xsl:variable>
  <xsl:variable name="start-range-event" as="element(ev:start-range)">
    <ev:start-range name="{$event/@name}" id="{$event/@id}"
      hash="start-range('{$event/@ns}','{$event/@name}','{$event/@id}')" />
  </xsl:variable>

  <xsl:variable name="deriv1" as="element()+"
    select="pat:derivative($start-element-event, parent::pat:define/@name, $patterns)" />
  <xsl:variable name="deriv2" as="element()+"
    select="pat:derivative($start-range-event, parent::pat:define/@name, $deriv1)" />
  <xsl:call-template name="pat:choice">
    <xsl:with-param name="pattern1" select="$deriv1[1]/@name" />
    <xsl:with-param name="pattern2" select="$deriv2[1]/@name" />
    <xsl:with-param name="patterns" select="$deriv2" />
  </xsl:call-template>
</xsl:template>
  
<xsl:template match="pat:range" as="element()+" mode="pat:start-range-derivative">
  <xsl:param name="event" as="element()" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:apply-templates select="." mode="pat:start-tag-derivative">
    <xsl:with-param name="event" select="$event" />
    <xsl:with-param name="patterns" select="$patterns" />
  </xsl:apply-templates>
</xsl:template>  
  
<test:tests>
  <test:title>Validating Elements</test:title>
  <test:test>
    <test:title>Start tag against element</test:title>
    <test:context>
      <pat:element>
        <pat:ref name="d32e0"/>
        <pat:ref name="#text"/>
      </pat:element>
    </test:context>
    <test:param name="event">
      <ev:start-tag ns="" name="foo" hash="start-tag('','foo','')" />            
    </test:param>
    <test:param name="patterns">
      <pat:define name="#notAllowed" hash="#notAllowed" nullable="false" allows-text="false">
        <pat:notAllowed/>
      </pat:define>
      <pat:define name="#empty" hash="#empty" nullable="true" allows-text="false">
        <pat:empty/>
      </pat:define>
      <pat:define name="#text" hash="#text" nullable="true" allows-text="true">
        <pat:text/>
      </pat:define>
      <pat:define name="d32e0" hash="{}foo" nullable="false" allows-text="false">
        <pat:name name="foo" ns=""/>
      </pat:define>
      <pat:define name="d36e3" hash="(#text,d36e0)" nullable="false" allows-text="true">
        <pat:group>
          <pat:ref name="#text"/>
          <pat:ref name="d36e0"/>
        </pat:group>
      </pat:define>
      <pat:define name="d36e0" hash="end-tag d32e0=" nullable="false" allows-text="false">
        <pat:end-tag id="">
          <pat:ref name="d32e0"/>
        </pat:end-tag>
      </pat:define>
      <pat:define name="d38e0" hash="after{d36e3,#empty}" nullable="false" allows-text="true">
        <pat:after>
          <pat:ref name="d36e3"/>
          <pat:ref name="#empty"/>
        </pat:after>
      </pat:define>
      <pat:define name="d33e0" hash="element d32e0 {#text}" nullable="false" allows-text="false">
        <pat:element>
          <pat:ref name="d32e0"/>
          <pat:ref name="#text"/>
        </pat:element>
      </pat:define>
    </test:param>
    <test:expect>
      <pat:define name="d38e0" hash="after{d36e3,#empty}" nullable="false" allows-text="true">
        <pat:after>
          <pat:ref name="d36e3"/>
          <pat:ref name="#empty"/>
        </pat:after>
      </pat:define>
      <pat:define name="#notAllowed" hash="#notAllowed" nullable="false" allows-text="false">
        <pat:notAllowed/>
      </pat:define>
      <pat:define name="#empty" hash="#empty" nullable="true" allows-text="false">
        <pat:empty/>
      </pat:define>
      <pat:define name="#text" hash="#text" nullable="true" allows-text="true">
        <pat:text/>
      </pat:define>
      <pat:define name="d32e0" hash="{}foo" nullable="false" allows-text="false">
        <pat:name name="foo" ns=""/>
      </pat:define>
      <pat:define name="d36e3" hash="(#text,d36e0)" nullable="false" allows-text="true">
        <pat:group>
          <pat:ref name="#text"/>
          <pat:ref name="d36e0"/>
        </pat:group>
      </pat:define>
      <pat:define name="d36e0" hash="end-tag d32e0=" nullable="false" allows-text="false">
        <pat:end-tag id="">
          <pat:ref name="d32e0"/>
        </pat:end-tag>
      </pat:define>
      <pat:define name="d33e0" hash="element d32e0 {#text}" nullable="false" allows-text="false">
        <pat:element>
          <pat:ref name="d32e0"/>
          <pat:ref name="#text"/>
        </pat:element>
      </pat:define>
    </test:expect>
  </test:test>
</test:tests>
<xsl:template match="pat:element | pat:range" as="element()+" 
              mode="pat:start-tag-derivative">
  <xsl:param name="event" as="element()" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:choose>
    <xsl:when test="pat:contains(pat:ref[1], QName($event/@ns, $event/@name), $patterns)">
      <xsl:variable name="name" as="element()">
        <pat:name name="{$event/@name}" ns="{$event/@ns}" />
      </xsl:variable>      
      <xsl:variable name="end-tag" as="element()">
        <pat:end-tag id="{$event/@id}">
          <xsl:sequence select="$name" />
        </pat:end-tag>
      </xsl:variable>

      <xsl:variable name="compiled-end-tag" as="element()+">
        <xsl:apply-templates select="$end-tag" mode="pat:compile">
          <xsl:with-param name="patterns" select="$patterns" />
        </xsl:apply-templates>
      </xsl:variable>      
      <xsl:variable name="group" as="element()+">
        <xsl:call-template name="pat:group">
          <xsl:with-param name="pattern1" select="pat:ref[2]/@name" />
          <xsl:with-param name="pattern2" select="$compiled-end-tag[1]/@name" />
          <xsl:with-param name="patterns" select="$compiled-end-tag" />
        </xsl:call-template>
      </xsl:variable>
      <xsl:choose>
        <xsl:when test="self::pat:element">
          <xsl:variable name="after" as="element()+">
            <xsl:call-template name="pat:after">
              <xsl:with-param name="pattern1" select="$group[1]/@name" />
              <xsl:with-param name="pattern2" select="'#empty'" />
              <xsl:with-param name="patterns" select="$group" />
            </xsl:call-template>
          </xsl:variable>
          <xsl:sequence select="$after" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:sequence select="$group" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:when>
    <xsl:otherwise>
      <xsl:next-match>
        <xsl:with-param name="event" select="$event" />
        <xsl:with-param name="patterns" select="$patterns" />
      </xsl:next-match>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template> 
  
<xsl:template match="pat:*" as="element()+" 
              mode="pat:start-tag-derivative
                    pat:start-element-derivative
                    pat:start-range-derivative">
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:variable name="notAllowed" as="element()" select="$patterns[@name = '#notAllowed']" />
  <xsl:sequence select="$notAllowed, $patterns except $notAllowed" />
</xsl:template>
  
<!-- *** pat:end-tag-derivative mode *** -->
  
<xsl:template match="pat:end-tag" mode="pat:end-tag-derivative" as="element()+">
  <xsl:param name="event" as="element(ev:end-end-tag)" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:param name="nc" as="element(pat:name)"
    select="pat:pattern(pat:ref[1]/@name, $patterns)/pat:name" />
  <xsl:choose>
    <xsl:when test="$nc/@name eq $event/@name and
                    $nc/@ns eq $event/@ns and
                    @id eq $event/@id">
      <xsl:variable name="empty" as="element()" select="$patterns[@name = '#empty']" />
      <xsl:sequence select="$empty, $patterns except $empty" />
    </xsl:when>
    <xsl:otherwise>
      <xsl:next-match>
        <xsl:with-param name="event" select="$event" />
        <xsl:with-param name="patterns" select="$patterns" />
      </xsl:next-match>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>  
  
<xsl:template match="pat:*" mode="pat:end-tag-derivative" as="element()+">
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:variable name="notAllowed" as="element()" select="$patterns[@name = '#notAllowed']" />
  <xsl:sequence select="$notAllowed, $patterns except $notAllowed" />
</xsl:template>

<!-- *** pat:start-annotation-derivative mode *** -->
  
<xsl:template match="pat:annotation" as="element()+" 
              mode="pat:start-annotation-derivative">
  <xsl:param name="event" as="element()" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:choose>
    <xsl:when test="pat:contains(pat:ref[1], QName($event/@ns, $event/@name), $patterns)">
      <xsl:variable name="name" as="element()">
        <pat:name name="{$event/@name}" ns="{$event/@ns}" />
      </xsl:variable>      
      <xsl:variable name="end-annotation" as="element()">
        <pat:end-annotation>
          <xsl:sequence select="$name" />
        </pat:end-annotation>
      </xsl:variable>

      <xsl:variable name="compiled-end-annotation" as="element()+">
        <xsl:apply-templates select="$end-annotation" mode="pat:compile">
          <xsl:with-param name="patterns" select="$patterns" />
        </xsl:apply-templates>
      </xsl:variable>      
      <xsl:variable name="group" as="element()+">
        <xsl:call-template name="pat:group">
          <xsl:with-param name="pattern1" select="pat:ref[2]/@name" />
          <xsl:with-param name="pattern2" select="$compiled-end-annotation[1]/@name" />
          <xsl:with-param name="patterns" select="$compiled-end-annotation" />
        </xsl:call-template>
      </xsl:variable>
      <xsl:variable name="after" as="element()+">
        <xsl:call-template name="pat:after">
          <xsl:with-param name="pattern1" select="$group[1]/@name" />
          <xsl:with-param name="pattern2" select="'#empty'" />
          <xsl:with-param name="patterns" select="$group" />
        </xsl:call-template>
      </xsl:variable>
      <xsl:sequence select="$after" />
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="notAllowed" as="element()" select="$patterns[@name = '#notAllowed']" />
      <xsl:sequence select="$notAllowed, $patterns except $notAllowed" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>  
  
<xsl:template match="pat:group" as="element()+"
              mode="pat:start-annotation-derivative">
  <xsl:param name="event" as="element()" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:choose>
    <xsl:when test="not(pat:allows-annotations(pat:ref[1], $patterns))">
      <xsl:variable name="deriv" as="element()+" 
        select="pat:derivative($event, pat:ref[2]/@name, $patterns)" />
      <xsl:variable name="after" as="element()+">
        <xsl:call-template name="pat:apply-after">
          <xsl:with-param name="construct" select="'group'" />
          <xsl:with-param name="arg1" select="pat:ref[1]/@name" />
          <xsl:with-param name="pattern" select="$deriv[1]/@name" />
          <xsl:with-param name="patterns" select="$deriv" />
        </xsl:call-template>
      </xsl:variable>
      <!--
      <xsl:message>
        event: <xsl:copy-of select="$event" copy-namespaces="no" />
        group: <xsl:copy-of select="." copy-namespaces="no" />
        deriv: <xsl:copy-of select="$deriv[1]" copy-namespaces="no" />
        after: <xsl:copy-of select="$after[1]" copy-namespaces="no" />
        grammar: <xsl:copy-of select="$deriv" copy-namespaces="no" />
      </xsl:message>
      -->
      <xsl:sequence select="$after" />
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="deriv" as="element()+"
        select="pat:derivative($event, pat:ref[1]/@name, $patterns)" />  
      <xsl:variable name="after" as="element()+">
        <xsl:call-template name="pat:apply-after">
          <xsl:with-param name="construct" select="'group'" />
          <xsl:with-param name="arg2" select="pat:ref[2]/@name" /> 
          <xsl:with-param name="pattern" select="$deriv[1]/@name" />
          <xsl:with-param name="patterns" select="$deriv" />
        </xsl:call-template>
      </xsl:variable>
      <xsl:choose>
        <xsl:when test="pat:nullable(pat:ref[1], $after)">
          <xsl:variable name="deriv2" as="element()+"
            select="pat:derivative($event, pat:ref[2]/@name, $after)" />      
          <xsl:call-template name="pat:choice">
            <xsl:with-param name="pattern1" select="$deriv[1]/@name" />
            <xsl:with-param name="pattern2" select="$after[1]/@name" />
            <xsl:with-param name="patterns" select="$after" />
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          <xsl:sequence select="$after" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="pat:notAllowed | pat:empty" as="element()+"
              mode="pat:start-annotation-derivative">
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:variable name="notAllowed" as="element()" select="$patterns[@name = '#notAllowed']" />
  <xsl:sequence select="$notAllowed, $patterns except $notAllowed" />
</xsl:template>
  
<xsl:template match="pat:*" as="element()+" mode="pat:start-annotation-derivative">
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:sequence select=".., $patterns except .." />
</xsl:template>

<!-- *** pat:end-annotation-derivative mode *** -->
  
<xsl:template match="pat:end-annotation" mode="pat:end-annotation-derivative" as="element()+">
  <xsl:param name="event" as="element(ev:end-end-annotation)" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:param name="nc" as="element(pat:name)"
    select="pat:pattern(pat:ref[1]/@name, $patterns)/pat:name" />
  <xsl:choose>
    <xsl:when test="$nc/@name eq $event/@name and
                    $nc/@ns eq $event/@ns">
      <xsl:variable name="empty" as="element()" select="$patterns[@name = '#empty']" />
      <xsl:sequence select="$empty, $patterns except $empty" />
    </xsl:when>
    <xsl:otherwise>
      <xsl:next-match>
        <xsl:with-param name="event" select="$event" />
        <xsl:with-param name="patterns" select="$patterns" />
      </xsl:next-match>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>  
  
<xsl:template match="pat:*" mode="pat:end-annotation-derivative" as="element()+">
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:variable name="notAllowed" as="element()" select="$patterns[@name = '#notAllowed']" />
  <xsl:sequence select="$notAllowed, $patterns except $notAllowed" />
</xsl:template>  
  
<!-- *** pat:text-derivative mode *** -->
  
<xsl:template match="pat:text" mode="pat:text-derivative" as="element()+">
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:sequence select=".., $patterns except .." />
</xsl:template>  
  
<xsl:template match="pat:*" mode="pat:text-derivative" as="element()+">
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:variable name="notAllowed" as="element()" select="$patterns[@name = '#notAllowed']" />
  <xsl:sequence select="$notAllowed, $patterns except $notAllowed" />
</xsl:template>
      
<!-- *** pat:apply-after *** -->  
  
<!-- This follows James Clark's logic. -->
<!-- $pattern2 is like a template whose second argument will be the
     second argument from $pattern1 -->
<xsl:template name="pat:apply-after" as="element()+">
  <xsl:param name="construct" as="xs:string" required="yes" />
  <xsl:param name="arg1" as="xs:string?" select="()" />
  <xsl:param name="arg2" as="xs:string?" select="()" />
  <xsl:param name="pattern" as="xs:string" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:variable name="pat" as="element()" select="pat:pattern($pattern, $patterns)" />
  <!--
  <xsl:message>
    construct: <xsl:value-of select="$construct" />
    arg1: <xsl:value-of select="$arg1" />
    arg2: <xsl:value-of select="$arg2" />
    pattern: <xsl:value-of select="$pattern" />
    patterns: <xsl:copy-of select="$patterns" copy-namespaces="no" />
  </xsl:message>
  -->
  <xsl:choose>
    <xsl:when test="$pat/pat:after">
      <xsl:variable name="group" as="element()+">
        <xsl:variable name="pat1" as="xs:string" 
          select="if (exists($arg1)) then $arg1 else $pat/pat:after/pat:ref[2]/@name"/>
        <xsl:variable name="pat2" as="xs:string" 
          select="if (exists($arg2)) then $arg2 else $pat/pat:after/pat:ref[2]/@name" />
        <xsl:choose>
          <xsl:when test="$construct = 'group'">
            <xsl:call-template name="pat:group">
              <xsl:with-param name="pattern1" select="$pat1" />
              <xsl:with-param name="pattern2" select="$pat2" />
              <xsl:with-param name="patterns" select="$patterns" />
            </xsl:call-template>
          </xsl:when>
          <xsl:when test="$construct = 'interleave'">
            <xsl:call-template name="pat:interleave">
              <xsl:with-param name="pattern1" select="$pat1" />
              <xsl:with-param name="pattern2" select="$pat2" />
              <xsl:with-param name="patterns" select="$patterns" />
            </xsl:call-template>
          </xsl:when>
          <xsl:when test="$construct = 'overlap'">
            <xsl:call-template name="pat:overlap">
              <xsl:with-param name="pattern1" select="$pat1" />
              <xsl:with-param name="pattern2" select="$pat2" />
              <xsl:with-param name="patterns" select="$patterns" />
            </xsl:call-template>
          </xsl:when>
          <xsl:when test="$construct = 'after'">
            <xsl:call-template name="pat:after">
              <xsl:with-param name="pattern1" select="$pat1" />
              <xsl:with-param name="pattern2" select="$pat2" />
              <xsl:with-param name="patterns" select="$patterns" />
            </xsl:call-template>
          </xsl:when>
        </xsl:choose>
      </xsl:variable>      
      <xsl:call-template name="pat:after">
        <xsl:with-param name="pattern1" select="$pat/pat:after/pat:ref[1]/@name" />
        <xsl:with-param name="pattern2" select="$group[1]/@name" />
        <xsl:with-param name="patterns" select="$group" />
      </xsl:call-template>
    </xsl:when>
    <xsl:when test="$pat/pat:choice">
      <xsl:variable name="after1" as="element()+">
        <xsl:call-template name="pat:apply-after">
          <xsl:with-param name="construct" select="$construct" />
          <xsl:with-param name="arg1" select="$arg1" />
          <xsl:with-param name="arg2" select="$arg2" />
          <xsl:with-param name="pattern" select="$pat/pat:choice/pat:ref[1]/@name" />
          <xsl:with-param name="patterns" select="$patterns" />
        </xsl:call-template>
      </xsl:variable>
      <xsl:variable name="after2" as="element()+">
        <xsl:call-template name="pat:apply-after">
          <xsl:with-param name="construct" select="$construct" />
          <xsl:with-param name="arg1" select="$arg1" />
          <xsl:with-param name="arg2" select="$arg2" />
          <xsl:with-param name="pattern" select="$pat/pat:choice/pat:ref[2]/@name" />
          <xsl:with-param name="patterns" select="$after1" />
        </xsl:call-template>
      </xsl:variable>      
      <xsl:call-template name="pat:choice">
        <xsl:with-param name="pattern1" select="$after1[1]/@name" />
        <xsl:with-param name="pattern2" select="$after2[1]/@name" />
        <xsl:with-param name="patterns" select="$after2" />
      </xsl:call-template>
    </xsl:when>
    <xsl:when test="$pat/pat:ref">
      <xsl:call-template name="pat:apply-after">
        <xsl:with-param name="construct" select="$construct" />
        <xsl:with-param name="arg1" select="$arg1" />
        <xsl:with-param name="arg2" select="$arg2" />
        <xsl:with-param name="pattern" select="$pat/pat:ref/@name" />
        <xsl:with-param name="patterns" select="$patterns" />
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="notAllowed" as="element()" select="$patterns[@name = '#notAllowed']" />
      <xsl:sequence select="$notAllowed, $patterns except $notAllowed" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>  

<!-- *** pat:content *** -->
<!-- This mode returns the content specified in the pattern: only text and atoms -->
  
<xsl:template match="pat:group |
                     pat:interleave |
                     pat:choice |
                     pat:overlap"
              mode="pat:content" as="element()+">
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:variable name="content1" as="element()+">
    <xsl:apply-templates select="pat:ref[1]" mode="pat:content">
      <xsl:with-param name="patterns" select="$patterns" />
    </xsl:apply-templates>
  </xsl:variable>
  <xsl:variable name="content2" as="element()+">
    <xsl:apply-templates select="pat:ref[2]" mode="pat:content">
      <xsl:with-param name="patterns" select="$content1" />
    </xsl:apply-templates>
  </xsl:variable>
  <xsl:call-template name="pat:combine">
    <xsl:with-param name="combiner" select="local-name(.)" />
    <xsl:with-param name="pattern1" select="$content1[1]/@name" />
    <xsl:with-param name="pattern2" select="$content2[1]/@name" />
    <xsl:with-param name="patterns" select="$content2" />
  </xsl:call-template>
</xsl:template>
  
<xsl:template match="pat:oneOrMore | pat:overlapOneOrMore"
              mode="pat:content" as="element()+">
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:variable name="content" as="element()+">
    <xsl:apply-templates select="pat:ref" mode="pat:content">
      <xsl:with-param name="patterns" select="$patterns" />
    </xsl:apply-templates>
  </xsl:variable>
  <xsl:call-template name="pat:repeat">
    <xsl:with-param name="repeater" select="local-name(.)" />
    <xsl:with-param name="patterns" select="$content" />
  </xsl:call-template>
</xsl:template>
  
<xsl:template match="pat:text" mode="pat:content" as="element()+">
  <xsl:param name="patterns" as="element()+" />
  <xsl:sequence select="., $patterns except ." />
</xsl:template>
  
<xsl:template match="pat:ref" mode="pat:content" as="element()+">
  <xsl:param name="patterns" as="element()+" />
  <xsl:apply-templates select="$patterns[@name = current()/@name]" mode="pat:content">
    <xsl:with-param name="patterns" select="$patterns" />
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="pat:define" mode="pat:content" as="element()+">
  <xsl:param name="patterns" as="element()+" />
  <xsl:apply-templates select="pat:*[1]" mode="pat:content">
    <xsl:with-param name="patterns" select="$patterns" />
  </xsl:apply-templates>
</xsl:template>  
  
<!--
<xsl:template match="pat:range" mode="pat:content" as="element()+">
  <xsl:param name="patterns" as="element()+" />
  <xsl:apply-templates select="pat:*[2]" mode="pat:content">
    <xsl:with-param name="patterns" select="$patterns" />
  </xsl:apply-templates>
</xsl:template>  
-->
  
<xsl:template match="pat:*" mode="pat:content" as="element()+">
  <xsl:param name="patterns" as="element()+" />
  <xsl:variable name="empty" as="element()" select="$patterns[@name = '#empty']" />
  <xsl:sequence select="$empty, $patterns except $empty" />
</xsl:template>  
  
<!-- *** pat:contains() *** -->
  
<xsl:function name="pat:contains" as="xs:boolean">
  <xsl:param name="nc" as="element()" />
  <xsl:param name="qname" as="xs:QName" />
  <xsl:param name="patterns" as="element()+" />
  <xsl:apply-templates select="$nc" mode="pat:contains">
    <xsl:with-param name="qname" select="$qname" />
    <xsl:with-param name="patterns" select="$patterns" />
  </xsl:apply-templates>
</xsl:function>
  
<xsl:template match="pat:ref" mode="pat:contains" as="xs:boolean">
  <xsl:param name="qname" as="xs:QName" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:sequence 
    select="pat:contains(pat:pattern(@name, $patterns), $qname, $patterns)" />
</xsl:template>  

<xsl:template match="pat:define" mode="pat:contains" as="xs:boolean">
  <xsl:param name="qname" as="xs:QName" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:sequence select="pat:contains(pat:*, $qname, $patterns)" />
</xsl:template>  
  
<xsl:template match="pat:name" mode="pat:contains" as="xs:boolean">
  <xsl:param name="qname" as="xs:QName" required="yes" />
  <xsl:param name="patterns" as="element()+" required="yes" />
  <xsl:sequence select="@name = local-name-from-QName($qname) and
                        @ns = namespace-uri-from-QName($qname)" />
</xsl:template>
  
<!-- *** ev:hash() *** -->
  
<xsl:function name="ev:hash" as="xs:string">
  <xsl:param name="event" as="element()" />
  <xsl:apply-templates select="$event" mode="ev:hash" />
</xsl:function>
  
<xsl:template match="ev:start-tag | ev:end-start-tag | 
                     ev:end-tag | ev:end-end-tag |
                     ev:start-element | ev:end-start-element |
                     ev:end-element | ev:end-end-element |
                     ev:start-range | ev:end-start-range |
                     ev:end-range | ev:end-end-range"
              mode="ev:hash" as="xs:string">
  <xsl:sequence select="concat(local-name(), '(''', @ns, ''',', @name, ',', @id, ')')" />
</xsl:template>
  
<xsl:template match="ev:start-annotation | ev:end-start-annotation | 
                     ev:end-annotation | ev:end-end-annotation |
                     ev:start-atom | ev:end-atom"
              mode="ev:hash" as="xs:string">
  <xsl:sequence select="concat(local-name(), '(''', @ns, ''',', @name, ')')" />
</xsl:template>
  
<xsl:template match="ev:text"
              mode="ev:hash" as="xs:string">
  <xsl:sequence select="concat(local-name(), '(''', @chars, ''')')" />
</xsl:template>
  
</xsl:stylesheet>
