<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:param name="imagePrefixURL"/>
    <xsl:output method="xml" encoding="UTF-8" omit-xml-declaration="yes"/>
    <xsl:template match="/">
        <images>
			<!-- 
				TRAITEMENT DES ELEMENTS
			-->
            <xsl:call-template name="computeChildElement">
                <xsl:with-param name="level">0</xsl:with-param>
            </xsl:call-template>
        </images>
    </xsl:template>

	<!-- 
		TESTE SI UN ELEMENT A DEJA ETE TRAITE
	-->
    <xsl:template name="hasBeenAlreadyComputed">
        <xsl:param name="name"/>
        <xsl:param name="type"/>
        <xsl:param name="level"/>
        <xsl:choose>
            <xsl:when test="//*[local-name()='element'][@name=$name and (not(@type) or @type=$type) and number($level) &gt; count(ancestor::*[local-name()='element'])]">
                <xsl:copy-of select="true()"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy-of select="false()"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

	<!-- 
		TESTE SI UN ELEMENT A DES FILS DE SECOND NIVEAU
	-->
    <xsl:template name="hasScndLevelElements">
        <xsl:param name="element"/>
        <xsl:param name="level"/>
        <xsl:choose>
            <xsl:when test="$element/descendant::*[local-name()='element'][count(ancestor::*[local-name()='element']) = $level]">
                <xsl:copy-of select="true()"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy-of select="false()"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

	<!-- 
		TESTE SI IL EXISTE DES ELEMENTS DE NIVEAU DONNE
	-->
    <xsl:template name="newLevelExist">
        <xsl:param name="level"/>
        <xsl:choose>
            <xsl:when test="//*[local-name()='element'][count(ancestor::*[local-name()='element']) = $level]">
                <xsl:copy-of select="true()"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy-of select="false()"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

	<!--
		TRAITEMENT DES ELEMENTS METIER (NIVEAU >= 2)
	-->
    <xsl:template name="computeChildElement">
        <xsl:param name="level"/>

		<!-- Parcours des éléments du niveau donné -->
        <xsl:for-each select="//*[local-name()='element'][count(ancestor::*[local-name()='element']) = $level]">
            <xsl:variable name="element" select="."/>
			<!-- Teste si l'élément peut faire l'objet d'un tableau -->
            <xsl:variable name="isValid">
                <xsl:call-template name="hasScndLevelElements">
                    <xsl:with-param name="element" select="$element"/>
                    <xsl:with-param name="level" select="$level + 2"/>
                </xsl:call-template>
            </xsl:variable>
            <xsl:if test="string($isValid)=string(true())">
				<!-- Teste si l'élément n'a pas déjà fait l'objet d'un tableau -->
                <xsl:variable name="isAlreadyComputed">
                    <xsl:call-template name="hasBeenAlreadyComputed">
                        <xsl:with-param name="name" select="$element/@name"/>
                        <xsl:with-param name="type" select="$element/@type"/>
                        <xsl:with-param name="level" select="$level"/>
                    </xsl:call-template>
                </xsl:variable>
                <xsl:if test="string($isAlreadyComputed)=string(false())">
					<!-- Traitement de l'élément -->
                    <xsl:call-template name="computeElement">
                        <xsl:with-param name="element" select="$element"/>
                        <xsl:with-param name="first" select="true()"/>
                        <xsl:with-param name="firstLevelChild" select="$level + 1"/>
                        <xsl:with-param name="lastLevelChild" select="$level + 3"/>
                    </xsl:call-template>
                </xsl:if>
            </xsl:if>
        </xsl:for-each>
		<!--Test d'existence des éléments d'un niveau supérieur 
				et appel récursif le cas échéant -->
        <xsl:variable name="newLevelExist">
            <xsl:call-template name="newLevelExist">
                <xsl:with-param name="level" select="$level + 1"/>
            </xsl:call-template>
        </xsl:variable>
        <xsl:if test="string($newLevelExist)=string(true())">
            <xsl:call-template name="computeChildElement">
                <xsl:with-param name="level" select="$level + 1"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>


	<!-- 
		TRAITEMENT D'UN ELEMENT
	-->
    <xsl:template name="computeElement">
        <xsl:param name="element"/>
        <xsl:param name="first"/>
        <xsl:param name="firstLevelChild"/>
        <xsl:param name="lastLevelChild"/>
        <xsl:param name="isOneLevel"/>
        <xsl:param name="isTwoLevel"/>
        <xsl:param name="graphParentLevel"/>
        <xsl:param name="graphParentNode"/>
        <xsl:param name="levelPosition"/>
        <xsl:choose>
			<!-- Traitement du premier élément de l'image -->
            <xsl:when test="string($first)=string(true())">
                <image name="{concat('Image_', $element/@name, '.gif')}">
                    <xsl:text>digraph {rankdir=LR; ranksep=0.5; edge [arrowhead=none];</xsl:text>
                    <xsl:text>subgraph{node0 [shape=box, label="</xsl:text>
                    <xsl:value-of select="$element/@name"/>
                    <xsl:text>" ]}</xsl:text>
					<!-- Traitement des sous-éléments -->
                    <xsl:call-template name="computeSubElements">
                        <xsl:with-param name="parentElement" select="$element"/>
                        <xsl:with-param name="firstLevelChild" select="$firstLevelChild"/>
                        <xsl:with-param name="lastLevelChild" select="$lastLevelChild"/>
                        <xsl:with-param name="graphParentNode">node0</xsl:with-param>
                        <xsl:with-param name="graphParentLevel">0</xsl:with-param>
                    </xsl:call-template>
                    <xsl:text>}</xsl:text>
                </image>
            </xsl:when>
            <xsl:otherwise>
			
				<!-- Traitement des sous-éléments -->
                <xsl:choose>
                    <xsl:when test="string($isOneLevel)=string(true())">
                        <xsl:call-template name="computeSubElements">
                            <xsl:with-param name="parentElement" select="$element"/>
                            <xsl:with-param name="firstLevelChild" select="$firstLevelChild"/>
                            <xsl:with-param name="lastLevelChild" select="$lastLevelChild"/>
                            <xsl:with-param name="graphParentLevel" select="$graphParentLevel"/>
                            <xsl:with-param name="graphParentNode" select="$graphParentNode"/>
                            <xsl:with-param name="levelPosition" select="$levelPosition"/>
                        </xsl:call-template>
                    </xsl:when>
                    <xsl:when test="string($isTwoLevel)=string(true())">
                        <xsl:call-template name="computeSubElements">
                            <xsl:with-param name="parentElement" select="$element"/>
                            <xsl:with-param name="firstLevelChild" select="$firstLevelChild"/>
                            <xsl:with-param name="lastLevelChild" select="$lastLevelChild"/>
                            <xsl:with-param name="graphParentLevel" select="$graphParentLevel"/>
                            <xsl:with-param name="graphParentNode" select="$graphParentNode"/>
                            <xsl:with-param name="levelPosition" select="$levelPosition"/>
                            <xsl:with-param name="isTwoLevel" select="$isTwoLevel"/>
                        </xsl:call-template>
                    </xsl:when>
                </xsl:choose>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
	
	<!-- 
		TRAITEMENT DES ELEMENTS FILS D'UN
		ELEMENT FAISANT L'OBJET D'UN TABLEAU
	-->
    <xsl:template name="computeSubElements">
        <xsl:param name="parentElement"/>
        <xsl:param name="firstLevelChild"/>
        <xsl:param name="lastLevelChild"/>
        <xsl:param name="graphParentNode"/>
        <xsl:param name="graphParentLevel"/>
        <xsl:param name="levelPosition"/>
        <xsl:param name="isTwoLevel"/>
		
		<!-- Teste si les éléments fils font parti d'un "choice" ou d'un "sequence"-->
        <xsl:variable name="isChoice">
            <xsl:choose>
                <xsl:when test="$parentElement/descendant::*[local-name()='element'][count(ancestor::*[local-name()='element']) = $firstLevelChild]/parent::*[local-name()='choice']">
                    <xsl:copy-of select="true()"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:copy-of select="false()"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:variable>
        <xsl:variable name="nextLevel">
            <xsl:value-of select="$graphParentLevel + 2"/>
        </xsl:variable>
        <xsl:variable name="currentLevel">
            <xsl:value-of select="$graphParentLevel"/>
        </xsl:variable>
        <xsl:variable name="interLevel">
            <xsl:value-of select="$graphParentLevel + 1"/>
        </xsl:variable>
        <xsl:variable name="intermediaireNode">
            <xsl:value-of select="concat($graphParentNode, 'To', $interLevel)"/>
        </xsl:variable>
        <xsl:variable name="subElements" select="$parentElement/descendant::*[local-name()='element'][count(ancestor::*[local-name()='element']) = $firstLevelChild]"/>
        <xsl:variable name="childCount">
            <xsl:choose>
                <xsl:when test="string($isTwoLevel) != string(true())">
                    <xsl:value-of select="count($subElements)"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="'1'"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:variable>
        <xsl:variable name="levelIndex">
            <xsl:if test="string($levelPosition) != ''">
                <xsl:value-of select="$levelPosition"/>
            </xsl:if>
        </xsl:variable>
		<!-- Définition du noeud choiceplus/sequenceplus/choiceminus/sequenceminus -->
        <xsl:value-of select="$intermediaireNode"/>
        <xsl:text> [shapefile="</xsl:text>
        <xsl:value-of select="$imagePrefixURL"/>
			<!-- Détermination de l'image -->
        <xsl:choose>
            <xsl:when test="string($isChoice) = string(true())">
                <xsl:choose>
                    <xsl:when test="string($isTwoLevel) = string(true())">
                        <xsl:text>choiceplus.gif</xsl:text>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:text>choiceminus.gif</xsl:text>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:when>
            <xsl:otherwise>
                <xsl:choose>
                    <xsl:when test="string($isTwoLevel) = string(true())">
                        <xsl:text>sequenceplus.gif</xsl:text>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:text>sequenceminus.gif</xsl:text>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:otherwise>
        </xsl:choose>
			<!-- Pas de label pour une image -->
        <xsl:text>", style=invis, label=""</xsl:text>
			<!-- Détermination de l'URL pour un élément faisant l'objet d'une image spécifique -->
        <xsl:choose>
            <xsl:when test="string($isTwoLevel) = string(true())">
                <xsl:text>, URL="#Image_</xsl:text>
                <xsl:value-of select="concat($parentElement/@name, '.gif')"/>
                <xsl:text>"</xsl:text>
            </xsl:when>
            <xsl:otherwise/>
        </xsl:choose>
        <xsl:text>];</xsl:text>
		<!-- Définition des noeuds du niveau intermédiaire -->
			<!-- Si l'élément ne fait pas l'objet d'une image spécifique -->
        <xsl:if test="string($isTwoLevel) != string(true())">
            <xsl:text>subgraph{rankdir=TB; rank=same; node [shape=point, style=invis]; edge [style="dashed"]</xsl:text>
            <xsl:choose>
                <xsl:when test="number($childCount) = 1">
                    <xsl:value-of select="concat('node', $interLevel, $levelIndex)"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:for-each select="$subElements">
                        <xsl:if test="position() != last()">
                            <xsl:value-of select="concat('node', $interLevel, $levelIndex, position())"/>-&gt;<xsl:value-of select="concat('node', $interLevel, $levelIndex, position() + 1)"/>
                            <xsl:text>;</xsl:text>
                        </xsl:if>
                    </xsl:for-each>
                </xsl:otherwise>
            </xsl:choose>
            <xsl:text>}</xsl:text>
        </xsl:if>
		<!-- Liaison noeud niveau parent - noeud choice / sequence - noeud fils -->
        <xsl:variable name="childNode">
            <xsl:choose>
                <xsl:when test="number($childCount) = 1">
                    <xsl:value-of select="concat('node', $interLevel, $levelIndex)"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="concat('node', $interLevel, $levelIndex, ceiling($childCount div 2))"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:variable>
        <xsl:value-of select="$graphParentNode"/>-&gt;<xsl:value-of select="$intermediaireNode"/>
        <xsl:text> [style=dotted];</xsl:text>
			<!-- Si l'élément ne fait pas l'objet d'une image spécifique -->
        <xsl:if test="string($isTwoLevel) != string(true())">
            <xsl:value-of select="$intermediaireNode"/>-&gt;<xsl:value-of select="$childNode"/>
            <xsl:text> [style=dotted];</xsl:text>
			<!-- Définition des noeuds du niveau suivant -->
            <xsl:text>subgraph{rankdir=TB; rank=same; node [shape=box]; edge [style=invis];</xsl:text>
				<!-- Définition des noeuds -->
            <xsl:for-each select="$subElements">
                <xsl:value-of select="concat('node', $nextLevel, $levelIndex, position())"/>
                <xsl:text> [label="</xsl:text>
                <xsl:value-of select="./@name"/>
                <xsl:text>"</xsl:text>
                <xsl:choose>
                    <xsl:when test="@minOccurs and number(@minOccurs) = 0">
                        <xsl:text>, style="dashed"</xsl:text>
                    </xsl:when>
                    <xsl:otherwise/>
                </xsl:choose>
                <xsl:text>];</xsl:text>
            </xsl:for-each>
				<!-- Lien entre les noeuds -->
            <xsl:for-each select="$subElements">
                <xsl:if test="position() != last()">
                    <xsl:value-of select="concat('node', $nextLevel, $levelIndex, position())"/>-&gt;<xsl:value-of select="concat('node', $nextLevel, $levelIndex, position() + 1)"/>
                    <xsl:text>;</xsl:text>
                </xsl:if>
            </xsl:for-each>
            <xsl:text>}</xsl:text>	
			<!-- Liaison noeuds intermédiaires - noeud fils -->
            <xsl:choose>
                <xsl:when test="number($childCount) = 1">
                    <xsl:variable name="minOccurs">
                        <xsl:call-template name="getMinOccurence">
                            <xsl:with-param name="minOccurs" select="$subElements[1]/@minOccurs"/>
                        </xsl:call-template>
                    </xsl:variable>
                    <xsl:value-of select="$childNode"/>-&gt;<xsl:value-of select="concat('node', $nextLevel, $levelIndex, $childCount)"/>
                    <xsl:text> [labeldistance=1.75, headlabel="</xsl:text>
                    <xsl:value-of select="$minOccurs"/>
                    <xsl:text>...</xsl:text>
                    <xsl:call-template name="getMaxOccurence">
                        <xsl:with-param name="maxOccurs" select="$subElements[1]/@maxOccurs"/>
                    </xsl:call-template>
                    <xsl:text>"</xsl:text>
                    <xsl:choose>
                        <xsl:when test="number($minOccurs) = 0">
                            <xsl:text>, style="dashed"</xsl:text>
                        </xsl:when>
                        <xsl:otherwise/>
                    </xsl:choose>
                    <xsl:text>];</xsl:text>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:for-each select="$subElements">
                        <xsl:variable name="minOccurs">
                            <xsl:call-template name="getMinOccurence">
                                <xsl:with-param name="minOccurs" select="@minOccurs"/>
                            </xsl:call-template>
                        </xsl:variable>
                        <xsl:value-of select="concat('node', $interLevel, $levelIndex, position())"/>-&gt;<xsl:value-of select="concat('node', $nextLevel, $levelIndex, position())"/>
                        <xsl:text> [labeldistance=1.75, headlabel="</xsl:text>
                        <xsl:value-of select="$minOccurs"/>
                        <xsl:text>...</xsl:text>
                        <xsl:call-template name="getMaxOccurence">
                            <xsl:with-param name="maxOccurs" select="@maxOccurs"/>
                        </xsl:call-template>
                        <xsl:text>"</xsl:text>
                        <xsl:choose>
                            <xsl:when test="number($minOccurs) = 0">
                                <xsl:text>, style="dashed"</xsl:text>
                            </xsl:when>
                            <xsl:otherwise/>
                        </xsl:choose>
                        <xsl:text>];</xsl:text>
                    </xsl:for-each>
                </xsl:otherwise>
            </xsl:choose>

			<!-- Parcours des éléments fils -->
            <xsl:for-each select="$subElements">
                <xsl:variable name="childElement" select="."/>
                <xsl:choose>
                    <xsl:when test="not($childElement/descendant::*[local-name()='element'])">
                        <xsl:call-template name="computeSimpleElement">
                            <xsl:with-param name="element" select="$childElement"/>
                            <xsl:with-param name="level" select="$nextLevel"/>
                            <xsl:with-param name="position" select="position()"/>
                        </xsl:call-template>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:choose>
                            <xsl:when test="not($childElement/descendant::*[local-name()='element'][count(ancestor::*[local-name()='element']) = $lastLevelChild])">
                                <xsl:call-template name="computeOneLevelElement">
                                    <xsl:with-param name="element" select="$childElement"/>
                                    <xsl:with-param name="level" select="$nextLevel"/>
                                    <xsl:with-param name="firstLevelChild" select="$firstLevelChild"/>
                                    <xsl:with-param name="lastLevelChild" select="$lastLevelChild"/>
                                    <xsl:with-param name="graphParentNode">
                                        <xsl:value-of select="concat('node', $nextLevel, position())"/>
                                    </xsl:with-param>
                                    <xsl:with-param name="levelPosition">
                                        <xsl:value-of select="position()"/>
                                    </xsl:with-param>
                                </xsl:call-template>
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:call-template name="computeTwoLevelElement">
                                    <xsl:with-param name="element" select="$childElement"/>
                                    <xsl:with-param name="level" select="$nextLevel"/>
                                    <xsl:with-param name="firstLevelChild" select="$firstLevelChild"/>
                                    <xsl:with-param name="lastLevelChild" select="$lastLevelChild"/>
                                    <xsl:with-param name="graphParentNode">
                                        <xsl:value-of select="concat('node', $nextLevel, position())"/>
                                    </xsl:with-param>
                                </xsl:call-template>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each>
        </xsl:if>
    </xsl:template>

	<!-- 
		????
	-->
    <xsl:template name="computeTwoLevelElement">
        <xsl:param name="element"/>
        <xsl:param name="level"/>
        <xsl:param name="graphParentNode"/>
        <xsl:param name="firstLevelChild"/>
        <xsl:param name="lastLevelChild"/>
        <xsl:call-template name="computeElement">
            <xsl:with-param name="element" select="$element"/>
            <xsl:with-param name="isTwoLevel" select="true()"/>
            <xsl:with-param name="graphParentLevel" select="$level"/>
            <xsl:with-param name="graphParentNode" select="$graphParentNode"/>
            <xsl:with-param name="firstLevelChild" select="$firstLevelChild + 1"/>
            <xsl:with-param name="lastLevelChild" select="$firstLevelChild + 3"/>
        </xsl:call-template>
    </xsl:template>

	<!-- 
		????
	-->
    <xsl:template name="computeOneLevelElement">
        <xsl:param name="element"/>
        <xsl:param name="level"/>
        <xsl:param name="firstLevelChild"/>
        <xsl:param name="lastLevelChild"/>
        <xsl:param name="graphParentNode"/>
        <xsl:param name="levelPosition"/>
        <xsl:call-template name="computeElement">
            <xsl:with-param name="element" select="$element"/>
            <xsl:with-param name="isOneLevel" select="true()"/>
            <xsl:with-param name="firstLevelChild" select="$firstLevelChild + 1"/>
            <xsl:with-param name="lastLevelChild" select="$firstLevelChild + 3"/>
            <xsl:with-param name="graphParentLevel" select="$level"/>
            <xsl:with-param name="graphParentNode" select="$graphParentNode"/>
            <xsl:with-param name="levelPosition" select="$levelPosition"/>
        </xsl:call-template>
    </xsl:template>

	<!-- 
		????
	-->
    <xsl:template name="computeSimpleElement">
        <xsl:param name="element"/>
        <xsl:param name="level"/>
        <xsl:param name="position"/>
    </xsl:template>
    <xsl:template name="getMinOccurence">
        <xsl:param name="minOccurs"/>
        <xsl:choose>
            <xsl:when test="string($minOccurs) = '' ">
                <xsl:value-of select="'1'"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$minOccurs"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    <xsl:template name="getMaxOccurence">
        <xsl:param name="maxOccurs"/>
        <xsl:choose>
            <xsl:when test="string($maxOccurs) = '' ">
                <xsl:value-of select="'1'"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:choose>
                    <xsl:when test="string($maxOccurs) = 'unbounded' ">
                        <xsl:value-of select="'*'"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="$maxOccurs"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>