<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
	xmlns:msxsl="urn:schemas-microsoft-com:xslt"
	xmlns:exsl="urn:schemas-microsoft-com:xslt"
	xmlns:picnet="http://www.picnet.com.au">

	<xsl:import href="common.xsl"/>	
	
	<xsl:template match="/">
		<xsl:apply-templates select="dal/entity"/>
	</xsl:template>
	
	<xsl:template match="entity">				
		<xsl:variable name="filecontents">					
			<xsl:apply-templates select="." mode="impl"/>
		</xsl:variable>

		<xsl:variable name="filename" select="concat(/dal/outdir, '/', @name, '.hbm.xml')"/>				 
		<xsl:for-each select="exsl:node-set($filecontents)/*">
			<xsl:variable name="tmp" select="picnet:WriteXML($filename, .)"/>
		</xsl:for-each>				
		<xsl:variable name="tmp" select="picnet:CleanXML($filename)"/>
	</xsl:template>

	<xsl:template match="entity" mode="impl">
		<xsl:variable name="mutable">
			<xsl:choose><xsl:when test="@read-only='true'">false</xsl:when><xsl:otherwise>true</xsl:otherwise></xsl:choose>
		</xsl:variable>
		<xsl:variable name="cache-usage">
			<xsl:choose><xsl:when test="@read-only='true'">read-only</xsl:when><xsl:otherwise>read-write</xsl:otherwise></xsl:choose>
		</xsl:variable>
		<xsl:variable name="table">
			<xsl:choose><xsl:when test="@table"><xsl:value-of select="@table"/></xsl:when><xsl:otherwise><xsl:value-of select="@name"/></xsl:otherwise></xsl:choose>
		</xsl:variable>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
	<class name="{/dal/namespace}.{@name}, {/dal/assembly}" table="`{$table}`" lazy="true" mutable="{$mutable}">		
		<cache usage="{$cache-usage}"/>
		<xsl:apply-templates select="field[@pk='true']" mode="pk"/>		
		<xsl:apply-templates select="field[not(@pk) and (not(@type) and not(@objecttype)) or (@type = picnet:GetObjectType(@type, @objecttype)) and not(ignore-sql)]"/>
		<xsl:apply-templates select="field[not(@pk) and not(@type) and @objecttype and not(ignore-sql) and not(@one-to-one)]" mode="many-to-one"/>
		<xsl:apply-templates select="field[not(@pk) and not(@type) and @objecttype and not(ignore-sql) and @one-to-one = 'true']" mode="one-to-one"/>
	
		<xsl:variable name="currententity" select="."/>
		<xsl:apply-templates select="../entity/field[picnet:GetObjectType(@type, @objecttype)=$currententity/@name and not(@one-to-one)]" mode="entities-properties-bags">		
			<xsl:with-param name="entity" select="$currententity"/>
		</xsl:apply-templates>
	
		<xsl:if test="sql-delete"><sql-delete><xsl:value-of select="sql-delete"/></sql-delete></xsl:if>
		<xsl:if test="sql-update"><sql-update><xsl:value-of select="sql-update"/></sql-update></xsl:if>
		<xsl:if test="sql-insert"><sql-insert><xsl:value-of select="sql-insert"/></sql-insert></xsl:if>
	</class>
</hibernate-mapping>
	</xsl:template>
			
	<xsl:template match="field" mode="pk">
		<id name="ID" column="{@name}" unsaved-value="0">
			<generator class="native"/>
		</id>
	</xsl:template>
	
	<xsl:template match="field">
		<xsl:variable name="column">
			<xsl:choose><xsl:when test="@column"><xsl:value-of select="@column"/></xsl:when><xsl:otherwise><xsl:value-of select="@name"/></xsl:otherwise></xsl:choose>
		</xsl:variable>
		<xsl:variable name="hib-type">
			<xsl:call-template name="get-hibernate-type">
				<xsl:with-param name="field" select="."/>
			</xsl:call-template>
		</xsl:variable>
		<xsl:variable name="hib-length">
			<xsl:call-template name="get-hibernate-type-length">
				<xsl:with-param name="field" select="."/>
			</xsl:call-template>
		</xsl:variable>
		<xsl:element name="property">
			<xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
			<xsl:attribute name="column"><xsl:value-of select="$column"/></xsl:attribute>
			<xsl:attribute name="type"><xsl:value-of select="$hib-type"/></xsl:attribute>
			<xsl:if test="not(@null)">
				<xsl:attribute name="not-null">true</xsl:attribute>
			</xsl:if>
			<xsl:if test="$hib-type = 'String'">
				<xsl:attribute name="length"><xsl:value-of select="$hib-length"/></xsl:attribute>
			</xsl:if>
			<xsl:if test="$hib-type = 'YesNo'">
				<xsl:attribute name="length">1</xsl:attribute>
			</xsl:if>
			<xsl:if test="@type = 'byte[]'">
				<xsl:attribute name="length"><xsl:value-of select="maxlength"/></xsl:attribute>
			</xsl:if>
		</xsl:element>		
	</xsl:template>		
	
	<xsl:template match="field" mode="entities-properties-bags">
		<xsl:param name="entity"/>
		
		<xsl:variable name="method-name"><xsl:apply-templates select="." mode="entities-list-name"/>Entities</xsl:variable>
		<xsl:variable name="column">
			<xsl:choose><xsl:when test="@column"><xsl:value-of select="@column"/></xsl:when><xsl:otherwise><xsl:value-of select="@name"/></xsl:otherwise></xsl:choose>
		</xsl:variable>
		
		<xsl:variable name="thisentityname" select="../@name"/>
				
		<xsl:variable name="on-delete-cascade">
			<xsl:choose>
				<xsl:when test="@on-delete-cascade='true' or (count(//field[picnet:GetObjectType(@type, @objecttype)=$thisentityname]) = 0 and count($entity/field[picnet:GetTypeSafe(@type) != picnet:GetObjectType(@type, @objecttype)]) = 0)">true</xsl:when>				
				<xsl:otherwise>false</xsl:otherwise>
			</xsl:choose>
		</xsl:variable>
		
		<xsl:variable name="cascade-delete">
			<xsl:choose>
				<xsl:when test="$on-delete-cascade='true' or $entity/cascade-delete-children = 'false'">false</xsl:when>
				<xsl:otherwise>true</xsl:otherwise>
			</xsl:choose>
		</xsl:variable>
		
		<xsl:element name="set">
			<xsl:attribute name="name"><xsl:value-of select="$method-name"/></xsl:attribute>
			<xsl:attribute name="lazy">true</xsl:attribute>			
			<xsl:attribute name="cascade">
				<xsl:choose>
					<xsl:when test="$cascade-delete='true'">delete</xsl:when>
					<xsl:otherwise>none</xsl:otherwise>
				</xsl:choose>
			</xsl:attribute>			
			<xsl:attribute name="inverse">true</xsl:attribute>			
			
			<xsl:element name="key">
				<xsl:attribute name="column"><xsl:value-of select="$column"/></xsl:attribute>
				<xsl:if test="$on-delete-cascade='true'">
					<xsl:attribute name="on-delete">cascade</xsl:attribute>				
				</xsl:if>
			</xsl:element>
			<xsl:element name="one-to-many"><xsl:attribute name="class"><xsl:value-of select="concat(/dal/namespace, '.', ../@name, ', ', /dal/assembly)"/></xsl:attribute></xsl:element>
		</xsl:element>
	</xsl:template>
	
	<xsl:template match="field" mode="many-to-one">
		
		<xsl:variable name="column">
			<xsl:choose><xsl:when test="@column"><xsl:value-of select="@column"/></xsl:when><xsl:otherwise><xsl:value-of select="@name"/></xsl:otherwise></xsl:choose>
		</xsl:variable>
		<xsl:element name="many-to-one">
			<xsl:attribute name="name"><xsl:value-of select="picnet:FieldName(@fieldname, @name, false())"/>_Internal</xsl:attribute>
			<xsl:attribute name="column"><xsl:value-of select="$column"/></xsl:attribute>
			<xsl:attribute name="lazy">false</xsl:attribute> <!-- Parents are never lazy -->
			<xsl:if test="not(@null)"><xsl:attribute name="not-null">true</xsl:attribute></xsl:if>
		</xsl:element>
	</xsl:template>
	
	<xsl:template match="field" mode="one-to-one">
		<xsl:element name="one-to-one">
			<xsl:attribute name="cascade">delete</xsl:attribute>
			<xsl:attribute name="name"><xsl:value-of select="picnet:FieldName(@fieldname, @name, false())"/></xsl:attribute>
			<xsl:attribute name="class"><xsl:value-of select="concat(/dal/namespace, '.', picnet:GetObjectType(@type, @objecttype), ', ', /dal/assembly)"/></xsl:attribute>			
		</xsl:element>
	</xsl:template>
	
<!-- FUNCTIONS -->
	<xsl:template name="get-hibernate-type-length">	
		<xsl:param name="field"/>
		
		<xsl:choose>
			<xsl:when test="$field/encrypted = 'true'">
				<xsl:choose>
					<xsl:when test="$field/@type = 'bool'">24</xsl:when>
					<xsl:when test="not($field/@type) or $field/@type = 'int'">128</xsl:when>
					<xsl:when test="$field/@type = 'short'">64</xsl:when>
					<xsl:when test="$field/@type = 'long'">256</xsl:when>
					<xsl:when test="$field/@type = 'decimal'">256</xsl:when>
					<xsl:when test="$field/@type = 'double'">256</xsl:when>
					<xsl:when test="$field/@type = 'string'"><xsl:value-of select="$field/@length * 3"/></xsl:when>
					<xsl:otherwise>
						<xsl:message terminate="yes">Table:<xsl:value-of select="$field/../@name"/> Column:<xsl:value-of select="$field/@name"/> - Encrypted columns cannot be of type [<xsl:value-of select="$field/@type"/>].</xsl:message>
					</xsl:otherwise>
				</xsl:choose>
			</xsl:when>
			<xsl:when test="$field/@type = 'string'"><xsl:value-of select="$field/@length"/></xsl:when>
			<xsl:when test="$field/@type = 'bool'">1</xsl:when>
		</xsl:choose>
	</xsl:template>
	
	<xsl:template name="get-hibernate-type">	
		<xsl:param name="field"/>
		
		<xsl:choose>
			<xsl:when test="$field/encrypted = 'true'">String</xsl:when>			
			<xsl:when test="$field/@type = 'string'">String</xsl:when>
			<xsl:when test="$field/@type = 'long'">Int64</xsl:when>
			<xsl:when test="$field/@type = 'short'">Int16</xsl:when>
			<xsl:when test="not($field/@type) or $field/@type = 'int'">Int32</xsl:when>
			<xsl:when test="$field/@type = 'bool'">YesNo</xsl:when>
			<xsl:when test="$field/@type = 'decimal'">Decimal</xsl:when>
			<xsl:when test="$field/@type = 'double'">Double</xsl:when>
			<xsl:when test="$field/@type = 'DateTime'">DateTime</xsl:when>
			<xsl:when test="$field/@type = 'byte[]' or $field/@type = 'object'">Byte[](<xsl:value-of select="$field/maxlength"/>)</xsl:when>
			<xsl:otherwise>
				<xsl:message terminate="yes">Type '<xsl:value-of select="$field/@type"/>' is unknown.</xsl:message>			
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>

	<xsl:template name="get-hibernate-type-object">	
		<xsl:param name="field"/>
		
	</xsl:template>
</xsl:stylesheet>