<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
                xmlns:s="http://www.ldodds.com/ns/spooky"
                exclude-result-prefixes="s">

   <!-- make things readable -->
   <xsl:output indent="yes" />

   <!-- indicates where spooky lives. Used for copying default build files, etc -->
   <xsl:param name="spooky-home"/>
   <xsl:param name="output">name-of-output-file</xsl:param>

   <!-- global variables -->
   <xsl:variable name="name" select="/s:project/s:meta/s:name"/>
   <xsl:variable name="home" select="/s:project/s:meta/s:home"/>
   <xsl:variable name="desc" select="/s:project/s:meta/s:description"/>

   <!-- Used for messages. Include a similarly named variable in importing stylesheets -->
   <xsl:variable name="this" select="'Spooky Default'"/>

   <!-- It all starts here...

        1. create Ant project, with useful defaults
        2. create global properties for name, description
        3. generate Ant targets to:
            - make directories
            - make default files
            - make a project build file
            - default makeProject target
   -->
   <xsl:template match="s:project">
      <xsl:message><xsl:value-of select="$this"/> generating Ant build file for <xsl:value-of select="$name"/></xsl:message>

      <xsl:message>Creating project...</xsl:message>
      <project name="{$name}" default="makeProject" basedir="{$home}">
         <description>Spooky project generator for: <xsl:value-of select="$desc"/></description>

         <property name="name" value="{$name}"/>
         <property name="desc" value="{$desc}"/>

         <xsl:message>Creating directory build target...</xsl:message>
         <xsl:call-template name="makeDirectories"/>
         <xsl:message>Creating file creation target...</xsl:message>
         <xsl:call-template name="makeFiles"/>
         <xsl:message>Creating build file generation target...</xsl:message>
         <xsl:call-template name="makeBuildFile"/>
         <xsl:variable name="getDependencies">
            <xsl:call-template name="makeDependencies"/>
         </xsl:variable>
         <target name="makeProject" depends="makeDirectories,makeFiles,makeBuildFile"/>
      </project>
      <xsl:message>Complete</xsl:message>
      <xsl:message>Execute the following to create the project in <xsl:value-of select="$home"/>:</xsl:message>
      <xsl:message>ant -buildfile <xsl:value-of select="$output"/></xsl:message>
   </xsl:template>

   <!-- The following four templates are suitable for 'over-riding' in implementation specific
           ways. Simply provide an alternate template in the importing stylesheet.

           However typically only makeBuildFile, to customise how the Ant project build file
           is created will be altered
    -->

   <xsl:template name="makeDirectories">
         <target name="makeDirectories">
            <xsl:apply-templates select="s:structure/s:dir" mode="dir"/>
         </target>
   </xsl:template>

   <xsl:template name="makeFiles">
         <target name="makeFiles">
            <xsl:apply-templates select="s:structure/s:dir|s:structure/s:file" mode="file"/>
         </target>
   </xsl:template>

  <xsl:template name="makeBuildFile">
   <target name="makeBuildFile"/>
  </xsl:template>

   <xsl:template name="makeDependencies">
        <xsl:value-of select="'makeDirectories,makeFiles,makeBuildFile'"/>
   </xsl:template>

   <!-- process directory elements to generate Ant mkdir elements -->
   <xsl:template match="s:dir" mode="dir">
      <xsl:variable name="path-name">
         <xsl:call-template name="buildFullPath">
            <xsl:with-param name="ancestors" select="ancestor-or-self::s:dir"/>
         </xsl:call-template>
      </xsl:variable>
      <mkdir dir="{$path-name}"/>
      <xsl:apply-templates select="s:dir" mode="dir"/>
   </xsl:template>

   <!-- process directory elements whilst creating files. In this case just continue
          searching -->
   <xsl:template match="s:dir" mode="file">
      <xsl:apply-templates select="s:dir|s:file" mode="file"/>
   </xsl:template>

   <!-- process file elements to generate Ant concat elements -->
   <xsl:template match="s:file" mode="file">
      <xsl:variable name="path-name">
         <xsl:call-template name="buildFullPath">
            <xsl:with-param name="ancestors" select="ancestor::s:dir"/>
         </xsl:call-template>
      </xsl:variable>
      <xsl:variable name="contents">
         <xsl:choose>
            <xsl:when test="string-length(.) != 0 or child::*">
               <xsl:copy-of select="*|text()"/>
            </xsl:when>
            <xsl:otherwise>
               <xsl:value-of select="@name"/>            
            </xsl:otherwise>
         </xsl:choose>
      </xsl:variable>
      <concat destfile="{$path-name}{@name}"><xsl:copy-of select="$contents"/></concat>
      <xsl:apply-templates select="s:dir|s:file" mode="file"/>
   </xsl:template>

   <!--
        Make an Ant filter element based on some precedence rules:
            1. the name of the directory
            2. the type of the directory (name attribute can be omitted if type name == directory name)
            3. current working directory (may not be best fall-back, TODO)
   -->
   <xsl:template name="makeDirectoryToken">
      <xsl:param name="type"/>
      <xsl:variable name="dir" select="//s:dir[@type=$type]"/>
      <xsl:variable name="dir-path">
         <xsl:apply-templates select="$dir" mode="buildPath"/>
      </xsl:variable>
      <xsl:choose>   
         <xsl:when test="$dir/@name">
            <filter token="{$type}.dir" value="{$dir-path}{$dir/@name}"/>
         </xsl:when>
         <xsl:when test="$dir/@type">
            <filter token="{$type}.dir" value="{$dir-path}{$dir/@type}"/>
         </xsl:when>
         <xsl:otherwise>
            <filter token="{$type}.dir" value="'.'"/>
         </xsl:otherwise>
      </xsl:choose>
   </xsl:template>
   
   <xsl:template match="s:dir" mode="buildPath">
      <xsl:call-template name="buildFullPath">
         <xsl:with-param name="ancestors" select="ancestor::s:dir"/>
      </xsl:call-template>
   </xsl:template>

   <!-- Makes a directory path for a file or dir element. -->
   <xsl:template name="buildFullPath">
      <xsl:param name="ancestors"/>
      <xsl:for-each select="$ancestors">
         <xsl:variable name="name">
            <xsl:choose>
               <xsl:when test="@name">
                  <xsl:value-of select="@name"/>
               </xsl:when>
               <xsl:otherwise>
                  <xsl:value-of select="@type"/>
               </xsl:otherwise>
            </xsl:choose>
         </xsl:variable>
         <xsl:value-of select="concat($name, '/')"/>
      </xsl:for-each>
   </xsl:template>
   
</xsl:stylesheet>
