<?xml version="1.0" encoding="ISO-8859-1" ?>
<!-- ex: set tabstop=2 shiftwidth=2 expandtab: -->

<!-- ===========================================================================
(@) PROJECT  : Atelier
(@) VERSION  : 0.2
(@) FILE     : xml2dia.xsl
(@) AUTHORS  : Stephane Barrault (SBA) - barrault@free.fr
(@) COMMENT  : Transformation d'une description de base de donnees en schema
(@) COMMENT  : relationnel
(@) CREATION : 2002/11/18
(@) UPDATE   : 
(@) HISTORY  : 2002/11/19 : v0.1
(@) HISTORY  : 2002/12/05 : v0.2
(@) CVS      : $Id: xml2dia.xsl,v 1.2 2002/12/05 20:45:25 chips Exp $
============================================================================ -->

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:dia="http://www.lysator.liu.se/~alla/dia/">

  <xsl:output method="xml" indent="yes" encoding="UTF-8"/>

  <!-- Nombre d'objets par ligne -->
  <xsl:variable name="mod" select="4" />
  <!-- Intervalle horizontal entre les debuts de boites -->
  <xsl:variable name="xinter" select="25" />
  <!-- Intervalle vertical entre les debuts de boites -->
  <xsl:variable name="yinter" select="20" />

<!-- ======================================================================= -->
  <!-- Creation de la structure XML du document DIA -->
  <xsl:template match="/">
    <dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
      <dia:diagramdata>
        <dia:attribute name="background">
          <dia:color val="#ffffff"/>
        </dia:attribute>
        <dia:attribute name="paper">
          <dia:composite type="paper">
            <dia:attribute name="name">
              <dia:string>#A4#</dia:string>
            </dia:attribute>
            <dia:attribute name="tmargin">
              <dia:real val="0.5"/>
            </dia:attribute>
             <dia:attribute name="bmargin">
              <dia:real val="0.5"/>
            </dia:attribute>
            <dia:attribute name="lmargin">
              <dia:real val="1.0"/>
            </dia:attribute>
            <dia:attribute name="rmargin">
              <dia:real val="0.5"/>
            </dia:attribute>
            <dia:attribute name="is_portrait">
              <dia:boolean val="true"/>
            </dia:attribute>
            <dia:attribute name="scaling">
              <dia:real val="1"/>
            </dia:attribute>
            <dia:attribute name="fitto">
              <dia:boolean val="false"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="grid">
          <dia:composite type="grid">
            <dia:attribute name="width_x">
              <dia:real val="1"/>
            </dia:attribute>
            <dia:attribute name="width_y">
              <dia:real val="1"/>
            </dia:attribute>
            <dia:attribute name="visible_x">
              <dia:int val="1"/>
            </dia:attribute>
            <dia:attribute name="visible_y">
              <dia:int val="1"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="guides">
          <dia:composite type="guides">
            <dia:attribute name="hguides"/>
            <dia:attribute name="vguides"/>
          </dia:composite>
        </dia:attribute>
      </dia:diagramdata>
      <!-- Creer les ensembles d'objets -->
      <dia:layer name="tag" visible="true">
      <xsl:for-each select="/project/object">
        <xsl:sort select="@tag" />
        <xsl:call-template name="make-tag" />
      </xsl:for-each>
      </dia:layer>
      <dia:layer name="object-attribute" visible="true">
      <!-- Creer les objets -->
      <xsl:for-each select="/project/object">
        <xsl:sort select="concat(@tag,@name)" />
          <xsl:call-template name="make-object" />
      </xsl:for-each>
      <!-- Creer les associations -->
        <xsl:call-template name="make-attribute" />
      </dia:layer>
    </dia:diagram>
  </xsl:template>

<!-- ======================================================================= -->
  <!-- Creation des objets -->
  <xsl:template name="make-object">
    <xsl:variable name="postag">
      <xsl:call-template name="get-y-tag">
        <xsl:with-param name="tag">
          <xsl:value-of select="@tag"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:variable>
    <!-- Indice de l'objet -->
    <xsl:variable name="ia">
      <xsl:call-template name="get-position-object-in-tag">
        <xsl:with-param name="name">
          <xsl:value-of select="@name"/>
        </xsl:with-param>
        <xsl:with-param name="tag">
          <xsl:value-of select="@tag"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="i" select="number($ia) - 1" />
    <!-- Reste calcule -->
    <xsl:variable name="res" select="number($i) mod number($mod)" />
    <!-- Coordonnees de l'objet dans le diagramme -->
    <xsl:variable name="x" select="number($res) * number($xinter)" />
    <xsl:variable name="y" 
      select="floor(number($i) div $mod) * $yinter + number($postag)" />

    <dia:object type="UML - Class" version="0" id="{@name}">
      <dia:attribute name="obj_pos">
        <dia:point val="{$x},{$y}"/>
      </dia:attribute>
      <dia:attribute name="obj_bb">
        <dia:rectangle val="5,5;5,5"/>
      </dia:attribute>
      <dia:attribute name="elem_corner">
        <dia:point val="{$x},{$y}"/>
      </dia:attribute>
      <dia:attribute name="elem_width">
        <dia:real val="10"/>
      </dia:attribute>
      <dia:attribute name="elem_height">
        <dia:real val="2"/>
      </dia:attribute>
      <dia:attribute name="name">
        <dia:string>#<xsl:value-of select="@name" />#</dia:string>
      </dia:attribute>
      <dia:attribute name="stereotype">
        <dia:string/>
      </dia:attribute>
      <dia:attribute name="abstract">
        <dia:boolean val="false"/>
      </dia:attribute>
      <dia:attribute name="suppress_attributes">
        <dia:boolean val="false"/>
      </dia:attribute>
      <dia:attribute name="suppress_operations">
        <dia:boolean val="false"/>
      </dia:attribute>
      <dia:attribute name="visible_attributes">
        <dia:boolean val="true"/>
      </dia:attribute>
      <dia:attribute name="visible_operations">
        <dia:boolean val="false"/>
      </dia:attribute>
      <dia:attribute name="foreground_color">
        <dia:color val="#000000"/>
      </dia:attribute>
      <dia:attribute name="background_color">
        <dia:color val="#ffffff"/>
      </dia:attribute>
      <dia:attribute name="normal_font">
        <dia:font name="Helvetica"/>
      </dia:attribute>
      <dia:attribute name="abstract_font">
        <dia:font name="Courier-Oblique"/>
      </dia:attribute>
      <dia:attribute name="classname_font">
        <dia:font name="Helvetica-Bold"/>
      </dia:attribute>
      <dia:attribute name="abstract_classname_font">
        <dia:font name="Helvetica-BoldOblique"/>
      </dia:attribute>
      <dia:attribute name="font_height">
        <dia:real val="0.8"/>
      </dia:attribute>
      <dia:attribute name="abstract_font_height">
        <dia:real val="0.8"/>
      </dia:attribute>
      <dia:attribute name="classname_font_height">
        <dia:real val="1"/>
      </dia:attribute>
      <dia:attribute name="abstract_classname_font_height">
        <dia:real val="1"/>
      </dia:attribute>
      <!-- Placer les attributs -->
      <dia:attribute name="attributes">
        <xsl:apply-templates />
      </dia:attribute>
      <dia:attribute name="operations"/>
      <dia:attribute name="template">
        <dia:boolean val="false"/>
      </dia:attribute>
      <dia:attribute name="templates"/>
    </dia:object>
    
  </xsl:template>

<!-- ======================================================================= -->
  <!-- Creation des attributs des objets -->
  <xsl:template match="//attribute">
    <dia:composite type="umlattribute">
      <dia:attribute name="name">
        <dia:string>#<xsl:value-of select="@name" />#</dia:string>
      </dia:attribute>
      <dia:attribute name="type">
        <dia:string>#<xsl:value-of select="@type" />#</dia:string>
      </dia:attribute>
      <dia:attribute name="value">
        <dia:string/>
      </dia:attribute>
      <dia:attribute name="visibility">
        <dia:enum val="3"/>
      </dia:attribute>
      <dia:attribute name="abstract">
        <dia:boolean val="false"/>
      </dia:attribute>
      <dia:attribute name="class_scope">
        <xsl:choose>
          <xsl:when test="@primarykey = 'true'">
            <dia:boolean val="true"/>
          </xsl:when>
          <xsl:otherwise>
            <dia:boolean val="false"/>
          </xsl:otherwise>
        </xsl:choose>
      </dia:attribute>
    </dia:composite>
  </xsl:template>

<!-- ======================================================================= -->
  <!-- Creation des associations sous forme de lignes reliant les objets -->
  <xsl:template name="make-attribute">
    <xsl:for-each select="//attribute">
      <xsl:if test="@card = '1'">

        <xsl:variable name="postag">
          <xsl:call-template name="get-y-tag">
            <xsl:with-param name="tag">
              <xsl:value-of select="../@tag"/>
            </xsl:with-param>
          </xsl:call-template>
        </xsl:variable>
        <!-- Indice de l'objet -->
        <xsl:variable name="ia">
          <xsl:call-template name="get-position-object-in-tag">
            <xsl:with-param name="name">
              <xsl:value-of select="../@name"/>
            </xsl:with-param>
            <xsl:with-param name="tag">
              <xsl:value-of select="../@tag"/>
            </xsl:with-param>
          </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="i" select="number($ia) - 1" />
        <!-- Reste calcule -->
        <xsl:variable name="res" select="number($i) mod number($mod)" />
        <!-- Coordonnees de l'objet dans le diagramme -->
        <xsl:variable name="x" select="number($res) * number($xinter)" />
        <xsl:variable name="y" 
          select="floor(number($i) div $mod) * $yinter + number($postag)" />

        <xsl:variable name="t2" select="@type" />
        <xsl:variable name="postag2">
          <xsl:call-template name="get-y-tag">
            <xsl:with-param name="tag">
              <xsl:value-of select="//object[@name = $t2]/@tag"/>
            </xsl:with-param>
          </xsl:call-template>
        </xsl:variable>
        <!-- Indice de l'objet -->
        <xsl:variable name="i2a">
          <xsl:call-template name="get-position-object-in-tag">
            <xsl:with-param name="name">
              <xsl:value-of select="@type"/>
            </xsl:with-param>
            <xsl:with-param name="tag">
              <xsl:value-of select="//object[@name = $t2]/@tag"/>
            </xsl:with-param>
          </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="i2" select="number($i2a) - 1" />
        <!-- Reste calcule -->
        <xsl:variable name="res2" select="number($i2) mod number($mod)" />
        <!-- Coordonnees de l'objet dans le diagramme -->
        <xsl:variable name="x2" select="number($res2) * number($xinter)" />
        <xsl:variable name="y2" 
          select="floor(number($i2) div $mod) * $yinter +number($postag2)" />

        <xsl:variable name="xa" select="number($x) - 0.5" />
        <xsl:variable name="x2a" select="number($x2) - 0.5" />
        <xsl:variable name="ya" select="number($y) - 0.5" />
        <xsl:variable name="y2a" select="number($y2) - 0.5" />
    
        <dia:object type="Standard - PolyLine" version="0" id="{position()}">
          <dia:attribute name="obj_pos">
            <dia:point val="{$x},{$y}"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="{$x},{$y};{$x2},{$y2}"/>
          </dia:attribute>
          <dia:attribute name="poly_points">
            <dia:point val="{$x},{$y}"/>
            <dia:point val="{$xa},{$ya}"/>
            <dia:point val="{$x2a},{$y2a}"/>
            <dia:point val="{$x2},{$y2}"/>
          </dia:attribute>
          <dia:connections>
            <dia:connection handle="0" to="{../@name}" connection="0"/>
            <dia:connection handle="3" to="{@type}" connection="0"/>
          </dia:connections>
        </dia:object>
    
      </xsl:if>
    </xsl:for-each>
  </xsl:template>

<!-- ======================================================================= -->
  <!-- Creation des ensembles d'objets -->
  <xsl:template name="make-tag">
    <xsl:variable name="t" select="@tag" />
    <xsl:variable name="n" select="@name" />
    <xsl:variable name="nbobject" select="count(//object[@tag = $t])" />
    <xsl:variable name="vert"
      select="-floor(- number($nbobject) div number($mod)) * number($yinter)" />

    <xsl:variable name="i">
      <xsl:call-template name="get-position-object-in-tag">
        <xsl:with-param name="name">
          <xsl:value-of select="@name"/>
        </xsl:with-param>
        <xsl:with-param name="tag">
          <xsl:value-of select="@tag"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:variable>
          
    <xsl:variable name="j">
      <xsl:call-template name="get-position-object">
        <xsl:with-param name="name">
          <xsl:value-of select="concat(@tag,@name)"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:variable>
          
    <xsl:variable name="x" select="-2" />
    <xsl:variable name="y2">
      <xsl:call-template name="get-y-tag">
        <xsl:with-param name="tag">
          <xsl:value-of select="@tag"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="y" select="number($y2) -2" />

    <xsl:if test="number($i) = 1">
    <dia:object type="UML - LargePackage" version="0" id="{position()}">
      <dia:attribute name="obj_pos">
        <dia:point val="{$x},{$y}"/>
      </dia:attribute>
      <dia:attribute name="obj_bb">
        <dia:rectangle val="{$x},{$y};25,25"/>
      </dia:attribute>
      <dia:attribute name="elem_corner">
        <dia:point val="{$x},{$y}"/>
      </dia:attribute>
      <dia:attribute name="elem_width">
        <dia:real val="{$mod * $yinter + 2}"/>
      </dia:attribute>
      <dia:attribute name="elem_height">
        <dia:real val="{$vert}"/>
      </dia:attribute>
      <dia:attribute name="stereotype">
        <dia:string>##</dia:string>
      </dia:attribute>
      <dia:attribute name="name">
        <dia:string>#<xsl:value-of select="@tag"/>#</dia:string>
      </dia:attribute>
    </dia:object>
    </xsl:if>
  </xsl:template>

<!-- ======================================================================= -->
  <!-- Evite la recopie de la doc dans le fichier de sortie -->
  <xsl:template match="//doc">
  </xsl:template>
  
<!-- ======================================================================= -->
  <!-- Renvoie la position d'un objet classe par ordre alphabetique des tags
       et des noms -->
  <xsl:template name="get-position-object">
    <xsl:param name="name"></xsl:param>
    <xsl:for-each select="/project/object" >
      <xsl:sort select="concat(@tag,@name)" />
      <xsl:if test="concat(@tag,@name) = $name">
        <xsl:variable name="pos">
          <xsl:number value="position()" />
        </xsl:variable>
        <xsl:value-of select="number($pos) - 1" />
      </xsl:if>
    </xsl:for-each>
  </xsl:template>

<!-- ======================================================================= -->
  <!-- Renvoie le nom d'un tag en fonction de sa position ordonnee -->
  <xsl:template name="get-next-name-tag">
    <xsl:param name="pos">1</xsl:param>
    <xsl:for-each select="//object[not(@tag = preceding-sibling::object/@tag)]">
      <xsl:sort select="@tag"/>
      <xsl:if test="number($pos) = position()">
        <xsl:value-of select="@tag"/>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>

<!-- ======================================================================= -->
  <!-- Position d'un objet dans un ensemble d'objets -->
  <xsl:template name="get-position-object-in-tag">
    <xsl:param name="name"></xsl:param>
    <xsl:param name="tag"></xsl:param>
    <xsl:for-each select="/project/object[@tag = $tag]" >
      <xsl:sort select="@name" />
      <xsl:if test="@name = $name">
        <xsl:variable name="pos">
          <xsl:number value="position()" />
        </xsl:variable>
        <xsl:value-of select="number($pos)" />
      </xsl:if>
    </xsl:for-each>
  </xsl:template>
  
<!-- ======================================================================= -->
  <!-- Position (coordonnee y) d'un tag dans le diagramme -->
  <xsl:template name="get-y-tag">
    <xsl:param name="tag"></xsl:param>
    <xsl:param name="indice">1</xsl:param>
    <xsl:param name="y">0</xsl:param>
    <xsl:variable name="curtag">
      <xsl:call-template name="get-next-name-tag">
        <xsl:with-param name="pos">
          <xsl:value-of select="$indice"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="$tag = $curtag">
        <xsl:value-of select="$y"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:variable name="morey" 
          select="- floor(- count(/project/object[@tag = $curtag]) div 
                number($mod)) * number($yinter)" />
        <xsl:call-template name="get-y-tag">
          <xsl:with-param name="tag">
            <xsl:value-of select="$tag"/>
          </xsl:with-param>
          <xsl:with-param name="indice">
            <xsl:value-of select="number($indice) + 1"/>
            </xsl:with-param>
          <xsl:with-param name="y">
            <xsl:value-of select="number($y) + number($morey)"/>
          </xsl:with-param>
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

