<project name="ThemeBuildImports" xmlns:if="ant:if" xmlns:unless="ant:unless">
	<description>Common properties and macros needed for sub builds</description>

	<!--
		Someproperties we do not want ANYONE to be able to override.
	-->
	<property name="build.number" value="${project.version}"/>
	<property name="debug.target.file.name.suffix" value="_debug"/>
	<property name="output.dir" location="${build.rootdir}/classes/theme"/><!-- WComponents expects files to be here so don't change it at all -->
	<!--
		Per-user/per build overrides. See `user.xml` for some options.
	-->
	<import file="build-import-overrides.xml" optional="true"/>

	<!--
		Eventually this build will optimise for http2 unless this property is true. Also eventually the default for
		this property will be false.

		As a first cut, if this property is "false" then we will not base64 encode images into the CSS.
	-->
	<property name="build.optimise.http1" value="true"/>

	<!-- GLOBAL PROPERTIES: used in both input and output tasks -->
	<property name="tmp.dir" location="${theme.tmp.dir}"/>


	<property name="npm.loglevel" value="warn"/>

	<!-- INPUT PROPERTIES: relating to the artefacts used as inputs by this build -->
	<property name="theme.src.dir" location="${component.rootdir}/src"/>
	<property name="common.src.rootdir" location="${theme.src.dir}/main"/>
	<property name="impl.src.rootdir" location="${theme.impl.dir}"/>
	<property name="impl.src.dir" location="${impl.src.rootdir}/${implementation.name}"/>
	<property name="impl.src.main.dir" location="${impl.src.dir}/src/main"/>

	<!-- OUTPUT PROPERTIES: relating to the artefacts generated by this build -->
	<property name="target.rootdir" location="${output.dir}/${implementation.name}"/>

	<!--
		This file is used to pass properties calculated in bujild-css to build-js for styleLoader
		TODO: Make this better - i.e. not in build at all.
	-->
	<property name="properties.build.constants" location="${tmp.dir}/all.${implementation.name}.properties" />

	<!-- CSS needs images for base64 -->
	<property name="images.to.base64.dataurls" value="true"/>
	<property name="images.tmp.src.dir" location="${tmp.dir}/images"/>

	<!-- JS properties used elsewhere -->
	<!-- The name of the output directory for compressed JS -->
	<property name="script.target.dir.name" value="scripts"/>
	<!-- The name of the output directory for uncompressed JS -->
	<property name="script.debug.target.dir.name" value="${script.target.dir.name}${debug.target.file.name.suffix}"/>
	<!-- The path to the debug/uncompressed JS. Needed for jsdoc -->
	<property name="script.debug.build.target.dir" location="${target.rootdir}/${script.debug.target.dir.name}"/>

	<!-- resource paths needed in build, JS and XSLT -->
	<property name="resource.target.dir.name" value="resource"/>
	<property name="resource.build.target.dir" location="${output.dir}/${implementation.name}/${resource.target.dir.name}" />

	<!-- Sass/CSS -->
	<property name="css.target.dir.name" value="style"/>
	<property name="css.target.file.name" value="wc"/>

	<!-- ENVIRONMENT PROPERTIES -->
	<property environment="env"/>
	<hostinfo/>

	<path id="project.class.path">
		<path path="${maven.plugin.classpath}"/>
	</path>
	<!-- TASKDEFS and MACRODEFS -->
	<taskdef resource="net/sf/antcontrib/antcontrib.properties" classpathref="project.class.path"/>
	<taskdef resource="net/sf/antcontrib/antlib.xml" classpathref="project.class.path"/>

	<!-- "PRIVATE" properties, for use by macros inside this file - don't play with them -->
	<var name="private.unique.id.increment.count" value="0"/>







	<!--
		Converts a Path to an excludes file. The resulting file will contain a list of file names,
		one name per line. The full file path will be stripped from the file name, leaving only the
		actual name of the file itself.

		excludesFileName The name of the file to write
		pathId The id of the path to write to file
	-->
	<macrodef name="pathToExcludesFile" description="Writes the contents of a path element to an excludes file">
		<attribute name="excludesFileName"/>
		<attribute name="pathId"/>
		<sequential>
			<var name="tmp.pathToExcludesFile" unset="true"/>
			<property name="tmp.pathToExcludesFile" refid="@{pathId}"/>
			<propertyregex property="tmp.pathToExcludesFile.prop"
							override="true"
							input="${tmp.pathToExcludesFile}"
							regexp="${path.separator}"
							replace="&#10;"
							casesensitive="false"/>
			<if>
				<isset property="tmp.pathToExcludesFile.prop"/>
				<then>
					<echo message="${tmp.pathToExcludesFile.prop}" file="@{excludesFileName}"/>
					<replaceregexp file="@{excludesFileName}" match="^.*\${file.separator}" replace="" byline="true"/>
				</then>
				<else>
					<fail>Not a path: @{pathId}</fail>
				</else>
			</if>
		</sequential>
	</macrodef>

	<!--
		Checks that all properties have been expanded during the build.
		Unexpanded properties are a common source of build errors so this
		is an important check.
	-->
	<target name="checkPropertiesExpanded">
		<path id="unexpanded.properties">
			<fileset dir="${output.dir}">
				<include name="**/*.js"/>
				<include name="**/*.css"/>
				<include name="**/*.xsl"/>
				<include name="**/*.xml"/>
				<exclude name="**/lib/**"/>
				<containsregexp expression="\$\{[^\}]+\}"/>
				<!--<contains text="${"/> this would be much better as a regex-->
			</fileset>
		</path>
		<property name="unexpanded" refid="unexpanded.properties"/>
		<fail message="UNEXPANDED PROPERTIES FOUND: ${unexpanded}">
			<condition>
				<resourcecount when="greater" count="0" refid="unexpanded.properties" />
			</condition>
		</fail>
	</target>

	<!--
		Runs static analysis on javascript code.

		Note we deliberately overwrite the config file so it's harder to change.
		This is so we all code to the same standard - if you agree this is a noble goal then please work within this constraint.
		If you don't like the standard get in touch and we can look at changing it.
	-->
	<macrodef name="javascript.lint">
		<attribute name="jsdir" description="The directory that contains javascript to lint."/>
		<attribute name="failonerror" default="true"/>
		<sequential>
			<property name="jshint.executable" location="${basedir}/node_modules/eslint/bin/eslint.js"/>
			<property name="jshintrc" location="${basedir}/.eslintrc"/>
			<property name="jshintignore" location="${basedir}/.eslintignore"/>
			<echo file="${jshintrc}" force="true">{
	"env": {
		"browser": true,
		"amd": true
	},
	"extends": "eslint:recommended",
	"rules": {
		"no-console": 0,
		"no-shadow": 2,
		"brace-style": 2,
		"semi": [2, "always"],
		"space-before-blocks": [2, "always"],
		"spaced-comment": [2, "always"],
		"keyword-spacing": 2,
		"indent": [2, "tab", { "SwitchCase": 1 } ],
		"quotes": 0
	},
	"globals": {
		"KeyEvent": true,
		"Promise": true,
		"DataView": true
	}
}
</echo>
			<echo file="${jshintignore}" force="true"># Only ignore third-party scripts
**/lib/**
</echo>
			<echo>
				If the build fails here it means static analysis has detected Javascript issues.
				Please read the issues below and remedy them.
				All issue descriptions will yield results on Google, or contact your tech lead for help.

				If you have "'variable' is not defined" then please fix it (your forgot to use 'var' or you have a typo).
				In AMD there should be no global variables besides 'require' and 'define'.
			</echo>
			<echo>node ${jshint.executable} @{jsdir} --config ${jshintrc} --ignore-path ${jshintignore}</echo>
			<nodejs.exec cwd="${basedir}" failonerror="@{failonerror}">
				<arguments>
					<arg value="${jshint.executable}"/>
					<arg value="@{jsdir}"/>
					<arg value="--config"/>
					<arg value="${jshintrc}"/>
					<arg value="--ignore-path"/>
					<arg value="${jshintignore}"/>
				</arguments>
			</nodejs.exec>
		</sequential>
	</macrodef>

<!--	<macrodef name="loadJsDebugMap">
		<attribute name="propertyToSet"/>
		<sequential>
			<loadfile property="@{propertyToSet}" srcFile="${tmp.dir}/config/map.txt"/>
		</sequential>
	</macrodef>-->

	<!--
		Does what "npm install" does.
	-->
	<macrodef name="npm.install">
		<attribute name="package" default="" description="The name of the package to install."/>
		<attribute name="cwd" default="${basedir}" description="The working directory"/>
		<attribute name="failonerror" default="false"/>
		<sequential>
			<local name="npm.command"/>
			<property name="npm.command" value="install"/>
			<echo>npm ${npm.command} @{package}</echo>
			<npm.exec cwd="@{cwd}">
				<arg-elements>
					<arg value="${npm.command}"/>
					<arg value="@{package}"/>
				</arg-elements>
			</npm.exec>
		</sequential>
	</macrodef>

	<!--
	This macro knows how to call the npm executable on different platforms.
	It is primarily a helper for other macros in this library.

	Expects the following ant properties to be set:
		project.build.directory - the default working directory (target) - may be overriden with cwd arg
	-->
	<macrodef name="npm.exec">
		<attribute name="cwd" default="${basedir}" description="The working directory"/>
		<attribute name="failonerror" default="false"/>
		<element name="arg-elements" description="Ant 'arg' elements representing the args to pass to the npm command."/>
		<sequential>
			<local name="onwin"/>
			<property environment="env"/>
			<condition property="onwin">
				<os family="windows"/>
			</condition>
			<echo>
				If npm hangs then make sure you have set your ${user.home}/.npmrc file correctly.
			</echo>
			<nodejs.exec cwd="@{cwd}" failonerror="@{failonerror}">
				<arguments>
					<arg value="${npmjs.dir}/npm-cli.js"/>
					<arg-elements />
					<arg value="--loglevel"/>
					<arg value="${npm.loglevel}"/>
				</arguments>
			</nodejs.exec>
		</sequential>
	</macrodef>

	<!--
	This macro knows how to call the nodejs executable on different platforms.
	It is primarily a helper for other macros in this library.

	Expects the following ant properties to be set:
		nodejs.dir - the directory that contains the node executable
		project.build.directory - the default working directory (target) - may be overriden with cwd arg
	-->
	<macrodef name="nodejs.exec">
		<attribute name="cwd" default="${basedir}" description="The working directory"/>
		<attribute name="failonerror" default="false"/>
		<attribute name="spawn" default="false"/>
		<element name="arguments" description="Ant 'arg' elements representing the args to pass to the nodejs command."/>
		<sequential>
			<local name="node.ok"/>
			<local name="nodejs.dir.location"/>
			<property environment="env"/>
			<property name="nodejs.dir.location" location="${nodejs.dir}"/>
			<condition property="node.ok">
				<available file="${nodejs.dir.location}" type="dir"/>
			</condition>
			<fail unless="node.ok">
				Could not find nodejs.
				Current value is: ${nodejs.dir.location}
			</fail>
			<if>
				<os family="windows"/>
				<then>
					<exec dir="@{cwd}" executable="${nodejs.dir.location}/node" failonerror="@{failonerror}" spawn="@{spawn}">
						<env key="Path" path="${npmjs.dir};${nodejs.dir.location};${env.Path}"/>
						<env key="NVM_NODEJS_ORG_MIRROR" value="${node.download.root}"/><!-- TODO externalize. This is to get SASS to build. -->
						<env key="SASS_BINARY_SITE" value="${node.sass.download.root}"/><!-- TODO externalize. This is to get SASS to build. -->
						<arguments />
					</exec>
				</then>
				<else>
					<exec dir="@{cwd}" executable="${nodejs.dir.location}/node" failonerror="@{failonerror}" spawn="@{spawn}">
						<env key="PATH" path="/usr/bin:${npmjs.dir}:${nodejs.dir.location}:${env.PATH}"/>
						<env key="NVM_NODEJS_ORG_MIRROR" value="${node.download.root}"/><!-- TODO externalize. This is to get SASS to build. -->
						<env key="SASS_BINARY_SITE" value="${node.sass.download.root}"/><!-- TODO externalize. This is to get SASS to build. -->
						<arguments />
					</exec>
				</else>
			</if>
		</sequential>
	</macrodef>

	<!--
		General purpose way to invoke an executable.
	-->
	<macrodef name="wc.exec">
		<attribute name="executable" description="The path to the executable"/>
		<attribute name="cwd" default="${basedir}" description="The working directory"/>
		<attribute name="failonerror" default="false"/>
		<attribute name="spawn" default="false"/>
		<attribute name="needscmd" default="true"/>
		<element name="arguments" description="Ant 'arg' elements representing the args to pass to the command."/>
		<sequential>
			<if>
				<os family="windows"/>
				<then>
					<if>
						<equals arg1="@{needscmd}" arg2="true"/>
						<then>
							<exec dir="@{cwd}" executable="cmd" failonerror="@{failonerror}" spawn="@{spawn}">
								<env key="Path" path="${npmjs.dir};${nodejs.dir};${basedir}\node_modules\.bin;${env.Path}"/>
								<arg line="/c &quot;@{executable}&quot;"/>
								<arguments />
							</exec>
						</then>
						<else>
							<exec dir="@{cwd}" executable="@{executable}" failonerror="@{failonerror}" spawn="@{spawn}">
								<env key="Path" path="${npmjs.dir};${nodejs.dir};${basedir}\node_modules\.bin;${env.Path}"/>
								<arguments />
							</exec>
						</else>
					</if>

				</then>
				<else>
					<exec unless:set="onwin" dir="@{cwd}" executable="@{executable}" failonerror="@{failonerror}" spawn="@{spawn}">
						<env key="PATH" path="/usr/bin:${npmjs.dir}:${nodejs.dir}:${basedir}/node_modules/.bin:${env.PATH}"/>
						<arguments />
					</exec>
				</else>
			</if>
		</sequential>
	</macrodef>

	<!--

	This macro performs a transform from XML to JSON using xsltjson: https://github.com/bramstein/xsltjson.

	EXAMPLE:

	<wc.xsltjson
		xsltjsonDir="target/xsltjson"
		xmlDir="${src.dir}/xml"
		jsonDir="target/json"/>

	-->
	<macrodef name="wc.xsltjson">
		<attribute name="xsltjsonDir" description="The directory that contains the xsltjson zip"/>
		<attribute name="xmlDir" description="The directory that contains the XML to transform"/>
		<attribute name="jsonDir" default="@{xmlDir}" description="The directory to hold the result of the transform"/>
		<attribute name="destDir" default="@{xsltjsonDir}" description="The directory in which we will unzip xsltjson."/>
		<attribute name="xslName" default="xml-to-json.xsl" description="The name of the xslt file to use for the transform."/>
		<attribute name="useBadgerfish" default="false"/>
		<attribute name="useRabbitfish" default="false"/>
		<attribute name="useRayfish" default="false"/>
		<attribute name="extension" default=".xml"/>

		<sequential>
			<unzip dest="@{destDir}">
				<patternset>
					<include name="**/*.xsl"/>
					<include name="**/*.jar"/><!-- Not expecting this to exist, belt and braces... -->
				</patternset>
				<fileset dir="@{xsltjsonDir}">
					<include name="*.zip"/>
				</fileset>
				<mapper type="flatten"/>
			</unzip>
			<path id="saxon.classpath">
				<fileset dir="@{destDir}">
					<include name="saxon*.jar"/>
				</fileset>
			</path>
			<mkdir dir="@{jsonDir}"/>
			<xslt basedir="@{xmlDir}" destdir="@{jsonDir}" style="@{destDir}/@{xslName}">
				<classpath>
					<path refid="saxon.classpath"/>
				</classpath>
				<!--
					Any one of these can be switched on.
					With all of them off we produce "basic" JSON where there is no distinction
					between attributes and elements and it would not be possible to transform back to XML.

					Rabbitfish is the same but adds "@" to attributes.

					I believe basic is best for us, but rabbitfish could be an option too.
				-->
				<param name="use-badgerfish" expression="@{useBadgerfish}" type="BOOLEAN"/>
				<param name="use-rabbitfish" expression="@{useRabbitfish}" type="BOOLEAN"/>
				<param name="use-rayfish" expression="@{useRayfish}" type="BOOLEAN"/>
				<mapper type="glob" from="*@{extension}" to="*.json"/>
			</xslt>
		</sequential>
	</macrodef>
</project>
