<?xml version="1.0" encoding="UTF-8"?>
<!-- The task of this stylesheet is to transform a framework description made in XML into applicaction XML schema. -->
<!-- by Vaclav Cechticky & Ondrej Rohlik (Automatic Control Laboratory, ETH Zuerich) -->
<xsl:stylesheet version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:fmm="http://www.pnp-software.com/XFeature/fmm"
    xmlns:fm="http://www.pnp-software.com/XFeature/fmm"
    xmlns:dm="http://www.pnp-software.com/XFeature/displayModel"
    xmlns:inst="http://www.pnp-software.com/XFeature/instantiation"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exclude-result-prefixes="xsi">
    <!-- To clarify: fm is needed for input xfm document and fmm is needed for output document -->
    <xsl:output method="xml"/>
    <!-- ========================================================================= -->
    <!-- The template matches any node. -->
    <xsl:template match="/">
        <xs:schema targetNamespace="http://www.pnp-software.com/XFeature/fmm"
            xmlns:xs="http://www.w3.org/2001/XMLSchema"
            xmlns:dm="http://www.pnp-software.com/XFeature/displayModel"
            xmlns:fmm="http://www.pnp-software.com/XFeature/fmm"
            xmlns:fm="http://www.pnp-software.com/XFeature/fmm"
            xmlns:inst="http://www.pnp-software.com/XFeature/instantiation" 
            elementFormDefault="qualified"
            attributeFormDefault="qualified" 
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
            xsi:schemaLocation="http://www.w3.org/2001/XMLSchema ../../general_files/MetaMetaModel.xfmmm">
            <xs:annotation>
                <xs:appinfo>
                    <dm:OxygenToolXPathWorkaround/>
                </xs:appinfo>
            </xs:annotation>
            <xs:simpleType name="zero2inf">
                <xs:restriction base="xs:token">
                    <xs:pattern value="([1-9][0-9]*|0|\+|\*)"/>
                </xs:restriction>
            </xs:simpleType>
            <xs:simpleType name="one2inf">
                <xs:restriction base="xs:token">
                    <xs:pattern value="([1-9][0-9]*|\+|\*)"/>
                </xs:restriction>
            </xs:simpleType>
            <xs:simpleType name="greaterThanZero">
                <xs:restriction base="xs:token">
                    <xs:pattern value="([1-9][0-9]*)"/>
                </xs:restriction>
            </xs:simpleType>
            <!-- Definition of simple elements -->
            <xs:attribute name="name" type="xs:string"/>
            <xs:attribute name="type" type="xs:string"/>
            <xs:attribute name="cardMin" type="fmm:zero2inf"/>
            <xs:attribute name="cardMax" type="fmm:one2inf"/>
            <xs:attribute name="value" type="xs:string"/>
            <xs:attribute name="text" type="xs:string"/>
            <xsl:apply-templates/>
            <!--  select="//fm:GroupedFeatureNode" -->
            <!-- TBDeleted -->
            <!-- <xsl:call-template name="CreateDescriptionElement"/> -->
            <!-- TBDeleted -->
            <!-- ============================ Property Sets ========================= -->
            <!-- COMPONENTS (if GENERABLE) -->
            <xsl:if test="//fm:ComponentPropertySet/fm:StatusProperty/@fm:value='generable'">
                <xs:element name="ComponentInstantiationPropertySet">
                    <xs:complexType dm:displayType="propertySet">
                        <xs:sequence>
                            <xs:element ref="fmm:MissingClassNameProperty"/>
                        </xs:sequence>
                        <xs:attribute ref="fmm:value" use="required"/>
                    </xs:complexType>
                </xs:element>
                <xs:element name="MissingClassNameProperty">
                    <xs:complexType dm:displayType="property">
                        <xs:attribute name="value" type="xs:string" use="required"/>
                    </xs:complexType>
                </xs:element>
            </xsl:if>
            <!-- ATTRIBUTES incl. Enumeration -->
            <xsl:for-each-group select="//fm:Attribute" group-by="fm:AttributeName/@fm:value">
                <xsl:variable name="featureName" select="fm:AttributeName/@fm:value"/>
                <xsl:variable name="featureType" select="fm:AttributeType/@fm:value"/>
                <xs:element name="{$featureName}PropertySet">
                    <xs:complexType dm:displayType="propertySet">
                        <xs:sequence>
                            <xs:element ref="fmm:{$featureName}Property"/>
                        </xs:sequence>
                        <xs:attribute ref="fmm:value" use="required"/>
                    </xs:complexType>
                </xs:element>
                <xsl:choose>
                    <xsl:when test="fm:AttributeType/@fm:value">
                        <xs:element name="{$featureName}Property">
                            <xs:complexType dm:displayType="property">
                                <xs:attribute name="value" type="{$featureType}" use="required"/>
                            </xs:complexType>
                        </xs:element>
                    </xsl:when>
                    <xsl:otherwise>
                        <xs:simpleType name="{$featureName}Enumeration">
                            <xs:restriction base="xs:string">
                                <xsl:for-each select="fm:ValueItemProperty">
                                    <xs:enumeration value="{@fm:value}"/>
                                </xsl:for-each>
                            </xs:restriction>
                        </xs:simpleType>
                        <xs:element name="{$featureName}Property">
                            <xs:complexType dm:displayType="property">
                                <xs:attribute name="value" type="fmm:{$featureName}Enumeration" use="required"/>
                            </xs:complexType>
                        </xs:element>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each-group>
            
            <xs:element name="Annotation">
                <xs:complexType dm:displayType="propertySet">
                    <xs:sequence>
                        <xs:element ref="fmm:ShortDescription" minOccurs="0"/>
                        <xs:element ref="fmm:LongDescription" minOccurs="0"/>
                        <xs:element ref="fmm:Comment" minOccurs="0"/>
                        <xs:element ref="fmm:Hyperlink" minOccurs="0"/>
                    </xs:sequence>
                    <xs:attribute ref="fmm:value" use="required"/>
                </xs:complexType>
            </xs:element>
            <xs:element name="ShortDescription">
                <xs:complexType dm:displayType="property">
                    <xs:attribute ref="fmm:value" use="required"/>
                </xs:complexType>
            </xs:element>
            <xs:element name="LongDescription">
                <xs:complexType dm:displayType="property">
                    <xs:attribute ref="fmm:value" use="required"/>
                </xs:complexType>
            </xs:element>
            <xs:element name="Comment">
                <xs:complexType dm:displayType="property">
                    <xs:attribute ref="fmm:value" use="required"/>
                </xs:complexType>
            </xs:element>
            <xs:element name="Hyperlink">
                <xs:complexType dm:displayType="property">
                    <xs:attribute ref="fmm:value" use="required"/><!-- this can probably be made more precise to enforce the structure of a URL ... with pattern -->
                </xs:complexType>
            </xs:element>
            
        </xs:schema>
    </xsl:template>
    <!-- end of template for the main xs:schema element -->
    <!-- ========================================================================= -->
    <!-- The template matches Feature element. -->
    <xsl:template match="/fm:FeatureModel">
        <xs:element name="FeatureModel">
            <xs:complexType dm:displayType="root">
                <xs:sequence>
                    <xs:element ref="fmm:{/fm:FeatureModel/fm:SolitaryFeatureNode/@fm:value}"/>
                    <!-- Say, there will be no Annotation here (it is not obligatory, you know) -->
                </xs:sequence>
                <xs:attribute ref="fmm:value" use="required"/>
            </xs:complexType>
        </xs:element>
        <xsl:apply-templates/>
    </xsl:template>
    <!-- ========================================================================= -->
    <!-- The template matches Feature element. -->
    <xsl:template match="//fm:GroupedFeatureNode">
        <!-- just a defensive programming test -->
        <xsl:if test="not(fm:FeatureCardinality/@fm:cardMax='+' or fm:FeatureCardinality/@fm:cardMax='*' or fm:FeatureCardinality/@fm:cardMax='unbound')">
            <xsl:if test="fm:FeatureCardinality/@fm:cardMin gt fm:FeatureCardinality/@fm:cardMax">
                <xsl:message terminate="yes">ERROR: min cardinality (<xsl:value-of select="fm:FeatureCardinality/@fm:cardMin"/>) has to be less or equal to max cardinality (<xsl:value-of select="fm:FeatureCardinality/@fm:cardMax"/>).</xsl:message>
            </xsl:if>
        </xsl:if>   
        <xsl:call-template name="ProcessFeature"/>
        <xsl:apply-templates/>
    </xsl:template>
    <!-- ========================================================================= -->
    <!-- The template matches Feature element. -->
    <xsl:template match="//fm:MacroFeatureNode"> 
        <xsl:call-template name="ProcessFeature"/>
        <xsl:apply-templates/>
    </xsl:template>
    <!-- ========================================================================= -->
    <!-- The template matches Feature element. -->
    <xsl:template match="//fm:SolitaryFeatureNode">
        <!-- just a defensive programming test -->
        <xsl:if test="not(fm:FeatureCardinality/@fm:cardMax='+' or fm:FeatureCardinality/@fm:cardMax='*' or fm:FeatureCardinality/@fm:cardMax='unbound')">
            <xsl:if test="fm:FeatureCardinality/@fm:cardMin gt fm:FeatureCardinality/@fm:cardMax">
                <xsl:message terminate="yes">ERROR: min cardinality (<xsl:value-of select="fm:FeatureCardinality/@fm:cardMin"/>) has to be less or equal to max cardinality (<xsl:value-of select="fm:FeatureCardinality/@fm:cardMax"/>).</xsl:message>
            </xsl:if>
        </xsl:if>     
        <xsl:call-template name="ProcessFeature"/>
        <xsl:apply-templates/>
    </xsl:template>  
    <!-- ========================================================================= -->
    <!-- The template matches Group element -->
    <xsl:template match="//fm:GroupNode">
        <!-- create a new group -->
        <xs:group name="{@fm:value}">
            <!-- ========================================================================= -->
            <xsl:if test="not(fm:GroupCardinality/@fm:cardMax='+' or fm:GroupCardinality/@fm:cardMax='*' or fm:GroupCardinality/@fm:cardMax='unbound')">
                <xsl:if test="fm:GroupCardinality/@fm:cardMin gt fm:GroupCardinality/@fm:cardMax">
                    <xsl:message terminate="yes">ERROR: min cardinality (<xsl:value-of select="fm:GroupCardinality/@fm:cardMin"/>) has to be less or equal to max cardinality (<xsl:value-of select="fm:GroupCardinality/@fm:cardMax"/>).</xsl:message>
                </xsl:if>
                <xsl:if test="(count(child::fm:GroupedFeatureNode) + count(child::fm:CallMacroNode)) &lt; fm:GroupCardinality/@fm:cardMax">
                    <xsl:message terminate="yes">ERROR: there are less child elements (<xsl:value-of select="count(child::fm:GroupedFeatureNode) + count(child::fm:CallMacroNode)"/>) of group '<xsl:value-of select="@fm:value"/>' than is the max cardinality (<xsl:value-of select="fm:GroupCardinality/@fm:cardMax"/>) of the group.</xsl:message>
                </xsl:if>
            </xsl:if>   
            <!-- It processes a group cardinality in case that the minimal cardinality is 1 and maximal 1 -->
            <xsl:if test="(fm:GroupCardinality/@fm:cardMin=1) and (fm:GroupCardinality/@fm:cardMax=1)">
                <xsl:if test="count(child::fm:GroupedFeatureNode | child::fm:CallMacroNode)=1">
                    <xsl:if test="(count(child::fm:GroupedFeatureNode)=1) and (count(child::fm:CallMacroNode)=0)">
                        <xs:sequence>
                            <xsl:for-each select="fm:GroupedFeatureNode">
                                <xsl:call-template name="RefGroupedFeature"/>
                            </xsl:for-each>
                        </xs:sequence>
                    </xsl:if>
                    <xsl:if test="(count(child::fm:GroupedFeatureNode)=0) and (count(child::fm:CallMacroNode)=1)">
                        <xs:sequence>
                            <xsl:for-each select="fm:CallMacroNode">
                                <xsl:call-template name="RefCallMacro"/>
                            </xsl:for-each>
                        </xs:sequence>
                    </xsl:if>
                </xsl:if>
                <xsl:if test="count(child::fm:GroupedFeatureNode | child::fm:CallMacroNode)&gt;1">
                    <xs:choice>
                        <xsl:for-each select="fm:GroupedFeatureNode">
                            <xsl:call-template name="RefGroupedFeature"/>
                        </xsl:for-each>
                        <xsl:for-each select="fm:CallMacroNode">
                            <xsl:call-template name="RefCallMacro"/>
                        </xsl:for-each>
                    </xs:choice>
                </xsl:if>
            </xsl:if>
            <!-- ========================================================================= -->
            <!-- It processes a group cardinality in case that the minimal cardinality is 1 and maximal bigger than 1 -->
            <xsl:if test="(fm:GroupCardinality/@fm:cardMin&gt;=1) and (fm:GroupCardinality/@fm:cardMax&gt;1)">
                <xs:choice>
                    <xsl:call-template name="ExpandGroupCardinality">
                        <xsl:with-param name="minCard" select="fm:GroupCardinality/@fm:cardMin"/>
                        <xsl:with-param name="maxCard" select="fm:GroupCardinality/@fm:cardMax"/>
                    </xsl:call-template>
                </xs:choice>
            </xsl:if>
            <!-- ========================================================================= -->
            <!-- It processes a group cardinality in case that the minimal cardinality is 0 and maximal equal or bigger than 1 -->
            <xsl:if test="(fm:GroupCardinality/@fm:cardMin=0) and (fm:GroupCardinality/@fm:cardMax&gt;=1)">
                <xs:choice>
                    <xsl:call-template name="ExpandGroupCardinality">
                        <xsl:with-param name="minCard" select="1"/>
                        <xsl:with-param name="maxCard" select="fm:GroupCardinality/@fm:cardMax"/>
                    </xsl:call-template>
                </xs:choice>
            </xsl:if>
        </xs:group>
        <xsl:apply-templates/>
    </xsl:template>
    <!-- ========================================================================= -->
    <!-- The template makes all possible combinations of GroupedFeatures defined in a group based on group cardinality. -->
    <xsl:template name="ExpandGroupCardinality">
        <!-- store minimal group cardinality -->
        <xsl:param name="minCard"/>
        <!-- store maximal group cardinality -->
        <xsl:param name="maxCard"/>
        <xsl:variable name="minCombinationLength" select="$minCard"/>
        <xsl:variable name="maxCombinationLength" select="$maxCard"/>
        <!-- the current length of the combination -->
        <xsl:variable name="currentLength" select="1"/>
        <!-- The loop makes combinations for each feature or callmacro that is direct child of the group element,
		the length of combinations is driven by minimal and maximal combination length. -->
        <xsl:for-each select="fm:GroupedFeatureNode | fm:CallMacroNode">
            <xsl:if test="count(following-sibling::fm:GroupedFeatureNode | following-sibling::fm:CallMacroNode)&gt;=($minCombinationLength+(-1))">
                <xs:sequence>
                    <xsl:if test="self::fm:GroupedFeatureNode">
                        <xsl:call-template name="RefGroupedFeature"/>
                    </xsl:if>
                    <xsl:if test="self::fm:CallMacroNode">
                        <xsl:call-template name="RefCallMacro"/>
                    </xsl:if>
                    <xsl:if test="count(following-sibling::fm:GroupedFeatureNode | following-sibling::fm:CallMacroNode)&gt;=1">
                        <!-- it calls template where the combination are made by recursion -->
                        <xsl:call-template name="MakeCombinations">
                            <xsl:with-param name="list" select="following-sibling::fm:GroupedFeatureNode | following-sibling::fm:CallMacroNode"/>
                            <xsl:with-param name="minCombinationLength" select="$minCombinationLength"/>
                            <xsl:with-param name="maxCombinationLength" select="$maxCombinationLength"/>
                            <xsl:with-param name="currentLength" select="$currentLength+1"/>
                        </xsl:call-template>
                    </xsl:if>
                </xs:sequence>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
    <!-- ========================================================================= -->
    <!-- The template MakeCombinations is called from ExpandGroupCardinality template. MakeCombination makes the combination by recursion. -->
    <xsl:template name="MakeCombinations">
        <xsl:param name="list"/>
        <xsl:param name="minCombinationLength"/>
        <xsl:param name="maxCombinationLength"/>
        <xsl:param name="currentLength"/>
        <xsl:if test="($minCombinationLength&gt;=$currentLength) and ($maxCombinationLength&gt;$currentLength) and count($list)&gt;=1">
            <xs:choice>
                <xsl:for-each select="$list">
                    <xsl:if test="(count(following-sibling::fm:GroupedFeatureNode | following-sibling::fm:CallMacroNode)&gt;=($maxCombinationLength+(-$currentLength))) or (count(following-sibling::fm:GroupedFeatureNode | following-sibling::fm:CallMacroNode)&gt;=($minCombinationLength+(-$currentLength)))">
                        <xs:sequence>
                            <xsl:if test="self::fm:GroupedFeatureNode">
                                <xsl:call-template name="RefGroupedFeature"/>
                            </xsl:if>
                            <xsl:if test="self::fm:CallMacroNode">
                                <xsl:call-template name="RefCallMacro"/>
                            </xsl:if>
                            <xsl:call-template name="MakeCombinations">
                                <xsl:with-param name="list" select="following-sibling::fm:GroupedFeatureNode | following-sibling::fm:CallMacroNode"/>
                                <xsl:with-param name="minCombinationLength" select="$minCombinationLength"/>
                                <xsl:with-param name="maxCombinationLength" select="$maxCombinationLength"/>
                                <xsl:with-param name="currentLength" select="$currentLength+1"/>
                            </xsl:call-template>
                        </xs:sequence>
                    </xsl:if>
                </xsl:for-each>
            </xs:choice>
        </xsl:if>
        <xsl:if test="($minCombinationLength&lt;$currentLength) and ($maxCombinationLength&gt;$currentLength) and count($list)&gt;=1">
            <xs:choice minOccurs="0">
                <xsl:for-each select="$list">
                    <xsl:if test="(count(following-sibling::fm:GroupedFeatureNode | following-sibling::fm:CallMacroNode)&gt;=($maxCombinationLength+(-$currentLength))) or (count(following-sibling::fm:GroupedFeatureNode | following-sibling::fm:CallMacroNode)&gt;=($minCombinationLength+(-$currentLength)))">
                        <xs:sequence>
                            <xsl:if test="self::fm:GroupedFeatureNode">
                                <xsl:call-template name="RefGroupedFeature"/>
                            </xsl:if>
                            <xsl:if test="self::fm:CallMacroNode">
                                <xsl:call-template name="RefCallMacro"/>
                            </xsl:if>
                            <xsl:call-template name="MakeCombinations">
                                <xsl:with-param name="list" select="following-sibling::fm:GroupedFeatureNode | following-sibling::fm:CallMacroNode"/>
                                <xsl:with-param name="minCombinationLength" select="$minCombinationLength"/>
                                <xsl:with-param name="maxCombinationLength" select="$maxCombinationLength"/>
                                <xsl:with-param name="currentLength" select="$currentLength+1"/>
                            </xsl:call-template>
                        </xs:sequence>
                    </xsl:if>
                </xsl:for-each>
            </xs:choice>
        </xsl:if>
        <xsl:if test="($currentLength=$maxCombinationLength) and ($minCombinationLength=$maxCombinationLength) and count($list)&gt;=1">
            <xs:choice>
                <xsl:for-each select="$list">
                    <xsl:if test="self::fm:GroupedFeatureNode">
                        <xsl:call-template name="RefGroupedFeature"/>
                    </xsl:if>
                    <xsl:if test="self::fm:CallMacroNode">
                        <xsl:call-template name="RefCallMacro"/>
                    </xsl:if>
                </xsl:for-each>
            </xs:choice>
        </xsl:if>
        <xsl:if test="($currentLength=$maxCombinationLength) and ($minCombinationLength&lt;$maxCombinationLength) and count($list)&gt;=1">
            <xs:choice minOccurs="0">
                <xsl:for-each select="$list">
                    <xsl:if test="self::fm:GroupedFeatureNode">
                        <xsl:call-template name="RefGroupedFeature"/>
                    </xsl:if>
                    <xsl:if test="self::fm:CallMacroNode">
                        <xsl:call-template name="RefCallMacro"/>
                    </xsl:if>
                </xsl:for-each>
            </xs:choice>
        </xsl:if>
    </xsl:template>
    <!-- ========================================================================= -->
    <!-- ProcessFeature template processes the tag 'Feature'. -->
    <xsl:template name="ProcessFeature">
        <xs:element name="{@fm:value}">
            <!-- process feature properties, description, group and type -->
            <!-- XXX O.R. next line ommitted for XFeature XXX -->
            <!-- <xsl:call-template name="Description"/> -->
            <xs:complexType dm:displayType="node">
                <xsl:call-template name="Documentation"/>
                <xs:sequence>
                    <xsl:choose>                            
                        <xsl:when test="*[substring-before(name(),'__')='fm:Annotation']">
                            <!--<xsl:variable name="parentName" select="parent::*/@fm:value"/>-->
                            <!--<xsl:variable name="newAnnotantioName" select="concat(@fm:value,'__',$parentName)"/>-->
                            <!--<xsl:message>parentName: <xsl:value-of select="$parentName"/>, new: <xsl:value-of select="$newAnnotantioName"/></xsl:message>-->
                            <!--<xsl:variable name="newAnnotationName" select="concat('Annotation__',@fm:value)"/>-->
                            <!--<xsl:message>newAnnotationName: <xsl:value-of select="$newAnnotationName"/></xsl:message>-->

                            <!--<xsl:message> #################################### <xsl:value-of select="local-name()"/> ### </xsl:message>-->
                            <!--<xsl:variable name="num" select="count(preceding::fm:Annotation | ancestor::fm:Annotation)"/>-->
                            <xsl:variable name="AnnotationNode" select="*[substring-before(name(),'__')='fm:Annotation']"/>
                            <xsl:variable name="numberAnnotation" select="substring-after(name($AnnotationNode),'__')"/>
                            <xsl:variable name="newAnnotationName" select="concat('Annotation','__',$numberAnnotation)"/>

                            <xs:element ref="fmm:{$newAnnotationName}"  minOccurs="1"/><!-- ESTEC -->
                        </xsl:when>
                        <xsl:otherwise>
                            <xs:element ref="fmm:Annotation" minOccurs="0"/>
                        </xsl:otherwise>
                    </xsl:choose>
                    <xsl:if test="*[substring-before(name(),'__')='fm:DesignMapping']">
                            <xsl:variable name="DesignMappingNode" select="*[substring-before(name(),'__')='fm:DesignMapping']"/>
                            <xsl:variable name="numberDesignMapping" select="substring-after(name($DesignMappingNode),'__')"/>
                            <xsl:variable name="newDesignMappingName" select="concat('DesignMapping','__',$numberDesignMapping)"/>
                            
                            <xs:element ref="fmm:{$newDesignMappingName}"  minOccurs="1"/>
                    </xsl:if>
                    <xsl:if test="fm:Attribute">
                        <xsl:variable name="AttributeNode" select="fm:Attribute"/>
                        <xsl:variable name="AttributeParentName" select="@fm:value"/>
                        <!--<xsl:comment><xsl:value-of select="concat($AttributeParentName,'_Attributes')"/></xsl:comment>-->
                        <!--
                        <xsl:if test="*[substring-before(name(),'__')='fm:Attribute']/fm:AttributeRequired[@fm:value='true']">
                        </xsl:if>
                        -->
                            <!--<xsl:message>>>>>>>>>>>>>>>>>>> AttributeNode: <xsl:value-of select="$AttributeNode"/></xsl:message>-->
                            <!-- Here comes FOR each Attribute -->
                                <xs:element ref="fmm:{concat($AttributeParentName,'_Attributes')}">
                                    <xsl:attribute name="minOccurs">
                                        <xsl:choose>
                                            <xsl:when test="fm:Attribute/fm:AttributeRequired[@fm:value='true']">
                                                <xsl:value-of select="1"/>
                                            </xsl:when>
                                            <xsl:otherwise>
                                                <xsl:value-of select="0"/>
                                            </xsl:otherwise>
                                        </xsl:choose>
                                    </xsl:attribute>
                                </xs:element>
                                <!-- <xs:element ref="fmm:{$newAttributeName}">
                                    <xsl:attribute name="minOccurs">
                                        <xsl:choose>
                                            <xsl:when test="fm:AttributeRequired/@fm:value='true'">
                                                <xsl:value-of select="1"/>
                                            </xsl:when>
                                            <xsl:otherwise>
                                                <xsl:value-of select="0"/>
                                            </xsl:otherwise>
                                        </xsl:choose>
                                    </xsl:attribute>
                                </xs:element> -->                            
                    </xsl:if>
                    <!-- it makes a  reference to globally defined 'Description' element -->
                    <!-- XXX O.R. next line ommitted for XFeature XXX -->
                    <!-- <xs:element ref="Description" minOccurs="0"/> -->
                    <xsl:for-each select="fm:SolitaryFeatureNode">
                        <xsl:choose>
                            <!--<xsl:when test="(fm:FeatureCardinality/@fm:cardMin=0) and (fm:FeatureCardinality/@fm:cardMax&gt;=1)">
                <xs:group ref="fmm:{@fm:value}" minOccurs="0"/>
              </xsl:when>-->
                            <xsl:when test="fm:SolitaryFeatureCardinality">
                                <xs:element ref="fmm:{@fm:value}">
                                    <xsl:attribute name="minOccurs">
                                        <xsl:value-of select="fm:SolitaryFeatureCardinality/@fm:cardMin"/>
                                    </xsl:attribute>
                                    <xsl:attribute name="maxOccurs">
                                        
                                        <xsl:choose>
                                            <xsl:when test="(fm:SolitaryFeatureCardinality/@fm:cardMax='+') or (fm:SolitaryFeatureCardinality/@fm:cardMax='*')">
                                                
                                                <xsl:value-of select="'unbounded'"/>
                                            </xsl:when>
                                            <xsl:otherwise>
                                                <xsl:value-of select="fm:SolitaryFeatureCardinality/@fm:cardMax"/>
                                            </xsl:otherwise>
                                        </xsl:choose>
                                        
                                        <!--<xsl:value-of select="fm:SolitaryFeatureCardinality/@fm:cardMax"/>-->
                                    </xsl:attribute>
                                </xs:element>
                            </xsl:when>
                            <xsl:otherwise>
                                <xs:element ref="fmm:{@fm:value}"/>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:for-each>
                    <xsl:for-each select="fm:GroupNode">
                        <xsl:choose>
                            <xsl:when test="(fm:GroupCardinality/@fm:cardMin=0) and (fm:GroupCardinality/@fm:cardMax&gt;=1)">
                                <xs:group ref="fmm:{@fm:value}" minOccurs="0"/>
                            </xsl:when>
                            <xsl:otherwise>
                                <!-- it makes a  reference to globally defined group element -->
                                <xs:group ref="fmm:{@fm:value}"/>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:for-each>
                    <xsl:call-template name="PropertySet"/>
                </xs:sequence>
                <!-- This calls 'Type' template that is further processing different subtypes. -->
                <!-- XXX to be changed to choice of propertySet -->
                <!-- <xsl:call-template name="PropertySet"/> -->
                <xs:attribute ref="fmm:value" use="required"/>
            </xs:complexType>
        </xs:element>
        
        
        <xsl:if test="fm:Attribute">
            <xsl:variable name="attributesName"><xsl:value-of select="concat(@fm:value,'_Attributes')"/></xsl:variable>
            <xsl:comment>v=====================================================</xsl:comment>
            <xs:element name="{$attributesName}">
                <xs:complexType dm:displayType="propertySet">
                    <xs:sequence>
                        <xsl:for-each select="fm:Attribute">
                            <xs:element name="{fm:AttributeName/@fm:value}">
                                <xsl:attribute name="minOccurs">
                                    <xsl:choose>
                                        <xsl:when test="fm:AttributeRequired/@fm:value='true'">1</xsl:when>
                                        <xsl:otherwise>0</xsl:otherwise> 
                                    </xsl:choose>
                                </xsl:attribute>
                                <xs:complexType dm:displayType="property">
                                    <xsl:choose>
                                        <xsl:when test="fm:AttributeDefaultValue">
                                            <xs:attribute name="value" type="{fm:AttributeType/@fm:value}" default="{fm:AttributeDefaultValue/@fm:value}"/>
                                        </xsl:when>
                                        <xsl:otherwise>
                                            <xs:attribute name="value" type="{fm:AttributeType/@fm:value}"/>
                                        </xsl:otherwise>
                                    </xsl:choose>
                                </xs:complexType>
                            </xs:element> 
                            <xsl:if test="fm:AttributeDescription">
                                <xs:element name="{fm:AttributeName/@fm:value}_Description">
                                    <xsl:attribute name="minOccurs">
                                        <xsl:choose>
                                            <xsl:when test="fm:AttributeRequired/@fm:value='true'">1</xsl:when>
                                            <xsl:otherwise>0</xsl:otherwise> 
                                        </xsl:choose>
                                    </xsl:attribute>
                                    <xs:complexType dm:displayType="property">
                                        <xsl:choose>
                                            <xsl:when test="fm:AttributeDescription">
                                                <xs:attribute name="value" type="xs:string" default="{fm:AttributeDescription/@fm:value}"/>
                                            </xsl:when>
                                            <xsl:otherwise>
                                                <xs:attribute name="value" type="xs:string"/>
                                            </xsl:otherwise>
                                        </xsl:choose>
                                    </xs:complexType>
                                </xs:element> 
                            </xsl:if>
                        </xsl:for-each>
                    </xs:sequence>    
                    <xs:attribute name="value" type="xs:string" default="{AttributeName/@fm:value}" use="optional"/>
                </xs:complexType>
            </xs:element>
            <xsl:comment>^=====================================================</xsl:comment>
        </xsl:if>        
            
           
    </xsl:template>
    <!-- ========================================================================= -->
    <!-- RefGroupedFeature template processes the tag 'GroupedFeature'. -->
    <xsl:template name="RefGroupedFeature">
        <xsl:choose>
            <xsl:when test="(fm:FeatureCardinality/@fm:cardMax='+') or (fm:FeatureCardinality/@fm:cardMax='*')">
                <xs:element ref="fmm:{@fm:value}">
                    <xsl:attribute name="minOccurs">
                        <xsl:value-of select="fm:FeatureCardinality/@fm:cardMin"/>
                    </xsl:attribute>
                    <xsl:attribute name="maxOccurs">
                        <xsl:value-of select="'unbounded'"/>
                    </xsl:attribute>
                </xs:element>
            </xsl:when>
            <xsl:otherwise>
                <xsl:if test="(fm:FeatureCardinality/@fm:cardMax&gt;=1)">
                    <xs:element ref="fmm:{@fm:value}">
                        <xsl:attribute name="minOccurs">
                            <xsl:value-of select="fm:FeatureCardinality/@fm:cardMin"/>
                        </xsl:attribute>
                        <xsl:attribute name="maxOccurs">
                            <xsl:value-of select="fm:FeatureCardinality/@fm:cardMax"/>
                        </xsl:attribute>
                    </xs:element>
                </xsl:if>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    <!-- ========================================================================= -->
    <!-- RefGroupedFeatureMinZero template processes the tag 'GroupedFeature'. -->
    <xsl:template name="RefGroupedFeatureMinOccursZero">
        <xsl:if test="(fm:FeatureCardinality/@fm:cardMax&gt;=1)">
            <xs:element ref="fmm:{@fm:value}">
                <xsl:attribute name="minOccurs">
                    <xsl:value-of select="0"/>
                </xsl:attribute>
                <xsl:attribute name="maxOccurs">
                    <xsl:value-of select="fm:FeatureCardinality/@fm:cardMax"/>
                </xsl:attribute>
            </xs:element>
        </xsl:if>
        <xsl:if test="(fm:FeatureCardinality/@fm:cardMax='+') or (fm:FeatureCardinality/@fm:cardMax='*')">
            <xs:element ref="fmm:{@fm:value}">
                <xsl:attribute name="minOccurs">
                    <xsl:value-of select="0"/>
                </xsl:attribute>
                <xsl:attribute name="maxOccurs">
                    <xsl:value-of select="'unbounded'"/>
                </xsl:attribute>
            </xs:element>
        </xsl:if>
    </xsl:template>
    <!-- ========================================================================= -->
    <!-- RefCallMacro template processes the tag 'CallMacro'. -->
    <xsl:template name="RefCallMacro">
        <xsl:variable name="mName" select="@fm:value"/>
        <xsl:variable name="curr" select="."/>
        <xsl:variable name="min" select="fm:FeatureCardinality/@fm:cardMin"/>
        <xsl:variable name="max" select="fm:FeatureCardinality/@fm:cardMax"/>
        <!-- XXX O.R. Marco_Name ma dve zvlastnosti: 1) ma podrzitko a 2) nema namespace -->
        <xsl:choose>
            <xsl:when test="//fm:MacroFeatureNode[@fm:value=$mName]">
                <xsl:for-each select="//fm:MacroFeatureNode[@fm:value=$mName]">
                    
                    <!--<xsl:for-each select="fm:GroupedFeatureNode">-->
                    <!--<xsl:call-template name="RefGroupedFeature"/>-->
                    <!--</xsl:for-each>-->
                    
                    <xsl:choose>
                        <xsl:when test="(string($max) = '+') or (string($max) = '*')">
                            <xs:element ref="fmm:{@fm:value}">
                                <xsl:attribute name="minOccurs">
                                    <xsl:value-of select="$min"/>
                                </xsl:attribute>
                                <xsl:attribute name="maxOccurs">
                                    <xsl:value-of select="'unbounded'"/>
                                </xsl:attribute>
                            </xs:element>
                        </xsl:when>
                        <xsl:otherwise>
                            <!--<xsl:if test="($max&gt;=1)">-->
                            <xs:element ref="fmm:{@fm:value}">
                                <xsl:attribute name="minOccurs">
                                    <xsl:value-of select="$min"/>
                                </xsl:attribute>
                                <xsl:attribute name="maxOccurs">
                                    <xsl:value-of select="$max"/>
                                </xsl:attribute>
                            </xs:element>
                            <!--</xsl:if>-->
                        </xsl:otherwise>
                    </xsl:choose>
                    
                </xsl:for-each>
            </xsl:when>
            <xsl:otherwise>
                <xsl:message terminate="yes">ERROR: Called macro <xsl:value-of select="$mName"/> does NOT exist.</xsl:message>
            </xsl:otherwise>
        </xsl:choose>
        
    </xsl:template>
    <!-- ========================================================================= -->
    <!-- RefCallMacroMinOccursZero template processes the tag 'CallMacro'. -->
    <xsl:template name="RefCallMacroMinOccursZero">
        <xsl:variable name="mName" select="fm:MacroNameProperty/@fm:value"/>
        <!-- XXX O.R. Marco_Name ma dve zvlastnosti: 1) ma podrzitko a 2) nema namespace -->
        <xsl:for-each select="//fm:MacroFeatureNode[@fm:value=$mName]">
            <xsl:for-each select="fm:GroupedFeatureNode">
                <xsl:call-template name="RefGroupedFeatureMinOccursZero"/>
            </xsl:for-each>
        </xsl:for-each>
    </xsl:template>
    <!-- ========================================================================= -->
    <xsl:template name="PropertySet">
        
        <!--
        <xsl:if test="fm:DesignMapping">
            <xsl:call-template name="DesignMapping"/>
        </xsl:if>
        -->
        <!--
        <xsl:if test="fm:Annotation">
          <xsl:call-template name="Annotation"/>
        </xsl:if>
        -->
        <!-- 
        <xsl:if test="fm:Attribute">
            <xsl:call-template name="Attribute"/>
        </xsl:if>
        -->
        <!--<xsl:if test="fm:AppendFeaturePropertySet">
      <xsl:call-template name="AttributePropertySet"/>
    </xsl:if>
    <xsl:if test="fm:AppendGroupPropertySet">
      <xsl:call-template name="OperationPropertySet"/>
    </xsl:if>-->
    </xsl:template>
    <!-- ========================================================================= -->
    <xsl:template name="OperationPropertySet">
        <!-- No additional information needed - everything is in family model -->
    </xsl:template>
    <!-- ========================================================================= -->
    <xsl:template name="AspectPropertySet">
        <!-- No additional information needed - everything is in family model (maybe it can be provided/generable/missing but this is not in ICSR.xfmm) -->
    </xsl:template>
    <!-- ========================================================================= -->
    <xsl:template name="AbstractInterfacePropertySet">
        <!-- No additional information needed - everything is in family model -->
    </xsl:template>
    <!-- ========================================================================= -->
    <xsl:template name="ComponentPropertySet">
        <!-- <inst:InstantiatioInstructions type="foo" status="bar"/> -->
        <xsl:if test="fm:ComponentPropertySet/fm:StatusProperty/@fm:value='generable'">
            <xs:element ref="fmm:ComponentInstantiationPropertySet"/>
        </xsl:if>
    </xsl:template>
    <!-- ========================================================================= -->
    <xsl:template name="AttributePropertySet">
        <xsl:if test="fm:AttributePropertySet/fm:NameProperty/@fm:value">
            <xs:element ref="fmm:{fm:AttributePropertySet/fm:NameProperty/@fm:value}PropertySet"/>
        </xsl:if>
    </xsl:template>
    <!-- ========================================================================= -->
    <xsl:template name="CompositePropertySet">
        <!-- No additional information needed - everything is in family model -->
    </xsl:template>
    <!-- ========================================================================= -->
    <!-- Description template extracts information from feature types and write them into 'annotation' element. -->
    <xsl:template name="Documentation">
        
        <xs:annotation>
            <xs:documentation>
                <xsl:value-of select="fm:Annotation/fm:ShortDescription/@fm:value"/>
                <xsl:if test="fm:Annotation/fm:LongDescription">
                    <xsl:text> </xsl:text>
                    <xsl:value-of select="fm:Annotation/fm:LongDescription/@fm:value"/>
                </xsl:if> 
                <xsl:if test="fm:Annotation/fm:LongDescription | fm:Annotation/fm:ShortDescription">
                    <xsl:text> </xsl:text>
                </xsl:if>  
                <xsl:if test="fm:CompositePropertySet">The feature is of type composite.</xsl:if>
                <xsl:if test="fm:ComponentPropertySet">The feature is of type component. It is represented
                    by '<xsl:value-of select="fm:ComponentPropertySet/fm:StatusProperty/@fm:value"/>'
                    component '<xsl:value-of select="fm:ComponentPropertySet/fm:TypeProperty/@fm:value"/>'.</xsl:if>
                <xsl:if test="fm:AbstractInterfacePropertySet">The feature is of type abstract interface.</xsl:if>
                <xsl:if test="fm:AspectPropertySet">The feature is of type aspect.</xsl:if>
                <xsl:if test="fm:AttributePropertySet">The feature is of type attribute.</xsl:if>
                <xsl:if test="fm:OperationPropertySet">The feature is of type operation.</xsl:if>
                
            </xs:documentation>
        </xs:annotation>
    </xsl:template>
    
    <!-- ========================================================================= -->
    <!-- The template creates a global element called 'Description' where the developer of an application can write any commnets.  -->
    <xsl:template name="CreateDescriptionElement">
        <xs:element name="Description">
            <xs:complexType mixed="true">
                <xs:sequence>
                    <xs:any minOccurs="0" processContents="lax"/>
                </xs:sequence>
            </xs:complexType>
        </xs:element>
    </xsl:template>
    
    <!-- ========================================================================= -->
    <!-- Description template extracts information from feature types and write them into 'annotation' element. -->
    <!-- fm:Annotation -->
    <xsl:template match="//*[substring-before(name(),'__')='fm:Annotation']">
        <xsl:variable name="number" select="substring-after(name(),'__')"/>
        <xsl:variable name="newAnnotationName" select="local-name()"/>
        <xsl:variable name="newShortDescriptionName" select="concat('ShortDescription__',$number)"/>
        <xsl:variable name="newLongDescriptionName" select="concat('LongDescription__',$number)"/>
        <xsl:variable name="newCommentName" select="concat('Comment__',$number)"/>
        <xsl:variable name="newHyperlinkName" select="concat('Hyperlink__',$number)"/>
        
        <xs:element name="{$newAnnotationName}">
            <xs:complexType dm:displayType="propertySet">
                <xs:sequence>
                    <xs:element ref="fmm:{$newShortDescriptionName}" minOccurs="1"/> <!-- always --> <!-- ESTEC -->
                    <xsl:choose>
                        <xsl:when test="fm:LongDescription/@fm:value">
                            <xs:element ref="fmm:{$newLongDescriptionName}" minOccurs="1"/> <!-- ESTEC -->                            
                        </xsl:when>
                        <xsl:otherwise>
                            <xs:element ref="fmm:LongDescription" minOccurs="0"/>                            
                        </xsl:otherwise>
                    </xsl:choose>
                    <xsl:choose>
                        <xsl:when test="fm:Comment/@fm:value">
                            <xs:element ref="fmm:{$newCommentName}" minOccurs="0"/> <!-- ESTEC -->
                        </xsl:when>
                        <xsl:otherwise>
                            <xs:element ref="fmm:Comment" minOccurs="0"/>
                        </xsl:otherwise>
                    </xsl:choose>
                    <xsl:choose>
                        <xsl:when test="fm:Hyperlink/@fm:value">
                            <xs:element ref="fmm:{$newHyperlinkName}" minOccurs="0"/> <!-- ESTEC -->
                        </xsl:when>
                        <xsl:otherwise>
                            <xs:element ref="fmm:Hyperlink" minOccurs="0"/>
                        </xsl:otherwise>
                    </xsl:choose>
                </xs:sequence>
                <xs:attribute name="value" type="xs:string" default="Annotation" use="optional"/>
            </xs:complexType>
        </xs:element>
                    
        <xs:element name="{$newShortDescriptionName}">
            <xs:complexType dm:displayType="property">
                <xsl:choose>
                    <xsl:when test="fm:ShortDescription/@fm:value=''">
                        <xs:attribute name="value" type="xs:string" default="No ShortDescription defined in the family model" use="optional"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xs:attribute name="value" type="xs:string" default="{fm:ShortDescription/@fm:value}" use="optional"/>
                    </xsl:otherwise>
                </xsl:choose>          
            </xs:complexType>
        </xs:element>
        <xsl:if test="fm:LongDescription">
            <xs:element name="{$newLongDescriptionName}" >
                <xs:complexType dm:displayType="property">
                    <xs:attribute name="value" type="xs:string" default="{fm:LongDescription/@fm:value}" use="optional"/>
                </xs:complexType>
            </xs:element>
        </xsl:if>
        <xsl:if test="fm:Comment">
            <xs:element name="{$newCommentName}" >
                <xs:complexType dm:displayType="property">
                    <xs:attribute name="value" type="xs:string" default="{fm:Comment/@fm:value}" use="optional"/>
                </xs:complexType>
            </xs:element>
        </xsl:if>
        <xsl:if test="fm:Hyperlink">
            <xs:element name="{$newHyperlinkName}" >
                <xs:complexType dm:displayType="property">
                    <xs:attribute name="value" type="xs:string" default="{fm:Hyperlink/@fm:value}" use="optional"/>
                </xs:complexType>
            </xs:element>
        </xsl:if>
 
    </xsl:template>

    <!-- fm:Attribute --> 
    <!-- DELETED - ATTRIBUTES HANDLING MOVED TO ProcessFeature -->  
    
    <!-- fm:DesignMapping -->    
    <xsl:template match="//*[substring-before(name(),'__')='fm:DesignMapping']">
        <xsl:variable name="number" select="substring-after(name(),'__')"/>
        <xsl:variable name="newDesignMappingName" select="concat('DesignMapping__',$number)"/>
        <xsl:variable name="newInterfaceNameName" select="concat('InterfaceName__',$number)"/>
        <xsl:variable name="newClassNameName" select="concat('ClassName__',$number)"/>
        <xsl:variable name="newPropertyNameName" select="concat('PropertyName__',$number)"/>
        <xsl:variable name="newOperationNameName" select="concat('OperationName__',$number)"/>
        <xsl:variable name="newOperationTypeName" select="concat('OperationType__',$number)"/>
        
        <xs:element name="{$newDesignMappingName}">
            <xs:complexType dm:displayType="propertySet">
                <xs:sequence>
                    <xsl:if test="fm:InterfaceName/@fm:value">
                        <xs:element ref="fmm:{$newInterfaceNameName}" minOccurs="1"/>
                    </xsl:if>
                    <xsl:if test="fm:ClassName/@fm:value">
                        <xs:element ref="fmm:{$newClassNameName}" minOccurs="1"/>
                    </xsl:if>
                    <xsl:if test="fm:PropertyName/@fm:value">
                        <xs:element ref="fmm:{$newPropertyNameName}" minOccurs="1"/>
                    </xsl:if>
                    <xsl:if test="fm:OperationName/@fm:value">
                        <xs:element ref="fmm:{$newOperationNameName}" minOccurs="1"/>
                    </xsl:if>
                    <xsl:if test="fm:OperationType/@fm:value">
                        <xs:element ref="fmm:{$newOperationTypeName}" minOccurs="1"/>
                    </xsl:if>
                </xs:sequence>
                <xs:attribute name="value" type="xs:string" default="DesignMapping" use="optional"/>
            </xs:complexType>
        </xs:element>
        
        <xsl:if test="fm:InterfaceName">
            <xs:element name="{$newInterfaceNameName}" >
                <xs:complexType dm:displayType="property">
                    <xs:attribute name="value" type="xs:string" fixed="{fm:InterfaceName/@fm:value}" use="required"/>
                </xs:complexType>
            </xs:element>
        </xsl:if>
        <xsl:if test="fm:ClassName">
            <xs:element name="{$newClassNameName}" >
                <xs:complexType dm:displayType="property">
                    <xs:attribute name="value" type="xs:string" fixed="{fm:ClassName/@fm:value}" use="required"/>
                </xs:complexType>
            </xs:element>
        </xsl:if>
        <xsl:if test="fm:PropertyName">
            <xs:element name="{$newPropertyNameName}" >
                <xs:complexType dm:displayType="property">
                    <xs:attribute name="value" type="xs:string" fixed="{fm:PropertyName/@fm:value}" use="required"/>
                </xs:complexType>
            </xs:element>
        </xsl:if>
        <xsl:if test="fm:OperationName">
            <xs:element name="{$newOperationNameName}" >
                <xs:complexType dm:displayType="property">
                    <xs:attribute name="value" type="xs:string" fixed="{fm:OperationName/@fm:value}" use="required"/>
                </xs:complexType>
            </xs:element>
        </xsl:if>
        <xsl:if test="fm:OperationType">
            <xs:element name="{$newOperationTypeName}" >
                <xs:complexType dm:displayType="property">
                    <xs:attribute name="value" type="xs:string" fixed="{fm:OperationType/@fm:value}" use="required"/>
                </xs:complexType>
            </xs:element>
        </xsl:if>
    </xsl:template>  

    
    
</xsl:stylesheet>
