<?xml version='1.0'?>
<!-- this stylesheet decorates a serialized infoset with -->
<!-- map:to information from the schema.                 -->
<!-- it leaves the document unchanges otherwse.          -->
<!-- other stylesheets may add or remove information     -->
<!-- based on these values, such as removing elements    -->
<!-- with map:to="##nothing"                             -->
<!-- This stylesheet makes use of the id() function and  -->
<!-- requires at least a DTD subset such as infoset.dtd  -->
<xsl:stylesheet version="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:i="http://www.w3.org/2001/05/XMLInfoset" xmlns:psv="http://www.w3.org/2001/05/PSVInfosetExtension" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:map="http://www.cogsci.ed.ac.uk/~kari/schema-mapping" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="xml" indent="no"/>
  <xsl:strip-space elements="*"/>

  <xsl:param name="map:lang"/>


  <xsl:template match="/">

    <!-- get schema-wide defaults -->
    <!-- map:builtinMap is curently ignored, awaiting completion of a standard mapping -->
    <xsl:variable name="map:elementDefault">
      <xsl:call-template name="getMappingDefault">
        <xsl:with-param name="name" select="'elementDefault'"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="map:attributeDefault">
      <xsl:call-template name="getMappingDefault">
        <xsl:with-param name="name" select="'attributeDefault'"/>
      </xsl:call-template>
    </xsl:variable>
    <!--xsl:variable name="map:typeDefault">
      <xsl:call-template name="getMappingDefault">
        <xsl:with-param name="name" select="'typeDefault'"/>
      </xsl:call-template>
    </xsl:variable-->
    <xsl:variable name="map:complexTypeDefault">
      <xsl:call-template name="getMappingDefault">
        <xsl:with-param name="name" select="'complexTypeDefault'"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="map:simpleTypeDefault">
      <xsl:call-template name="getMappingDefault">
        <xsl:with-param name="name" select="'simpleTypeDefault'"/>
      </xsl:call-template>
    </xsl:variable>

    <xsl:apply-templates select="i:document/i:children/*">
      <xsl:with-param name="map:elementDefault" select="$map:elementDefault"/>
      <xsl:with-param name="map:attributeDefault" select="$map:attributeDefault"/>
      <!-- xsl:with-param name="map:typeDefault"        select="$map:typeDefault"/ -->
      <xsl:with-param name="map:complexTypeDefault" select="$map:complexTypeDefault"/>
      <xsl:with-param name="map:simpleTypeDefault" select="$map:simpleTypeDefault"/>
    </xsl:apply-templates>

  </xsl:template>


  <xsl:template name="getMappingDefault">
    <xsl:param name="name"/>
    <xsl:variable name="document-local-default" select="/i:document/i:children/i:element/psv:schemaInformation/psv:namespaceSchemaInformation/psv:schemaAnnotations/psv:annotation/psv:attributes/i:attribute[i:namespaceName='http://www.cogsci.ed.ac.uk/~kari/schema-mapping' and i:localName=$name]/i:normalizedValue"/>
    <xsl:choose>
      <xsl:when test="string($document-local-default)">
        <xsl:value-of select="$document-local-default"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:variable name="external-default" select="document('map-defaults.xml')/map:defaults/@map:*[local-name()=$name]"/>
        <!-- optioanally, check that the value was found -->
        <xsl:value-of select="$external-default"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- the only purpose of this template is to pass paramters   -->
  <!-- to templates called from it; this it the only difference -->
  <!-- compared to the default template                         -->
  <xsl:template match="*">
    <xsl:param name="map:elementDefault"/>
    <xsl:param name="map:attributeDefault"/>
    <!-- xsl:param name="map:typeDefault"/  -->
    <xsl:param name="map:complexTypeDefault"/>
    <xsl:param name="map:simpleTypeDefault"/>

    <xsl:apply-templates>
      <xsl:with-param name="map:elementDefault" select="$map:elementDefault"/>
      <xsl:with-param name="map:attributeDefault" select="$map:attributeDefault"/>
      <!-- xsl:with-param name="map:typeDefault"      select="$map:typeDefault"/ -->
      <xsl:with-param name="map:complexTypeDefault" select="$map:complexTypeDefault"/>
      <xsl:with-param name="map:simpleTypeDefault" select="$map:simpleTypeDefault"/>
    </xsl:apply-templates>
  </xsl:template>


 <xsl:template name="prefix">
  <xsl:param name="uri"/>
  <xsl:param name="isn"/>
  <xsl:if test="string-length($uri)>0">
   <xsl:variable name="entry" select="$isn/i:namespace[i:namespaceName=$uri]"/>
   <xsl:variable name="prefix" select="$entry/i:prefix"/>
   <xsl:if test="string-length($prefix)>0"><xsl:value-of select="$prefix"/>:</xsl:if>
  </xsl:if>
 </xsl:template>
 

  <xsl:template match="i:element">

    <xsl:param name="map:elementDefault"/>
    <xsl:param name="map:attributeDefault"/>
    <!-- xsl:param name="map:typeDefault"/  -->
    <xsl:param name="map:complexTypeDefault"/>
    <xsl:param name="map:simpleTypeDefault"/>

    <xsl:variable name="p">
      <xsl:call-template name="prefix">
        <xsl:with-param name="uri" select="i:namespaceName"/>
        <xsl:with-param name="isn" select="i:inScopeNamespaces"/>
      </xsl:call-template>
    </xsl:variable>

    <xsl:element name="{$p}{i:localName}" namespace="{i:namespaceName}">

      <!-- attributes -->

      <xsl:for-each select="i:attributes/i:attribute">
        <xsl:variable name="ap">
          <xsl:call-template name="prefix">
            <xsl:with-param name="uri" select="i:namespaceName"/>
            <xsl:with-param name="isn" select="../../i:inScopeNamespaces"/>
          </xsl:call-template>
        </xsl:variable>
        <xsl:choose>
          <xsl:when test="string-length(i:namespaceName)>0">
            <xsl:attribute name="{$ap}{i:localName}" namespace="{i:namespaceName}">
              <xsl:value-of select="i:normalizedValue"/>
            </xsl:attribute>
          </xsl:when>
          <xsl:otherwise>
            <xsl:attribute name="{i:localName}">
              <xsl:value-of select="i:normalizedValue"/>
            </xsl:attribute>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:for-each>


      <!-- annotations, type information -->

      <!-- element declaration -->

      <xsl:variable name="elementDeclarationRef" select="psv:declaration/psv:elementDeclaration/@ref"/>

      <xsl:variable name="map:item-to">
        <xsl:call-template name="getItemMapping">
          <xsl:with-param name="name" select="'to'"/>
          <xsl:with-param name="itemDeclarationRef" select="$elementDeclarationRef"/>
        </xsl:call-template>
      </xsl:variable>

      <xsl:attribute name="map:item-to">
        <xsl:choose>
          <xsl:when test="string($map:item-to)">
            <xsl:value-of select="$map:item-to"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="$map:elementDefault"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:attribute>

      <xsl:attribute name="map:item-name">
        <xsl:value-of select="id($elementDeclarationRef)/psv:name"/>
      </xsl:attribute>

      <xsl:attribute name="map:minOccurs">
        <xsl:value-of select="id($elementDeclarationRef)/../../psv:minOccurs"/>
      </xsl:attribute>

      <xsl:attribute name="map:maxOccurs">
        <xsl:value-of select="id($elementDeclarationRef)/../../psv:maxOccurs"/>
      </xsl:attribute>


      <!-- type definition -->

      <xsl:variable name="typeDefinitionRef" select="psv:typeDefinition/*/@ref"/>

      <xsl:variable name="map:type-to">
        <xsl:call-template name="getTypeMapping">
          <xsl:with-param name="name" select="'to'"/>
          <xsl:with-param name="typeDefinitionRef" select="$typeDefinitionRef"/>
        </xsl:call-template>
      </xsl:variable>
     
     <xsl:variable name="basetypeRef" select="id($typeDefinitionRef)/psv:baseTypeDefinition/*/@ref"/>

      <xsl:attribute name="map:type-to">
        <xsl:choose>
          <xsl:when test="string($map:type-to)">
            <xsl:value-of select="$map:type-to"/>
          </xsl:when>
          <xsl:otherwise>
	    <xsl:if test="local-name(id($typeDefinitionRef)) = 'complexTypeDefinition'">
              <xsl:value-of select="$map:complexTypeDefault"/>
	    </xsl:if>
	    <xsl:if test="local-name(id($typeDefinitionRef)) = 'simpleTypeDefinition'">
              <xsl:value-of select="$map:simpleTypeDefault"/>
	    </xsl:if>
            <!--xsl:value-of select="$map:typeDefault"/-->
          </xsl:otherwise>
        </xsl:choose>
      </xsl:attribute>

      <xsl:attribute name="map:type-name">
        <xsl:variable name="type-name" select="id($typeDefinitionRef)/psv:name/text()"/>
        <xsl:variable name="map:type-name" select="id($typeDefinitionRef)/psv:annotations/psv:annotation/psv:attributes/i:attribute[i:namespaceName='http://www.cogsci.ed.ac.uk/~kari/schema-mapping' and i:localName='name']"/>
        <xsl:choose>
          <xsl:when test="$map:type-name">
            <xsl:text>{</xsl:text>
            <xsl:value-of select="id($typeDefinitionRef)/../../psv:schemaNamespace/text()"/>
            <xsl:text>}</xsl:text>
            <xsl:value-of select="$map:type-name/i:normalizedValue"/>
          </xsl:when>
          <xsl:when test="$type-name">
            <xsl:text>{</xsl:text>
            <xsl:value-of select="id($typeDefinitionRef)/../../psv:schemaNamespace/text()"/>
            <xsl:text>}</xsl:text>
            <xsl:value-of select="$type-name"/>
          </xsl:when>
         <xsl:when test="$basetypeRef='xsd..type.anyType'">
          <!-- anonymous local type - - use elt name -->
          <xsl:text>{</xsl:text>
            <xsl:value-of select="id($typeDefinitionRef)/../../psv:schemaNamespace/text()"/>
            <xsl:text>}</xsl:text>
            <xsl:value-of select="id($elementDeclarationRef)/psv:name"/>
         </xsl:when>
          <xsl:when test="id($basetypeRef)/psv:name/text()">
            <xsl:text>{</xsl:text>
            <xsl:value-of select="id($basetypeRef)/../../psv:schemaNamespace/text()"/>
            <xsl:text>}</xsl:text>
            <xsl:value-of select="id($basetypeRef)/psv:name/text()"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:text>{</xsl:text>
            <xsl:value-of select="id($typeDefinitionRef)/../../psv:schemaNamespace/text()"/>
            <xsl:text>}</xsl:text>
            <xsl:value-of select="$typeDefinitionRef"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:attribute>

      <!-- text value -->

      <!-- include schema normalized values only if -->
      <!-- no individual characters were reported -->
      <xsl:if test="not (i:children/i:character)">
        <xsl:apply-templates select="psv:schemaNormalizedValue"/>
      </xsl:if>

      <!-- child elements -->

      <xsl:apply-templates select="i:children">
        <xsl:with-param name="map:elementDefault" select="$map:elementDefault"/>
        <xsl:with-param name="map:attributeDefault" select="$map:attributeDefault"/>
        <!-- xsl:with-param name="map:typeDefault"      select="$map:typeDefault"/ -->
        <xsl:with-param name="map:complexTypeDefault" select="$map:complexTypeDefault"/>
        <xsl:with-param name="map:simpleTypeDefault" select="$map:simpleTypeDefault"/>
      </xsl:apply-templates>

    </xsl:element>
 </xsl:template>


  <xsl:template name="getItemMapping">
    <xsl:param name="name"/>
    <xsl:param name="itemDeclarationRef"/>
    <xsl:value-of select="id($itemDeclarationRef)/psv:annotation/psv:annotation/psv:attributes/i:attribute[i:namespaceName='http://www.cogsci.ed.ac.uk/~kari/schema-mapping' and i:localName=$name]/i:normalizedValue"/>
  </xsl:template>

 
  <xsl:template name="getTypeMapping">
    <xsl:param name="name"/>
    <xsl:param name="typeDefinitionRef"/>
    <xsl:value-of select="id($typeDefinitionRef)/psv:annotations/psv:annotation/psv:attributes/i:attribute[i:namespaceName='http://www.cogsci.ed.ac.uk/~kari/schema-mapping' and i:localName=$name]/i:normalizedValue"/>
  </xsl:template>

 
 <xsl:template match="i:attribute">
 </xsl:template>

  <xsl:template match="i:character">
    <xsl:if test="i:elementContentWhitespace='false'">
      <!-- a hack that converts decimal unicode character -->
      <!-- codes into character references -->
      <xsl:text disable-output-escaping="yes">&amp;#</xsl:text><xsl:value-of select="i:characterCode"/>;</xsl:if>
  </xsl:template>

</xsl:stylesheet>
