<?xml version="1.0" encoding="UTF-8"?>
<!--
  Copyright 2022 UCAIug

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  https://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

  See the License for the specific language governing permissions and
  limitations under the License.
-->
<xsl:stylesheet version="1.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:xs="http://www.w3.org/2001/XMLSchema"
	xmlns:a="http://langdale.com.au/2005/Message#"
	xmlns:sawsdl="http://www.w3.org/ns/sawsdl"
	xmlns="http://langdale.com.au/2009/Indent">

	<xsl:output indent="yes" method="xml" encoding="utf-8" />
	<xsl:param name="version"/>
	<xsl:param name="baseURI"/>
	<xsl:param name="envelope">Profile</xsl:param>
	<xsl:param name="package">au.com.langdale.cimtool.generated</xsl:param>
	
	<xsl:param name="mridType">String</xsl:param>

	<xsl:template name="type">
		<xsl:param name="xstype" select="@xstype"/>
		<xsl:choose>
			<xsl:when test="$xstype = 'string'">String</xsl:when>
			<xsl:when test="$xstype = 'integer' or @xstype = 'int'">Integer</xsl:when>
			<xsl:when test="$xstype = 'float'">Double</xsl:when>
			<xsl:when test="$xstype = 'double'">Double</xsl:when>
			<xsl:when test="$xstype = 'boolean'">Boolean</xsl:when>
			<xsl:otherwise>String</xsl:otherwise>
		</xsl:choose>
	</xsl:template>

	<xsl:variable name="lc">abcdefghijklmnopqrstuvwxyz</xsl:variable>
	<xsl:variable name="uc">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>
	
	<xsl:template name="capitalise">
		<xsl:param name="name" select="@name"/>
		<xsl:param name="prefix"/>
		<xsl:value-of select="concat($prefix,translate(substring($name,1,1),$lc,$uc),substring($name,2))"/>
	</xsl:template>

	<xsl:template name="uncapitalise">
		<xsl:param name="name" select="@name"/>
		<xsl:value-of select="concat(translate(substring($name,1,1),$uc,$lc),substring($name,2))"/>
	</xsl:template>
	
	<xsl:template name="property">
		<xsl:param name="name"/>
		<xsl:param name="xstype"/>
		<xsl:param name="type">
			<xsl:call-template name="type">
				<xsl:with-param name="xstype" select="$xstype"/>
			</xsl:call-template>
		</xsl:param>
		<xsl:param name="annotate"/>
		<xsl:param name="prop">
			<xsl:value-of select="translate($name,'_','')"/>
		</xsl:param>
		<xsl:variable name="field">
			<xsl:call-template name="uncapitalise">
				<xsl:with-param name="name" select="$prop"/>
			</xsl:call-template>
		</xsl:variable>
		
		<item>
			public
			<xsl:value-of select="$type"/>
			<sp/>
			<xsl:call-template name="capitalise">
				<xsl:with-param name="prefix">get</xsl:with-param>
				<xsl:with-param name="name" select="$prop"/>
			</xsl:call-template>
			() 
			{ return <xsl:value-of select="$field"/>; }
		</item>
		<item>
			public void
			<xsl:call-template name="capitalise">
				<xsl:with-param name="prefix">set</xsl:with-param>
				<xsl:with-param name="name" select="$prop"/>
			</xsl:call-template>
			(
			<xsl:value-of select="$type"/>
			<sp/>
			<xsl:value-of select="$field"/>
			) {
			    this.<xsl:value-of select="$field"/> = 			
			    <xsl:value-of select="$field"/>;
			}    
		</item>
		<xsl:copy-of select="$annotate"/>
		<item>
			private
			<xsl:value-of select="$type"/>
			<sp/>
			<xsl:value-of select="$field"/>
			;
		</item>
		<sp/>
	</xsl:template>
 
	<xsl:template match="a:Catalog">
		<!--  the top level template  -->
		<document>
			<item>package <xsl:value-of select="$package"/>;</item>
			<item>import javax.persistence.*;</item>
			<list begin="/**" indent=" * " end=" */">
				<item>Annotated java for <xsl:value-of select="$envelope" /></item>
				<item>Generated by CIMTool https://cimtool.ucaiug.io/</item>
			</list>
			<item>public class <xsl:value-of select="$envelope" /></item>
			<list begin="{{" indent="    " end="}}">
		    	<xsl:apply-templates/>
		    	<xsl:call-template name="config"/>
		    </list>
		</document>
	</xsl:template>
	
	<xsl:template name="config">
		<sp/>
		<item>public static final Class[] allClasses = new Class[]</item>
		<list begin="{{" indent="    " delim="," end="}};">
			<xsl:apply-templates mode="config"/>
		</list>
	</xsl:template>
	
	<xsl:template match="a:ComplexType|a:Root|a:EnumeratedType" mode="config">
		<item><xsl:value-of select="@name"/>.class</item>
	</xsl:template>

	<xsl:template match="a:ComplexType|a:Root">
		<xsl:variable name="super" select="a:SuperType[1]"/>

		<!-- a table -->
		<xsl:call-template name="annotate" />
		<item>@Entity</item>
		<item>@Table(name="\"<xsl:value-of select="@name"/>\"")</item>
		<xsl:if test="not($super)">
			<item>@Inheritance(strategy=InheritanceType.JOINED)</item>
		</xsl:if>
		<xsl:if test="$super">
			<item>@PrimaryKeyJoinColumn(name="\"mRID\"")</item>
		</xsl:if>
		<item>public static class <xsl:value-of select="@name"/>
			<xsl:if test="$super">
				extends <xsl:value-of select="$super/@name"/>
			</xsl:if>
		</item>
		<list begin="{{" indent="    " end="}}"> 
			<xsl:if test="not($super)">
				<xsl:call-template name="property">
					<xsl:with-param name="name">mRID</xsl:with-param>
					<xsl:with-param name="type" select="$mridType"/>
					<xsl:with-param name="annotate">
						<item>@Id</item>
	  					<item>@Column(name="\"mRID\"")</item>
					</xsl:with-param>
				</xsl:call-template>
			</xsl:if>
		    <xsl:apply-templates/>
		</list>
	</xsl:template>
	
	<xsl:template match="a:EnumeratedType">
		<!-- a reference table for an enumeration -->
		<sp/>
		<xsl:call-template name="annotate" />
		<item>@Entity</item>
		<item>@Table(name="\"<xsl:value-of select="@name"/>\"")</item>
		<item>public static class <xsl:value-of select="@name"/></item>
		<list begin="{{" indent="    " end="}};">
			<xsl:call-template name="property">
				<xsl:with-param name="name">name</xsl:with-param>
				<xsl:with-param name="type">String</xsl:with-param>
				<xsl:with-param name="annotate">
					<item>@Id</item>
					<item>@Column(name="\"name\"")</item>
				</xsl:with-param>
			</xsl:call-template>
		</list>
	</xsl:template>

	<xsl:template match="a:Instance|a:Reference">
		<xsl:if test="@maxOccurs &lt;= 1 and @name != 'mRID'">
			<!-- a foreign key column -->
			<decorate>
				<xsl:call-template name="annotate" />
				<xsl:call-template name="property">
					<xsl:with-param name="name" select="@name"/>
					<xsl:with-param name="type" select="@type"/>
					<xsl:with-param name="annotate">
						<item>
							<list begin="@ManyToOne(" delim=", " end=")">
								<item>fetch=FetchType.LAZY</item>
								<xsl:if test="@minOccurs = 0">
									<item>optional=true</item>
								</xsl:if>
							</list>
						</item>
						<item>@JoinColumn(name="\"<xsl:value-of select="@name"/>\"")</item>
					</xsl:with-param>
				</xsl:call-template>
			</decorate>
		</xsl:if>
	</xsl:template>
	
	<xsl:template match="a:Enumerated">
		<!-- a foreign key column for a reference table -->
		<decorate>
			<xsl:call-template name="annotate" />
			<xsl:call-template name="property">
				<xsl:with-param name="name" select="@name"/>
				<xsl:with-param name="type">String</xsl:with-param>
				<xsl:with-param name="annotate">
					<item>
						<list begin="@Basic(" delim=", " end=")">
							<xsl:if test="@minOccurs = 0">
								<item>optional=true</item>
							</xsl:if>
						</list>
					</item>
					<item>@Column(name="\"<xsl:value-of select="@name"/>\"")</item>
				</xsl:with-param>
			</xsl:call-template>
		</decorate>
	</xsl:template>

	<xsl:template match="a:Simple|a:Domain">
		<!-- a simple column  -->
		<xsl:if test="@maxOccurs &lt;= 1 and @name != 'mRID'">
			<decorate>
				<xsl:call-template name="annotate" />
				<xsl:call-template name="property">
					<xsl:with-param name="name" select="@name"/>
					<xsl:with-param name="xstype" select="@xstype"/>
					<xsl:with-param name="annotate">
						<item>
							<list begin="@Basic(" delim=", " end=")">
								<xsl:if test="@minOccurs = 0">
									<item>optional=true</item>
								</xsl:if>
							</list>
						</item>
						<item>@Column(name="\"<xsl:value-of select="@name"/>\"")</item>
					</xsl:with-param>
				</xsl:call-template>
			</decorate>
		</xsl:if>
	</xsl:template>

	<xsl:template name="annotate">
		<!--  generate and annotation -->
		<list begin="/**" indent=" * " end=" */">
			<xsl:apply-templates mode="annotate"/>
		</list>
	</xsl:template>

	<xsl:template match="a:Comment|a:Note" mode="annotate">
		<!--  generate human readable annotation -->
		<wrap width="70">
			<xsl:value-of select="."/>
		</wrap>
	</xsl:template>

	<xsl:template match="text()">
		<!--  dont pass text through  -->
	</xsl:template>

	<xsl:template match="node()" mode="config">
		<!-- dont pass any defaults in config mode -->
	</xsl:template>

	<xsl:template match="node()" mode="annotate">
		<!-- dont pass any defaults in annotate mode -->
	</xsl:template>

</xsl:stylesheet>
