<project name="themes_build" default="build" xmlns:if="ant:if" xmlns:unless="ant:unless">
	<!--
	This is the main build file for the WComponent themes.

	WARNING! DO NOT CALL ANT TARGETS DIRECTLY! USE MAVEN INSTEAD!
	We use maven to fetch dependencies and set up the classpath.
	The build will not work if you try to run it directly thru ant.

	The main targets of interest are: "build", "test" and "clean".

	-->
	<import file="build-import.xml"/>
	<property name="sub.impl.dir" location="${tmp.dir}/implementations"/>
	<property name="single.impl.dir.separator" value=" "/>
	<property name="impl.dir.name" value="${theme.impl.name}"/>

	<target name="clean"
			depends="cleanTmpDir, cleanImplDir"
			description = "This target cleans all built output for the themes.">
		<delete dir="${sub.impl.dir}"/>
		<delete dir="${output.dir}"/>
		<delete dir="${build.rootdir}"/>
	</target>

	<target name="cleanImplDir" if="impl.dir.present">
		<for param="impl.dir"><!-- clean for each dir in 'implementations' -->
			<dirset dir="${impl.src.rootdir}">
				<depth min="0" max="0"/>
			</dirset>
			<sequential>
				<var name="next.clean.dir.name" unset="true"/>
				<basename property="next.clean.dir.name" file="@{impl.dir}" /><!-- next.clean.dir.name is now the dir name without the path -->
				<callAll implName="${next.clean.dir.name}" target="clean"/>
				<test implName="${next.clean.dir.name}" target="clean"/>
			</sequential>
		</for>
	</target>

	<target name="checkImplExists">
		<!--
			This check should happen as early as possible BUT it should happen after clean tasks have been called
			in case the implementation directory is cleaned away (i.e. it is located in the temporary directory).
		-->
		<available file="${impl.src.rootdir}" type="dir" property="impl.dir.present"/>
	</target>

	<target name="cleanTmpDir">
		<delete dir="${tmp.dir}" failonerror="true"/>
	</target>

	<target name="cleanupOptional" unless="build.preserve.tmp.onexit">
		<delete dir="${tmp.dir}" failonerror="false"/>
	</target>

	<target name="init" depends="cleanTmpDir, initTargetImplementations">
		<echo>build.xml basedir = ${basedir}</echo>
		<mkdir dir="${output.dir}"/>
		<mkdir dir="${sub.impl.dir}"/>
		<echo>Build properties can be overriden in any of the following locations (in order of decreasing priority):</echo>
		<echo>  ${user.home}/.wc/${user.name}.xml (in user home dir)</echo>
		<echo>  ${user.home}/.wc/wc_theme_build_properties.xml (in user home dir)</echo>
		<echo>  ${component.rootdir}/${user.name}.xml (in the project root dir)</echo>
		<echo>  ${component.rootdir}/wc_theme_build_properties.xml (in the project root dir)</echo>
		<!-- We create this package.json file so that we can install node modules locally -->
		<echo force="true" file="${basedir}/.npmrc"># This is a per-project .npmrc file.
# Do not add this file to source control!
# This file is automatically generated and/or overwritten EVERY BUILD!
# Why?
# Since users do not need NPM installed to run these builds we cannot assume they have an .npmrc file.
# This also allows the builds to run on CI or build servers without having to maintain .npmrc on those machines.
# Registry URL property = npm.registry.url
registry=${npm.registry.url}
strict-ssl=false

</echo>
		<if>
			<isset property="mirror.root"/>
			<then>
				<echo append="true" file="${basedir}/.npmrc">
chromedriver_cdnurl=${mirror.root}/chromedriver

				</echo>
			</then>
		</if>
		<copy file="${theme.core.dir}/unbuilt.package.json" tofile="${basedir}/package.json">
			<filterchain>
				<expandproperties/>
			</filterchain>
		</copy>
	<npm.install/>
	</target>

	<target name="initDefaultTheme" unless="impl.dir.present">
		<echo>No custom themes/implementations exist</echo>
		<!--
		<if>
			<isset property="impl.dir.name"/>
			<then>
				<echo level="warn">"impl.dir.name" should not be set if "impl.src.rootdir" is not set</echo>
			</then>
		</if>
		-->
		<mkdir dir="${impl.src.rootdir}"/>
		<ant antfile="${theme.core.dir}/build-implementation.xml" inheritAll="false" target="build">
			<property name="impl.src.rootdir" value="${impl.src.rootdir}"/>
			<property name="new.impl.name" value="${theme.default.name}"/>
		</ant>
		<buildImplementationList rootdir="${impl.src.rootdir}"/>
	</target>

	<target name="initImplementationTheme" if="impl.dir.present">
		<echo>Using provided implementations directory: ${impl.src.rootdir}</echo>
		<if>
			<or>
				<not>
					<isset property="impl.dir.name"/>
				</not>
				<equals arg1="${impl.dir.name}" arg2=""/>
			</or>
			<then>
				<buildImplementationList rootdir="${impl.src.rootdir}"/>
			</then>
		</if>
	</target>

	<target name="initTargetImplementations" depends="checkImplExists, initDefaultTheme, initImplementationTheme">
		<echo>inited target implementations</echo>
	</target>

	<target name="test" depends="initTargetImplementations" description = "This target runs the unit tests for the themes.">
		<for list="${impl.dir.name}" delimiter="${single.impl.dir.separator}" param="implementationName">
			<sequential>
				<test implName="@{implementationName}"/>
			</sequential>
		</for>
		<antcall target="cleanupOptional"/>
	</target>

	<target name="document" depends="initTargetImplementations" description="This target runs the JSDoc build for the themes.">
		<for list="${impl.dir.name}" delimiter="${single.impl.dir.separator}" param="implementationName">
			<sequential>
				<document implName="@{implementationName}"/>
			</sequential>
		</for>
	</target>


	<target name="build"
		description="This target builds the themes."
		depends="failWrongAnt, init">
		<for list="${impl.dir.name}" delimiter="${single.impl.dir.separator}" param="implementationName">
			<sequential>
				<buildImplementation rootdir="${impl.src.rootdir}" implName="@{implementationName}"/>
			</sequential>
		</for>
		<buildImplementationList rootdir="${sub.impl.dir}"/>
		<for list="${impl.dir.name}" delimiter="${single.impl.dir.separator}" param="implementationName">
			<sequential>
				<buildImplementation rootdir="${sub.impl.dir}" implName="@{implementationName}"/>
			</sequential>
		</for>
		<antcall target="cleanupOptional"/>
	</target>

	<!--
		Builds a list of the implementations contained in @rootDir and sets the property
		impl.dir.name with this list.

		We do it this way so that the build scripts take the same path of execution regardless
		of whether the list is built programatically here or provided "as is" by a user in a
		property override.
	-->
	<macrodef name="buildImplementationList">
		<attribute name="rootDir"/>
		<sequential>
			<var name="tmp.impl.dir.name" value=""/>
			<var name="impl.dir.name" unset="true"/>
			<for param="impl.dir"><!-- build for each dir in 'implementations' -->
				<dirset dir="@{rootDir}">
					<depth min="0" max="0"/>
				</dirset>
				<sequential>
					<var name="next.dir.name" unset="true"/>
					<basename property="next.dir.name" file="@{impl.dir}" />
					<var name="tmp.impl.dir.name" value="${tmp.impl.dir.name}${single.impl.dir.separator}${next.dir.name}"/>
				</sequential>
			</for>
			<property name="impl.dir.name" value="${tmp.impl.dir.name}"/>
		</sequential>
	</macrodef>

	<!--
		Builds the implementation named @implName in the directory @rootDir
	-->
	<macrodef name="buildImplementation">
		<attribute name="rootDir"/>
		<attribute name="implName"/>
		<sequential>
			<if>
				<available file="@{rootDir}/@{implName}/inherit.txt" type="file"/>
				<then>
					<echo message="Building sub-implementation @{implName}"/>
					<mergeSubImpl rootDir="@{rootDir}" implName="@{implName}"/>
				</then>
				<else>
					<echo>************************ BUILDING @{implName} ************************</echo>
					<callAll implName="@{implName}" rootdir="@{rootDir}" target="build"/>
					<writeVersionInfo implName="@{implName}"/>
					<antcall target="checkPropertiesExpanded"/>
				</else>
			</if>
		</sequential>
	</macrodef>

	<!--
		Takes care of implementation "inheritance".
		Builds a new "sub implementation" by merging the implementation named @implName
		in the directory @rootDir with the implementation it references in "inherit.txt".
	-->
	<macrodef name="mergeSubImpl">
		<attribute name="rootDir"/>
		<attribute name="implName"/>
		<sequential>
			<var name="impl.src.dir" unset="true"/>
			<property name="impl.src.dir" location="@{rootDir}/@{implName}"/>
			<var name="prototype.name" unset="true"/>
			<loadfile property="prototype.name" srcFile="${impl.src.dir}/inherit.txt"/>

			<var name="prototype.dir" unset="true"/>
			<var name="merge.impl.dir" unset="true"/>

			<if>
				<isset property="prototype.name"/>
				<then>
					<if>
						<and>
							<available file="${prototype.name}" type="file"/>
							<matches string="${prototype.name}" pattern="\.zip$" casesensitive="false"/>
						</and>
						<then>
							<echo>Found prototype zip file ${prototype.name}</echo>
							<property name="prototype.dir" location="${tmp.dir}/parent"/>
							<delete dir="${prototype.dir}"/>
							<!-- unzip the zip and set the path -->
							<unzip src="${prototype.name}" dest="${prototype.dir}" overwrite="true" failOnEmptyArchive="true">
								<patternset>
									<include name="*/**"/>
								</patternset>
							</unzip>
						</then>
						<elseif>
							<and>
								<matches string="${prototype.name}" pattern="\/"/>
								<available file="${prototype.name}" type="dir"/>
							</and>
							<then>
								<echo>Found prototype directory named ${prototype.name}</echo>
								<property name="prototype.dir" location="${prototype.name}"/>
							</then>
						</elseif>
						<elseif>
							<available file="${impl.src.rootdir}/${prototype.name}" type="dir"/>
							<then>
								<property name="prototype.dir" location="${impl.src.rootdir}/${prototype.name}"/>
								<echo>Using simple fallback prototype ${prototype.dir}</echo>
							</then>
						</elseif>
						<else>
							<fail message="Could not find prototype implementation ${prototype.name}"/>
						</else>
					</if>
				</then>
			</if>

			<if>
				<and>
					<isset property="prototype.dir"/>
					<available file="${prototype.dir}" type="dir"/>
				</and>
				<then>
					<property name="merge.impl.dir" location="${sub.impl.dir}/@{implName}"/>
					<delete dir="${merge.impl.dir}"/>
					<echo>Copying sub-implementation files from: ${impl.src.dir} to ${merge.impl.dir}</echo>
					<copy todir="${merge.impl.dir}">
						<!-- Copy the whole implementation to the dir where we will do the merge -->
						<fileset dir="${impl.src.dir}" excludes="inherit.txt">
							<exclude name="**/node/**"/>
							<exclude name="**/node_modules/**"/>
							<exclude name="**/target/**"/>
						</fileset>
					</copy>
					<!--
						We can't just copy the top level dir because we expect the excludes file
						is written relative to the dir that contains the source.
					 -->
					<concat append="true" destfile="${merge.impl.dir}/excludes.txt" fixlastline="yes">
						<!--
							fixlastline does not solve all our problems. If the first excludes file
							contains nothing but a single space then we get problems. Outputting a
							newline in the header solves this issue.
						-->
						<header filtering="no" trimleading="no">${line.separator}</header>
						<filelist dir="${prototype.dir}" files="excludes.txt"/>
						<filterchain>
							<tokenfilter>
								<deletecharacters chars="\t"/>
								<trim/>
								<ignoreblank/>
							</tokenfilter>
						</filterchain>
					</concat>
					<!-- be nice if we could just use sync... maybe we can?
					<sync todir="${merge.impl.dir}" includeEmptyDirs="true" overwrite="false">
						<fileset dir="${prototype.dir}">
							<present present="srconly" targetdir="${merge.impl.dir}"/>
						</fileset>
					</sync>
					-->
					<echo>Copying parent implementation files from: ${prototype.dir} to ${merge.impl.dir}</echo>
					<copy todir="${merge.impl.dir}/src/main/css" overwrite="false">
						<fileset dir="${prototype.dir}/src/main/css" includes="**/*.css" excludesfile="${impl.src.dir}/excludes.txt" erroronmissingdir="false">
							<present present="srconly" targetdir="${merge.impl.dir}/src/main/css"/>
						</fileset>
					</copy>
					<copy todir="${merge.impl.dir}/src/main/sass" overwrite="false">
						<fileset dir="${prototype.dir}/src/main/sass" includes="**/*.scss" excludesfile="${impl.src.dir}/excludes.txt" erroronmissingdir="false">
							<present present="srconly" targetdir="${merge.impl.dir}/src/main/scss"/>
						</fileset>
					</copy>
					<copy todir="${merge.impl.dir}/src/main/xslt" overwrite="false">
						<fileset dir="${prototype.dir}/src/main/xslt" includes="**/*.xsl" excludesfile="${impl.src.dir}/excludes.txt" erroronmissingdir="false">
							<present present="srconly" targetdir="${merge.impl.dir}/src/main/xslt"/>
						</fileset>
					</copy>
					<copy todir="${merge.impl.dir}/src/main/images" overwrite="false">
						<fileset dir="${prototype.dir}/src/main/images" includes="**/*" excludesfile="${impl.src.dir}/excludes.txt" erroronmissingdir="false">
							<present present="srconly" targetdir="${merge.impl.dir}/src/main/images"/>
						</fileset>
					</copy>
					<copy todir="${merge.impl.dir}/src/main/js" overwrite="false">
						<fileset dir="${prototype.dir}/src/main/js" includes="**/*.js" excludesfile="${impl.src.dir}/excludes.txt" erroronmissingdir="false">
							<present present="srconly" targetdir="${merge.impl.dir}/src/main/js"/>
						</fileset>
					</copy>
					<copy todir="${merge.impl.dir}/src/main/resource" overwrite="false">
						<fileset dir="${prototype.dir}/src/main/resource" includes="**/*" excludesfile="${impl.src.dir}/excludes.txt" erroronmissingdir="false">
							<present present="srconly" targetdir="${merge.impl.dir}/src/main/xml"/>
						</fileset>
					</copy>
					<delete file="${merge.impl.dir}/inherit.txt"/><!-- EEEK! Make sure to prevent infinite looping -->
				</then>
				<elseif>
					<isset property="prototype.dir"/>
					<then>
						<fail message="Could not find prototype directory ${prototype.dir}"/>
					</then>
				</elseif>
			</if>
		</sequential>
	</macrodef>

	<target name="antCheck">
		<echo message="ant.version=${ant.version}" />
		<antversion property="antversion" atleast="1.8.2"/>
	</target>

	<target name="failWrongAnt" unless="antversion" depends="antCheck">
		<fail>Use Ant 1.8.2 or newer</fail>
	</target>

	<macrodef name="callAll">
		<attribute name="implName"/>
		<attribute name="rootDir" default="${impl.src.rootdir}"/>
		<attribute name="target" default="build"/>
		<sequential>

			<initImplTmpDir implName="@{implName}"/>
			<!--
				Obviously build properties must be built before anything else can be.
			-->
			<callant antFile="build-images.xml" implName="@{implName}" rootDir = "@{rootDir}" target="@{target}"/>
			<callant antFile="build-resource.xml" implName="@{implName}" rootDir = "@{rootDir}" target="@{target}"/>
			<callant antFile="build-css.xml" implName="@{implName}" rootDir = "@{rootDir}" target="@{target}"/><!-- build after images -->
			<callant antFile="build-i18n.xml" implName="@{implName}" rootDir = "@{rootDir}" target="@{target}"/>
			<callant antFile="build-xslt.xml" implName="@{implName}" rootDir = "@{rootDir}" target="@{target}"/>
			<callant antFile="build-js.xml" implName="@{implName}" rootDir = "@{rootDir}" target="@{target}"/>
		</sequential>
	</macrodef>

	<macrodef name="callant">
		<attribute name="antFile"/>
		<attribute name="implName"/>
		<attribute name="rootDir"/>
		<attribute name="target"/>
		<sequential>
			<stopwatch name="@{antFile}" action="start"/>
			<ant antfile="${theme.core.dir}/@{antFile}" inheritAll="false" target="@{target}">
				<property name="component.rootdir" location="${theme.core.dir}"/>
				<property name="maven.plugin.classpath" value="${maven.plugin.classpath}"/>
				<property name="basedir" location="${basedir}"/>
				<property name="build.number" value="${project.version}"/>
				<property name="build.rootdir" location="${theme.target.dir}"/>
				<property name="theme.skip.tests" value="${skipOptionalTests}"/>
				<property name="impl.src.rootdir" value="@{rootDir}"/>
				<property name="implementation.name" value="@{implName}"/>
				<property name="tmp.dir" location="${impl.tmp.dir}"/>
				<property name="nodejs.dir" location="${nodejs.dir}"/>
				<property name="npmjs.dir" location="${npmjs.dir}"/>
				<property name="npm.registry.url" value="${npm.registry.url}"/>
				<property name="phantomjs.binary" value="${phantomjs.binary}"/>
				<property name="i18n.resources.dir" location="${i18n.resources.dir}"/>
				<property name="i18n.unpack.dir" location="${i18n.unpack.dir}"/>
			</ant>
			<stopwatch name="@{antFile}" action="total"/>
		</sequential>
	</macrodef>

	<macrodef name="test">
		<attribute name="implName"/>
		<attribute name="rootDir" default="${impl.src.rootdir}"/>
		<attribute name="target" default="test"/>
		<sequential>
			<if>
				<not>
					<!--
						Note: this property will only ever be passed in by the maven pom.
						It is ultimately driven by the skipOptionalTests property in the
						parent maven pom (the top level pom in WComponents).
						It allows "flaky" tests (selenium, jsTestDriver, anything that depends
						on browsers) to be skipped on the build box.
					-->
					<equals arg1="${theme.skip.tests}" arg2="true"/>
				</not>
				<then>
					<if>
						<available file="@{rootDir}/@{implName}" type="dir"/>
						<then>
							<initImplTmpDir implName="@{implName}"/>
							<callant antFile="build-test.xml" implName="@{implName}" rootDir = "@{rootDir}" target="@{target}"/>
						</then>
						<else>
							<fail>Implementation "@{implName}" does not exist.
								Check property "impl.dir.name": ${impl.dir.name}
							</fail>
						</else>
					</if>
				</then>
				<else>
					<echo>theme.skip.tests is 'true' so not executing test</echo>
				</else>
			</if>
		</sequential>
	</macrodef>

	<macrodef name="document">
		<attribute name="implName"/>
		<attribute name="rootDir" default="${impl.src.rootdir}"/>
		<attribute name="target" default="build"/>
		<sequential>
			<stopwatch name="site" action="start"/>
			<if>
				<available file="@{rootDir}/@{implName}" type="dir"/>
				<then>
					<initImplTmpDir implName="@{implName}"/>
					<callant antFile="build-jsdoc.xml" implName="@{implName}" rootDir = "@{rootDir}" target="@{target}"/>
				</then>
				<else>
					<echo level="error">Implementation "@{implName}" does not exist.
						Check property "impl.dir.name": ${impl.dir.name}
					</echo>
				</else>
			</if>
			<stopwatch name="site" action="total"/>
		</sequential>
	</macrodef>

	<macrodef name="initImplTmpDir">
		<attribute name="implName"/>
		<sequential>
			<var name="impl.tmp.dir" unset="true"/>
			<property name="impl.tmp.dir" location="${tmp.dir}/@{implName}"/>
			<mkdir dir="${impl.tmp.dir}"/>
		</sequential>
	</macrodef>

	<macrodef name="writeVersionInfo">
		<!--
			This is largely superfluous and a legacy of debugging builds many years in the past.
			It used to dump many different properties.
			HOWEVER one part of it has found new life (in ThemeUtils.java) and therefore this
			file must continue to:

			1. Be named version.properties
			2. Dump the "build.number" property.

			TODO can we ditch this entirely?
		-->
		<attribute name="implName"/>
		<sequential>
			<echo file="${output.dir}/@{implName}/version.properties">build.number=${build.number}</echo>
		</sequential>
	</macrodef>
</project>
