<?xml version="1.0" encoding="UTF-8"?>
<!--
 Stylesheet to create a HTML version of a Statestep model in XML.
 Author: Michael Breen
 $Revision: 1.3 $
-->
<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:s2="http://statestep.com">
<xsl:output method="html" encoding="UTF-8"
 doctype-system="http://www.w3.org/TR/html4/strict.dtd"
 doctype-public="-//W3C//DTD HTML 4.01//EN"
/>


<!-- substantially reduces processing time for large models -->
<xsl:variable name="all_vars" select="//s2:variable"/>

<xsl:key name="vars_by_name" match="s2:variable" use="@name"/>


<xsl:template match="s2:model">
   <xsl:variable name="title">
      <xsl:value-of select="./s2:title"/>
      <xsl:if test="not(./s2:title//text())">
         <xsl:text>[Untitled]</xsl:text>
      </xsl:if>
   </xsl:variable>
   <HTML>
      <HEAD>
         <TITLE>
            <xsl:value-of select="$title"/>
         </TITLE>
         <STYLE type="text/css">
            BODY { font-family: sans-serif; }
            H1, H3, H4 { font-weight: normal }
            H1 { text-align: center; font-size: 300% }
            H2, H3 { font-size: 200%; margin-top: 1.5em }
            H3 { font-style: italic; border-top: thin solid }
            H4
            {
               margin-top: 1.5em;
               text-decoration: underline;
               font-size: 150%
            }
            TABLE
            {
               empty-cells: show;
               border-collapse: collapse;
               border-spacing: 0
            }
            TABLE, TH, TD
            {
               background: white;
               border: 1px solid black
            }
            TD { vertical-align: top }
            TH, TD.constraining { background: #DDD }
            DIV.contents
            {
               padding: 1em;
               border: 1px solid;
               margin: 1em 0;
               background: #DDD
            }
            UL.contents { list-style-type: none }
            DT { font-weight: bold; }
            .constraint-list DT, .rule-list DT, .variable-list DT
            {
               margin-top: 1.5em; font-size: 120%
            }
            DD { margin-left: 0; margin-bottom: 1em }
            .constraint-list DD, .rule-list DD { padding: 0.5em }
            .variable-list DT { margin-bottom: 0.5em; }
            .variable-list DD { margin-bottom: 0.5em; }
            .value-list DT
            {
               margin-top: 0.5em;
               margin-bottom: 0.5em;
               font-size: 100%
            }
            DL DL { margin-left: 3em; }
            DL DL DD { margin-left: 2em; }
            .value-list DD { margin-bottom: 0em }
            DD.constraint-global { background: #DD9 }
            DD.constraint-event { background: #CF9 }
            DD.rule { background: #DDC }
            PRE { margin: 0.5em 0 }
         </STYLE>
      </HEAD>
      <BODY>
         <H1>
            <xsl:value-of select="$title"/>
         </H1>
         <ADDRESS>
            Model exported from
            <A href="http://statestep.com">Statestep</A>.
         </ADDRESS>
         <xsl:if test="./s2:description//text()">
            <P>
               <xsl:value-of select="./s2:description"/>
            </P>
         </xsl:if>
         <DIV class="contents">
            <P><STRONG>Contents</STRONG></P>
            <UL class="contents">
               <LI><A href="#vars">Variables</A></LI>
               <LI><A href="#globals">Global Constraints</A>
                  <UL class="contents">
                     <LI><A href="#ctable">Constraint Table</A></LI>
                     <LI>
                        <A href="#textglobals">
                           Other Global Constraints
                        </A>
                     </LI>
                  </UL>
               </LI>
               <LI>
                  <A href="#events">Events: Constraints and Rules</A>
                  <UL class="contents">
                     <xsl:for-each select=".//s2:event">
                        <LI>
                           <A href="#event-{@name}">
                              <xsl:value-of select="./@name"/>
                           </A>
                        </LI>
                     </xsl:for-each>
                  </UL>
               </LI>
            </UL>
         </DIV>
         <H2><A name="vars">Variables</A></H2>
         <DL class="variable-list">
            <xsl:apply-templates select="$all_vars"/>
         </DL>
         <H2><A name="globals">Global Constraints</A></H2>
         <H3><A name="ctable">Constraint Table</A></H3>
         <xsl:apply-templates select=".//s2:simple_constraints"/>
         <H3><A name="textglobals">Other Global Constraints</A></H3>
         <xsl:apply-templates select="./s2:constraints"/>
         <H2><A name="events">Events: Constraints and Rules</A></H2>
         <xsl:apply-templates select=".//s2:event"/>
     </BODY>
   </HTML>
</xsl:template>


<!-- variable definitions -->
<xsl:template match="s2:variable | s2:variable//s2:value">
   <xsl:param name="nodetype">variable</xsl:param>
   <DT class="{$nodetype}">
      <xsl:value-of select="@name"/>
   </DT>
   <xsl:if test="*">
      <DD>
         <xsl:value-of select="./s2:description"/>
         <xsl:if test="./s2:value">
            <DL class="value-list">
               <xsl:apply-templates select="./s2:value">
                  <xsl:with-param name="nodetype" select="'value'"/>
               </xsl:apply-templates>
            </DL>
         </xsl:if>
      </DD>
   </xsl:if>
</xsl:template>


<!-- variables used in the constraint table (in definition order) -->
<xsl:variable name="vars_used_in_ct"
 select="$all_vars/@name[key('refs_in_ct', .)[1]]"
/>
<xsl:key name="refs_in_ct"
 match="s2:constraint_group/s2:value_set/@variable" use="."
/>

<!--
 the constraint table rows in which the constraining values
 are values of the specified variable
-->
<xsl:key name="constraining_row"
 match="s2:constraint_group"
 use="./s2:value_set[@type = 'constraining']/@variable"
/>


<!-- constraint table -->
<xsl:template match="s2:simple_constraints">
   <TABLE>
      <THEAD><TR>
         <xsl:for-each select="$vars_used_in_ct">
            <TH><xsl:value-of select="."/></TH>
         </xsl:for-each>
      </TR></THEAD>
      <TBODY>
         <xsl:for-each select="$vars_used_in_ct">
            <xsl:apply-templates
             select="key('constraining_row', .)"
            />
         </xsl:for-each>
      </TBODY>
   </TABLE>
</xsl:template>


<xsl:template match="s2:constraint_group">
   <xsl:variable name="row" select="."/>
   <TR>
      <xsl:for-each select="$vars_used_in_ct">
         <xsl:variable name="var" select="."/>
         <xsl:variable name="cell"
          select="$row/s2:value_set[@variable = $var]"
         />
         <xsl:apply-templates select="$cell"/>
         <!-- output an empty table cell if no values specified -->
         <xsl:if test="not($cell)">
            <TD class="constrained"></TD>
         </xsl:if>
      </xsl:for-each>
   </TR>
</xsl:template>


<!-- constraints expressed as formulas -->
<xsl:template match="s2:constraints">
   <DL class="constraint-list">
      <xsl:apply-templates select="./s2:constraint"/>
   </DL>
</xsl:template>


<xsl:template match="s2:constraint">
   <DT class="constraint-name">
      <xsl:value-of select="./@name"/>
   </DT>
   <DD>
      <xsl:attribute name="class">
         <xsl:choose>
            <xsl:when test="ancestor::s2:event">
               <xsl:text>constraint-event</xsl:text>
            </xsl:when>
            <xsl:otherwise>
               <xsl:text>constraint-global</xsl:text>
            </xsl:otherwise>
         </xsl:choose>
      </xsl:attribute>
      <xsl:call-template name="formula_text"/>
   </DD>
</xsl:template>


<!-- events: rules and constraints -->
<xsl:template match="s2:event">
   <H3 class="event-name">
      <A name="event-{@name}"><xsl:value-of select="./@name"/></A>
   </H3>
   <xsl:if test="./s2:description">
      <P><xsl:value-of select="./s2:description"/></P>
   </xsl:if>
   <H4>Constraints</H4>
   <xsl:apply-templates select="./s2:constraints"/>
   <H4>Rules</H4>
   <xsl:apply-templates select="./s2:rules"/>
</xsl:template>


<xsl:template match="s2:rules">
   <DL class="rule-list">
      <xsl:apply-templates select="./s2:rule"/>
   </DL>
</xsl:template>


<xsl:template match="s2:rule">
   <DT class="rule-name">
      <xsl:value-of select="./ancestor::s2:event/@name"/>
      <xsl:text disable-output-escaping="yes"
       >&amp;nbsp;&amp;nbsp;&amp;nbsp;</xsl:text
      >
      <xsl:value-of select="./@name"/>
   </DT>
   <DD class="rule">
      <xsl:if test="./s2:values_array/s2:value_set">
         <TABLE>
            <THEAD><TR>
               <xsl:for-each select="$all_vars">
                  <TH><xsl:value-of select="./@name"/></TH>
               </xsl:for-each>
            </TR></THEAD>
            <TBODY>
               <xsl:call-template name="rule_row" >
                  <xsl:with-param name="type" select="'source'"/>
               </xsl:call-template>
               <xsl:if test=
                "./s2:values_array/s2:value_set[@type = 'target']"
               >
                  <xsl:call-template name="rule_row">
                     <xsl:with-param name="type" select="'target'"/>
                  </xsl:call-template>
               </xsl:if>
            </TBODY>
         </TABLE>
      </xsl:if>
      <xsl:if test="./s2:formula">
         <xsl:call-template name="formula_text"/>
      </xsl:if>
   </DD>
</xsl:template>


<xsl:template name="formula_text">
   <PRE><xsl:value-of select=".//s2:text"/></PRE>
</xsl:template>


<xsl:template name="rule_row">
   <xsl:param name="type" select="'source'"/>
   <TR class="{$type}-row">
      <!-- columns for all variables, whether present or not -->
      <xsl:variable name="context" select="./s2:values_array"/>
      <xsl:for-each select="$all_vars">
         <xsl:variable name="var" select="./@name"/>
         <xsl:variable name="cell" select=
          "$context/s2:value_set[@type = $type][@variable = $var]"
         />
         <xsl:apply-templates select="$cell"/>
         <!-- output empty table cell if no values specified -->
         <xsl:if test="not($cell)">
            <TD class="{$type}">
               <!-- space prevents collapse of empty rows -->
               <xsl:text disable-output-escaping="yes"
                >&amp;nbsp;</xsl:text
               >
            </TD>
         </xsl:if>
      </xsl:for-each>
   </TR>
</xsl:template>


<xsl:template match="s2:value_set">
   <xsl:variable name="type" select="./@type"/>
   <TD class="{$type}">
      <xsl:if test="./@content = 'dont_care'">*</xsl:if>
      <xsl:if test="./@content = 'no_change'">=</xsl:if>
      <xsl:if test="./@content = 'list'">
         <xsl:variable name="var" select="./@variable"/>
         <xsl:apply-templates select="./s2:value">
            <xsl:with-param name="parent_definition"
             select="key('vars_by_name', $var)"
            />
         </xsl:apply-templates>
      </xsl:if>
   </TD>
</xsl:template>


<xsl:template match="s2:value_set//s2:value">
   <!--
    Each value in a set of values for a variable should have a
    corresponding node in the definition of the variable.
    This argument points to that node's parent.
   -->
   <xsl:param name="parent_definition" select="/.."/>
   <xsl:variable name="val" select="./@name"/>
   <xsl:variable name="definition"
    select="$parent_definition/s2:value[@name = $val]"
   />
   <!-- if this is a leaf in the tree of values -->
   <xsl:if test="not(./s2:value)">
      <!-- if it's not the first value then output a separator -->
      <xsl:if
       test="ancestor-or-self::s2:value/preceding-sibling::s2:value"
      >
         <BR />
      </xsl:if>
      <!-- output the fully-qualified value name -->
      <xsl:for-each select="ancestor::s2:value">
         <xsl:value-of select="./@name"/>
         <xsl:text>-</xsl:text>
      </xsl:for-each>
      <xsl:value-of select="./@name"/>
      <!--
       if this leaf corresponds to a group of values (that is, if
       the corresponding node on the definition tree is a branch)
       then output an indication of this
      -->
      <xsl:if test="$definition/s2:value">-*</xsl:if>
   </xsl:if>
   <xsl:apply-templates select="./s2:value">
      <xsl:with-param name="parent_definition"
       select="$definition"
      />
   </xsl:apply-templates>
</xsl:template>


<!-- override default (echoing) template -->
<xsl:template match="text()|@*"/>


</xsl:stylesheet>
