<?xml version="1.0" encoding="UTF-8"?>
<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"
                xmlns:ev="http://www.lmnl.org/event"
                xmlns:syn="http://www.lmnl.org/event/syntactic"
                exclude-result-prefixes="xs ev syn test"
                xmlns:clix="http://lmnl.net/clix">
  
<test:tests>
  <test:title>Transforming to CLIX</test:title>
  <test:test>
    <test:title>Simple text</test:title>
    <test:context>
      <ev:events>
        <ev:text chars="foo" ws="false" />
      </ev:events>
    </test:context>
    <test:expect>
      <clix:clix>foo</clix:clix>
    </test:expect>
  </test:test>
  <test:test>
    <test:title>Single range</test:title>
    <test:context>
      <ev:events>
        <ev:text chars="..." ws="false" />
        <ev:start-tag-open ns="" name="foo" id="" depth="0" />
        <ev:start-tag-close ns="" name="foo" id="" depth="0" />
        <ev:text chars="..." ws="false" />
        <ev:end-tag-open ns="" name="foo" id="" depth="0" />
        <ev:end-tag-close ns="" name="foo" id="" depth="0" />
        <ev:text chars="..." ws="false" />
      </ev:events>
    </test:context>
    <test:expect>
      <clix:clix>...<foo clix:role="start-range" />...<foo clix:role="end-range" />...</clix:clix>
    </test:expect>
  </test:test>
  <test:test>
    <test:title>Non-overlapping ranges</test:title>
    <test:context>
      <ev:events>
        <ev:text chars="..." ws="false" />
        <ev:start-tag-open ns="" name="foo" id="" depth="0" />
        <ev:start-tag-close ns="" name="foo" id="" depth="0" />
        <ev:text chars="..." ws="false" />
        <ev:end-tag-open ns="" name="foo" id="" depth="0" />
        <ev:end-tag-close ns="" name="foo" id="" depth="0" />
        <ev:text chars="..." ws="false" />
        <ev:start-tag-open ns="" name="foo" id="" depth="0" />
        <ev:start-tag-close ns="" name="foo" id="" depth="0" />
        <ev:text chars="..." ws="false" />
        <ev:end-tag-open ns="" name="foo" id="" depth="0" />
        <ev:end-tag-close ns="" name="foo" id="" depth="0" />
        <ev:text chars="..." ws="false" />
      </ev:events>
    </test:context>
    <test:expect>
      <clix:clix>...<foo clix:role="start-range" />...<foo clix:role="end-range" />...<foo clix:role="start-range" />...<foo clix:role="end-range" />...</clix:clix>
    </test:expect>
  </test:test>
  <test:test>
    <test:title>Overlapping ranges</test:title>
    <test:context>
      <ev:events>
        <ev:text chars="..." ws="false" />
        <ev:start-tag-open ns="" name="foo" id="f1" depth="0" />
        <ev:start-tag-close ns="" name="foo" id="f1" depth="0" />
        <ev:text chars="..." ws="false" />
        <ev:start-tag-open ns="" name="foo" id="f2" depth="0" />
        <ev:start-tag-close ns="" name="foo" id="f2" depth="0" />
        <ev:text chars="..." ws="false" />
        <ev:end-tag-open ns="" name="foo" id="f1" depth="0" />
        <ev:end-tag-close ns="" name="foo" id="f1" depth="0" />
        <ev:text chars="..." ws="false" />
        <ev:end-tag-open ns="" name="foo" id="f2" depth="0" />
        <ev:end-tag-close ns="" name="foo" id="f2" depth="0" />
        <ev:text chars="..." ws="false" />
      </ev:events>
    </test:context>
    <test:expect>
      <clix:clix>...<foo clix:role="start-range" clix:sID="f1" />...<foo clix:role="start-range" clix:sID="f2" />...<foo clix:role="end-range" clix:eID="f1" />...<foo clix:role="end-range" clix:eID="f2" />...</clix:clix>
    </test:expect>
  </test:test>
  <test:test>
    <test:title>Single range with single annotation</test:title>
    <test:context>
      <ev:events>
        <ev:text chars="..." ws="false" />
        <ev:start-tag-open ns="" name="foo" id="" depth="0" />
        <ev:start-annotation-open ns="" name="bar" depth="1" />
        <ev:start-annotation-close ns="" name="bar" depth="1" />
        <ev:text chars="..." ws="false" />
        <ev:end-annotation-open ns="" name="bar" depth="1" />
        <ev:end-annotation-close ns="" name="bar" depth="1" />
        <ev:start-tag-close ns="" name="foo" id="" depth="0" />
        <ev:text chars="..." ws="false" />
        <ev:end-tag-open ns="" name="foo" id="" depth="0" />
        <ev:end-tag-close ns="" name="foo" id="" depth="0" />
        <ev:text chars="..." ws="false" />
      </ev:events>
    </test:context>
    <test:expect>
      <clix:clix>...<foo clix:role="start-range">
        <bar clix:role="start-annotation" />...<bar clix:role="end-annotation" />
      </foo>...<foo clix:role="end-range" />...</clix:clix>
    </test:expect>
  </test:test>
  <test:test>
    <test:title>Single range with two annotations</test:title>
    <test:context>
      <ev:events>
        <ev:text chars="..." ws="false" />
        <ev:start-tag-open ns="" name="foo" id="" depth="0" />
        <ev:start-annotation-open ns="" name="bar" depth="1" />
        <ev:start-annotation-close ns="" name="bar" depth="1" />
        <ev:text chars="..." ws="false" />
        <ev:end-annotation-open ns="" name="bar" depth="1" />
        <ev:end-annotation-close ns="" name="bar" depth="1" />
        <ev:start-annotation-open ns="" name="baz" depth="1" />
        <ev:start-annotation-close ns="" name="baz" depth="1" />
        <ev:text chars="..." ws="false" />
        <ev:end-annotation-open ns="" name="baz" depth="1" />
        <ev:end-annotation-close ns="" name="baz" depth="1" />
        <ev:start-tag-close ns="" name="foo" id="" depth="0" />
        <ev:text chars="..." ws="false" />
        <ev:end-tag-open ns="" name="foo" id="" depth="0" />
        <ev:end-tag-close ns="" name="foo" id="" depth="0" />
        <ev:text chars="..." ws="false" />
      </ev:events>
    </test:context>
    <test:expect>
      <clix:clix>...<foo clix:role="start-range">
        <bar clix:role="start-annotation" />...<bar clix:role="end-annotation" />
        <baz clix:role="start-annotation" />...<baz clix:role="end-annotation" />
      </foo>...<foo clix:role="end-range" />...</clix:clix>
    </test:expect>
  </test:test>
  <test:test>
    <test:title>Single range with nested annotations</test:title>
    <test:context>
      <ev:events>
        <ev:text chars="..." ws="false" />
        <ev:start-tag-open ns="" name="foo" id="" depth="0" />
        <ev:start-annotation-open ns="" name="bar" depth="1" />
        <ev:start-annotation-open ns="" name="baz" depth="2" />
        <ev:start-annotation-close ns="" name="baz" depth="2" />
        <ev:text chars="..." ws="false" />
        <ev:end-annotation-open ns="" name="baz" depth="2" />
        <ev:end-annotation-close ns="" name="baz" depth="2" />
        <ev:start-annotation-close ns="" name="bar" depth="1" />
        <ev:text chars="..." ws="false" />
        <ev:end-annotation-open ns="" name="bar" depth="1" />
        <ev:end-annotation-close ns="" name="bar" depth="1" />
        <ev:start-tag-close ns="" name="foo" id="" depth="0" />
        <ev:text chars="..." ws="false" />
        <ev:end-tag-open ns="" name="foo" id="" depth="0" />
        <ev:end-tag-close ns="" name="foo" id="" depth="0" />
        <ev:text chars="..." ws="false" />
      </ev:events>
    </test:context>
    <test:expect>
      <clix:clix>...<foo clix:role="start-range">
        <bar clix:role="start-annotation">
          <baz clix:role="start-annotation" />...<baz clix:role="end-annotation" />
        </bar>...<bar clix:role="end-annotation" />        
      </foo>...<foo clix:role="end-range" />...</clix:clix>
    </test:expect>
  </test:test>
  <test:test>
    <test:title>Single atom</test:title>
    <test:context>
      <ev:events>
        <ev:text chars="..." ws="false" />
        <ev:atom-open ns="" name="foo" id="" depth="0" />
        <ev:atom-close ns="" name="foo" id="" depth="0" />
        <ev:text chars="..." ws="false" />
      </ev:events>
    </test:context>
    <test:expect>
      <clix:clix>...<foo clix:role="atom" />...</clix:clix>
    </test:expect>
  </test:test>
  <test:test>
    <test:title>Anonymous range</test:title>
    <test:context>
      <ev:events>
        <ev:text chars="..." ws="false" />
        <ev:start-tag-open ns="" name="" id="" depth="0" />
        <ev:start-tag-close ns="" name="" id="" depth="0" />
        <ev:text chars="..." ws="false" />
        <ev:end-tag-open ns="" name="" id="" depth="0" />
        <ev:end-tag-close ns="" name="" id="" depth="0" />
        <ev:text chars="..." ws="false" />
      </ev:events>
    </test:context>
    <test:expect>
      <clix:clix>...<clix:anon clix:role="start-range" />...<clix:anon clix:role="end-range" />...</clix:clix>
    </test:expect>
  </test:test>
  <test:test>
    <test:title>Namespaced range</test:title>
    <test:context>
      <ev:events>
        <syn:ns-decl prefix="x" ns="http://www.example.com/" />
        <ev:text chars="..." ws="false" />
        <ev:start-tag-open prefix="x" ns="http://www.example.com/" name="foo" id="" depth="0" />
        <ev:start-tag-close prefix="x" ns="http://www.example.com/" name="foo" id="" depth="0" />
        <ev:text chars="..." ws="false" />
        <ev:end-tag-open prefix="x" ns="http://www.example.com/" name="foo" id="" depth="0" />
        <ev:end-tag-close prefix="x" ns="http://www.example.com/" name="foo" id="" depth="0" />
        <ev:text chars="..." ws="false" />
      </ev:events>
    </test:context>
    <test:expect>
      <clix:clix xmlns:x="http://www.example.com/">...<x:foo clix:role="start-range" />...<x:foo clix:role="end-range" />...</clix:clix>
    </test:expect>
  </test:test>
</test:tests>
<xsl:template match="ev:events" mode="ev:to-clix">
  <clix:clix>
    <xsl:for-each-group select="syn:ns-decl" group-by="@prefix">
      <xsl:namespace name="{@prefix}" select="@ns" />
    </xsl:for-each-group>
    <xsl:call-template name="ev:group-events">
      <xsl:with-param name="events" select="ev:*" />
    </xsl:call-template>
  </clix:clix>
</xsl:template>
  
<xsl:template match="ev:text" mode="ev:to-clix">
  <xsl:value-of select="@chars" />
</xsl:template>
  
<xsl:template match="syn:comment" mode="ev:to-clix">
  <xsl:comment select="@content" />
</xsl:template>
  
<xsl:template name="ev:group-events">
  <xsl:param name="events" as="element()*" required="yes" />
  <xsl:param name="depth" as="xs:integer" select="0" />
  <xsl:for-each-group select="$events" 
                      group-starting-with="ev:start-tag-open[@depth = $depth]
                                           | ev:end-tag-open[@depth = $depth]
                                           | ev:start-annotation-open[@depth = $depth]
                                           | ev:end-annotation-open[@depth = $depth]
                                           | ev:atom-open[@depth = $depth]">
    <xsl:choose>
      <xsl:when test="@depth">
        <xsl:variable name="event" as="xs:string" select="local-name(.)" />
        <xsl:for-each-group select="current-group()"
                            group-ending-with="ev:*[local-name(.) = replace($event, '-open', '-close') and
                                                    @depth = $depth]">
          <xsl:choose>
            <xsl:when test="position() = 1">
              <xsl:element name="{if (string(@name)) 
                                  then concat(if (string(@prefix)) then concat(@prefix, ':') else '', @name)
                                  else 'clix:anon'}" 
                           namespace="{if (string(@name))
                                       then @ns
                                       else 'http://lmnl.net/clix'}">
                <xsl:attribute name="clix:role">
                  <xsl:choose>
                    <xsl:when test="$event = 'start-tag-open'"       >start-range</xsl:when>
                    <xsl:when test="$event = 'end-tag-open'"         >end-range</xsl:when>
                    <xsl:when test="$event = 'start-annotation-open'">start-annotation</xsl:when>
                    <xsl:when test="$event = 'end-annotation-open'"  >end-annotation</xsl:when>
                    <xsl:when test="$event = 'atom-open'"            >atom</xsl:when>
                  </xsl:choose>                  
                </xsl:attribute>
                <xsl:if test="string(@id)">
                  <xsl:choose>
                    <xsl:when test="$event = 'start-tag-open'">
                      <xsl:attribute name="clix:sID" select="@id" />
                    </xsl:when>
                    <xsl:when test="$event = 'end-tag-open'">
                      <xsl:attribute name="clix:eID" select="@id" />                  
                    </xsl:when>
                  </xsl:choose>                  
                </xsl:if>
                <xsl:call-template name="ev:group-events">
                  <xsl:with-param name="events" select="current-group()[position() != 1 and position() != last()]" />
                  <xsl:with-param name="depth" select="$depth + 1" />
                </xsl:call-template>
              </xsl:element>
            </xsl:when>
            <xsl:otherwise>
              <xsl:apply-templates select="current-group()" mode="ev:to-clix" />
            </xsl:otherwise>
          </xsl:choose>          
        </xsl:for-each-group>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="current-group()" mode="ev:to-clix" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:for-each-group>
</xsl:template>  
  
</xsl:stylesheet>
