<?xml version="1.0"?>
<project name="Processing" default="build">

  <property environment="env"/>

  <taskdef resource="net/sf/antcontrib/antcontrib.properties">
    <classpath>
      <pathelement location="library/ant-contrib-0.6.jar"/>
    </classpath>
  </taskdef>

  <!-- Only do OS detection if platform isn't already set by override -->
  <condition property="platform" value="macos">
    <and>
      <not><isset property="platform"/></not>
      <os family="mac" />
    </and>
  </condition>

  <condition property="platform" value="windows">
    <and>
      <not><isset property="platform"/></not>
      <os family="windows" />
    </and>
  </condition>

  <condition property="platform" value="linux">
    <and>
      <not><isset property="platform"/></not>
      <and>
        <os family="unix" />
        <not>
          <os family="mac" />
        </not>
      </and>
    </and>
  </condition>

  <property name="examples.dir"
            location="../processing-examples" />

  <!-- 17.0.8+7 -->
  <property name="jdk.train" value="17" />
  <property name="jdk.detail" value="${jdk.train}.0.8" />
  <property name="jdk.build" value="7" />
  <property name="jdk.folder" value="jdk-${jdk.detail}+${jdk.build}" />


  <!-- Require Java ${train} everywhere. Ant works back to 1.10.7 at least. -->
  <fail message="Unsupported Java version: ${java.version}. To build, make sure that Java ${jdk.train} is installed, that you're using Ant 1.10.7 or later, and that JAVA_HOME points at the JDK that you want to use. For instance, on macOS, set it with:${line.separator}export JAVA_HOME=&quot;`/usr/libexec/java_home -v ${jdk.train}`&quot;">
    <condition>
      <not>
        <or>
          <!-- <contains string="${java.version}" substring="${jdk.train}." /> -->
          <equals arg1="${ant.java.version}" arg2="${jdk.train}" />
        </or>
      </not>
    </condition>
  </fail>


  <!-- Identify optional JDK files that can be removed to save space. -->

  <fileset dir="macos/work/Processing.app/Contents" id="jdk-optional-macos">
    <!-- src.zip is 52 MB and we absolutely do not need it -->
    <include name="PlugIns/${jdk.folder}/Contents/Home/lib/src.zip" />
  </fileset>

  <fileset dir="windows/work" id="jdk-optional-windows">
    <include name="java/lib/src.zip" />
  </fileset>

  <fileset dir="linux/work" id="jdk-optional-linux">
    <include name="java/lib/src.zip" />
  </fileset>


  <!-- Macro to help set the platform ant vars appropriately -->

  <!--
  <macrodef name="set-target">
    <attribute name="platform" />
    <attribute name="arch" />
    <sequential>
      <property name="host-platform" value="${platform}" />

      <!- - set the target plaform to the platform attribute passed in - ->
      <property name="target-platform" value="@{platform}" />

      <!- - Set a property named macos, linux, or windows.
           The 'value' chosen is arbitrary. - ->
      <property name="${target-platform}" value="${target-platform}" />

      <property name="jdk.data.model" value="@{datamodel}" />
    </sequential>
  </macrodef>
  -->


  <!-- Downloading the JDK -->

  <target name="jdk-check">
    <!-- JDK archive saved as .zip on Windows, .tgz on macOS and Linux -->
    <condition property="jdk.archive.ext" value="zip" else="tgz">
      <os family="windows" />
    </condition>

    <property name="jdk.archive.path" value="${platform}/jdk-${jdk.detail}-${os.arch}.${jdk.archive.ext}" />

    <echo message="Checking for ${jdk.archive.path}" />
    <available file="${jdk.archive.path}" property="jdk.archive.downloaded" />
    <!-- <echo message="Result: ${jdk.archive.downloaded}" /> -->
  </target>

  <target name="jdk-download" depends="jdk-check"
          unless="jdk.archive.downloaded">

    <!-- Windows is the outlier with the .zip extension (the other downloads
         are .tar.gz). Different from jdk.archive.ext which uses .tgz) -->
    <condition property="jdk.download.ext" value="zip" else="tar.gz">
      <os family="windows" />
    </condition>

    <!-- ${platform} ok for Windows/Linux, but 'macos' needs to be 'mac' -->
    <condition property="jdk.download.os" value="mac" else="${platform}">
      <equals arg1="${platform}" arg2="macos"/>
    </condition>

    <!-- amd64 or x86_64 use x64, others use os.arch -->
    <condition property="jdk.download.arch" value="x64" else="${os.arch}">
      <or>
        <equals arg1="${os.arch}" arg2="amd64" />
        <equals arg1="${os.arch}" arg2="x86_64" />
      </or>
    </condition>

    <property name="jdk.download.dist" value="jdk" />
    <!-- JRE? https://github.com/processing/processing4/issues/365 -->
    <!-- <property name="jdk.download.dist" value="jre" /> -->

    <!-- Java 17.0.1 via Adoptium -->
    <!--
      https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.1%2B12/OpenJDK17U-jre_x64_mac_hotspot_17.0.1_12.tar.gz
      https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.1%2B12/OpenJDK17U-jre_aarch64_mac_hotspot_17.0.1_12.tar.gz
      https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.1%2B12/OpenJDK17U-jdk_x64_windows_hotspot_17.0.1_12.zip
      https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.1%2B12/OpenJDK17U-jdk_x64_linux_hotspot_17.0.1_12.tar.gz
      https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.1%2B12/OpenJDK17U-jdk_arm_linux_hotspot_17.0.1_12.tar.gz
      https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.1%2B12/OpenJDK17U-jdk_aarch64_linux_hotspot_17.0.1_12.tar.gz
    -->
    <property name="jdk.download.url" value="https://github.com/adoptium/temurin17-binaries/releases/download/jdk-${jdk.detail}%2B${jdk.build}/OpenJDK17U-${jdk.download.dist}_${jdk.download.arch}_${jdk.download.os}_hotspot_${jdk.detail}_${jdk.build}.${jdk.download.ext}" />

    <get src="${jdk.download.url}"
         dest="${jdk.archive.path}"
         ignoreerrors="false"
         usetimestamp="true" />

  </target>

  <!-- Set the version of Java that must be present to build. -->
  <property name="jdk.path.macos" location="macos/${jdk.folder}" />
  <available file="${jdk.path.macos}" property="macos_jdk_found" />

  <!--
  <fail if="linux" unless="java_tools_found"
        message="The JAVA_HOME variable must be set to the location of a full JDK. For instance, on Ubuntu Linux, this might be /usr/lib/jvm/java-6-sun." />
  -->

  <!-- For now, just using the os.arch as the dist suffix; not sure if
       the alternatives (x64, arm32, arm64) are better/worth the trouble. -->
  <!-- <property name="dist.suffix" value="${os.arch}" /> -->

  <!-- Figure out the platform-specific output directory for all this work. -->
  <!-- This is set by antcall to assemble. If we set these up here, then we
       can't detect when someone is attempting 'ant assemble' (which is bad). -->
  <!--
  <condition property="target.path"
             value="macos/work/Processing.app/Contents/Java">
    <os family="mac" />
  </condition>

  <condition property="target.path" value="linux/work">
    <os family="unix" />
  </condition>

  <condition property="target.path" value="windows/work">
    <os family="windows" />
  </condition>
  -->

  <!-- Libraries required for running processing -->
  <!-- also need to copy these to the bundleapp task for macos -->
  <fileset dir=".." id="runtime.jars">
    <include name="app/pde.jar" />
    <include name="app/lib/jna.jar" />
    <include name="app/lib/jna-platform.jar" />
    <include name="app/lib/ant.jar" />
    <include name="app/lib/ant-launcher.jar" />
    <include name="app/lib/flatlaf.jar" />
  </fileset>

  <target name="build" description="Build Processing.">
    <antcall target="${platform}-build" />
  </target>

  <!--
  <target name="build" description="Build Processing.">
    <set-target platform="${platform}" arch="${os.arch}" />
    <antcall target="${target-platform}-build" />
  </target>
  -->

  <target name="cross-build-macos-aarch64"
          description="Cross-build Processing for Apple Silicon">
    <set-target platform="macos" arch="aarch64" />
    <antcall target="macos-build" />
  </target>

  <target name="cross-build-macos-x86_64"
          description="Cross-build Processing for macOS (64-bit Intel)">
    <set-target platform="macos" arch="x86_64" />
    <antcall target="macos-build" />
  </target>

  <target name="cross-build-linux-amd64"
          description="Cross-build Processing for Linux (64-bit Intel)">
    <set-target platform="linux" arch="amd64" />
    <antcall target="linux-build" />
  </target>

  <target name="cross-build-linux-aarch64"
          description="Cross-build Processing for Linux (64-bit ARM)">
    <set-target platform="linux" arch="aarch64" />
    <antcall target="linux-build" />
  </target>

  <target name="cross-build-linux-arm"
          description="Cross-build Processing for Linux (32-bit ARM)">
    <set-target platform="linux" arch="arm" />
    <antcall target="linux-build" />
  </target>

  <target name="cross-build-windows"
          description="Cross-build Processing for Windows (64-bit Intel)">
    <set-target platform="windows" arch="amd64" />
    <antcall target="windows-build" />
  </target>

  <!--
  <target name="run" description="Run Processing.">
    <set-target platform="${platform}" arch="${os.arch}" />
    <antcall target="${target-platform}-run" />
  </target>
  -->

  <target name="run" description="Run Processing.">
    <antcall target="${platform}-run" />
  </target>

  <!-- Run the app in a more "native" manner, i.e. no additional
       console for debugging. Ensures that double-clicking shortcuts
       and other desktop integration features work properly. -->
  <target name="app" description="Run Processing w/o console.">
    <antcall target="${platform}-run-app" />
  </target>

  <!-- <target name="dist" depends="revision-check, test" -->
    <target name="dist" depends="revision-check"
            description="Build Processing for distribution.">
    <input message="Enter version number:"
           addproperty="version"
           defaultvalue="${revision}" />

    <available file="${examples.dir}" property="examples.exist" />
    <fail unless="examples.exist" message="To do a distribution, the processing-examples repo must be checked out at the same level as the processing repo." />

    <!-- do a git pull in the docs repo so that it is up to date -->
    <exec executable="git" dir="${examples.dir}">
      <arg line="pull" />
    </exec>

    <antcall target="${platform}-dist" />
  </target>

  <!-- "§$§$&, ant doesn't have a built-in help target :(  -->
  <target name="help" description="Show project help">
    <java classname="org.apache.tools.ant.Main">
      <arg value="-p" />
    </java>
  </target>

  <!-- - - - - - - - - - - - - - - - - - -->
  <!-- Subprojects: Core, App, Libraries -->
  <!-- - - - - - - - - - - - - - - - - - -->

  <target name="subprojects-clean">
    <subant buildpath="../core" target="clean"/>
    <subant buildpath="../app" target="clean"/>
    <subant buildpath="../java/libraries/dxf" target="clean"/>
    <subant buildpath="../java/libraries/io" target="clean"/>
    <subant buildpath="../java/libraries/net" target="clean"/>
    <subant buildpath="../java/libraries/pdf" target="clean"/>
    <subant buildpath="../java/libraries/serial" target="clean"/>
    <subant buildpath="../java/libraries/svg" target="clean"/>
    <subant buildpath="shared/tools/MovieMaker" target="clean"/>
    <subant buildpath="../java" target="clean"/>

    <!-- make sure this isn't around from an old build 140730 -->
    <delete dir="../java/examples" />
  </target>

  <target name="test" depends="build">
    <subant buildpath="../core" target="test"/>
    <subant buildpath="../java" target="test"/>
  </target>

  <target name="subprojects-build">
    <subant buildpath="../core" target="build"/>
    <subant buildpath="../app" target="build"/>
    <subant buildpath="../java/libraries/dxf" target="build"/>
    <subant buildpath="../java/libraries/net" target="build"/>
    <subant buildpath="../java/libraries/pdf" target="build"/>
    <subant buildpath="../java/libraries/serial" target="build"/>
    <subant buildpath="../java/libraries/svg" target="build"/>
    <subant buildpath="shared/tools/MovieMaker" target="build"/>
    <subant buildpath="../java" target="build"/>
  </target>

  <!-- I/O library is only compiled on supported ARM platforms -->
  <condition property="raspberry.pi" value="true">
    <and>
      <equals arg1="${platform}" arg2="${linux}" />
      <or>
        <equals arg1="${os.arch}" arg2="arm" />
        <equals arg1="${os.arch}" arg2="aarch64" />
      </or>
    </and>
  </condition>

  <target name="subprojects-build-rpi" if="raspberry.pi">
    <subant buildpath="../java/libraries/io" target="build"/>
  </target>

  <!-- - - - - - - - - -->
  <!-- Basic Assembly  -->
  <!-- - - - - - - - - -->

  <target name="assemble" depends="version-clear, version-write">
    <fail unless="target.path"
          message="Do not call assemble from the command line." />

    <!-- copy shared tools folder -->
    <copy todir="${target.path}/tools" preservelastmodified="true">
      <fileset dir="shared/tools">
        <patternset>
          <include name="MovieMaker/tool.properties" />
          <include name="MovieMaker/tool/**" />
          <!-- <include name="**/tool/**" /> -->
        </patternset>
      </fileset>
    </copy>

    <!-- make sure ffmpeg/ffmpeg.exe have exec permission -->
    <condition property="ffmpeg.binary" value="ffmpeg.exe" else="ffmpeg">
      <os family="windows" />
    </condition>
    <chmod file="${target.path}/tools/MovieMaker/tool/${ffmpeg.binary}" perm="ugo+x" />

    <!-- See https://github.com/processing/processing4/issues/524 -->
    <!--
    <get src="https://download.processing.org/reference.zip"
         dest="../java/reference.zip"
         ignoreerrors="${reference.ignorable}"
         usetimestamp="true" />
    -->

    <copy todir="${target.path}/modes/java" preservelastmodified="true">
      <fileset dir="../java">
        <!-- don't include LWJGL, it's not operational -->
        <!-- <exclude name="libraries/lwjgl/**" /> -->
        <!-- starting with revision 1276, reference.zip stays intact -->
        <!-- <exclude name="reference.zip" /> -->
        <!-- <exclude name="**/._*" /> -->

        <include name="application/**" />
        <include name="keywords.txt" />

        <include name="libraries/**/examples/**" />
        <include name="libraries/**/library/**" />
        <include name="libraries/**/library.properties" />

        <include name="mode/**" />
        <!-- <include name="reference.zip" /> -->
        <include name="theme/**" />
      </fileset>
    </copy>

    <!-- get the examples folder, but don't require it to build (only required for dist) -->
    <copy todir="${target.path}/modes/java/examples"
          preservelastmodified="true" failonerror="false">
      <fileset dir="${examples.dir}" />
    </copy>

    <!-- if we're creating a dist, the reference is required -->
    <condition property="reference.ignorable" value="false" else="true">
      <isset property="version" />
    </condition>
  </target>

  <target name="version-clear">
    <delete file="${target.path}/lib/version.txt" />
  </target>

  <target name="version-write" if="version">
    <echo file="${target.path}/lib/version.txt" message="${version}"/>
  </target>


  <!-- - - - - - - - - -->
  <!-- Revision check  -->
  <!-- - - - - - - - - -->
  <target name="revision-check">
    <!-- figure out the revision number -->
    <loadfile srcfile="revision" property="revision">
      <filterchain>
        <headfilter lines="1"/>
        <tokenfilter>
          <stringtokenizer suppressdelims="true"/>
          <!-- grab the thing from the first line that's 4 digits -->
          <containsregex pattern="(\d\d\d\d)" />
        </tokenfilter>
      </filterchain>
    </loadfile>
    <!-- <echo message="revision is ${revision}." /> -->

    <!-- figure out the revision number in base.java -->
    <loadfile srcfile="../app/src/processing/app/Base.java"
              property="revision.base">
      <filterchain>
        <tokenfilter>
          <linetokenizer />
          <containsregex pattern="String VERSION_NAME = "/>
          <replaceregex pattern="[^0-9]*" flags="g" replace=""/>
        </tokenfilter>
      </filterchain>
    </loadfile>
    <!-- <echo message="base revision is ${revision.base}." /> -->

    <condition property="revision.correct">
      <!-- Using contains because I can't figure out how to get rid of the
           LF in revision.base. Please file a bug if you have a fix. -->
      <contains string="${revision.base}" substring="${revision}"/>
    </condition>

    <!-- the revision.base property won't be set
         if $revision wasn't found... -->
    <fail unless="revision.correct"
          message="Fix revision number in Base.java" />
  </target>


  <!-- - - - - - - - -->
  <!-- macOS         -->
  <!-- - - - - - - - -->

  <target name="macos-clean" depends="subprojects-clean" description="Clean macOS build">
    <delete dir="macos/work" />
    <delete>
      <fileset dir="macos" includes="processing-*zip" />
    </delete>
  </target>

  <target name="macos-check-os">
    <if>
      <equals arg1="${platform}" arg2="windows" />
      <then>
        <echo>
          =======================================================
          Processing for Mac can only be built on macOS or Linux.

          Bye.
          =======================================================
        </echo>

        <fail message="wrong platform (${os.name})" />
      </then>
    </if>
  </target>

  <target name="macos-build" depends="revision-check, macos-check-os, subprojects-build, jdk-download" description="Build macOS version">
    <mkdir dir="macos/work" />

    <!-- Extract JDK -->
    <echo message="Extracting JDK from ${jdk.archive.path}"/>
    <exec executable="tar" dir="macos">
      <!-- Change directory -->
      <!--
      <arg value="-C" />
      <arg value="linux/work" />
      <arg value="-xzpf" />
      -->
      <arg value="xfz" />
      <arg value="../${jdk.archive.path}"/>
    </exec>

    <!--
    <echo message="creating ${jdk.path.macos}/Contents/Home/legal.zip" />
    <zip destfile="${jdk.path.macos}/Contents/Home/legal.zip"
         basedir="${jdk.path.macos}/Contents/Home"
         includes="legal/**" />
    -->

    <!-- Need a working fat binary of appbundler.jar.
         https://github.com/processing/processing4/issues/284 -->
    <taskdef name="bundleapp"
             classname="com.oracle.appbundler.AppBundlerTask"
             classpath="macos/appbundler-${os.arch}.jar" />

    <bundleapp outputDirectory="macos/work"
               name="Processing"
               displayName="Processing"
               executableName="Processing"
               identifier="org.processing.app"
               signature="Pde4"
               icon="macos/processing.icns"
               copyright="© The Processing Foundation"
               shortVersion="${version}"
               version="${revision}"
               mainClassName="processing.app.ui.Splash"
               jvmRequired="${jdk.train}"
               minimumSystemVersion="10.14.6">

      <!-- mainClassName="processing.app.BaseSplash" -->

      <!-- The appbundler task needs a couple files (the Info.plist and
           anything else outside /jdk) from the full JDK, even though
           it's primarily copying over the JRE folder. -->
      <runtime dir="${jdk.path.macos}/Contents/Home" />

      <!-- use JRE https://github.com/processing/processing4/issues/365 -->
      <!-- <runtime dir="${jdk.path.macos}-jre/Contents/Home" /> -->

      <!-- Same as runtime.jars, seen above; plus core.jar. -->
      <classpath file="../app/pde.jar" />
      <classpath file="../app/lib/jna.jar" />
      <classpath file="../app/lib/jna-platform.jar" />
      <classpath file="../app/lib/ant.jar" />
      <classpath file="../app/lib/ant-launcher.jar" />
      <classpath file="../app/lib/flatlaf.jar" />


      <!-- Creates a copy of core.jar, but that's simplest for now. For 4.0a5
           development, appbundler was briefly changed to recursively walk the
           "Java" folder for all .jar files, so entries from "core" got picked
           up too, including core.jar and the JavaFX jars. But that wasn't the
           right solution for JavaFX (class path and modules path can't mix),
           so had to revert and we're back to duplicating core.jar -->
      <classpath file="../core/library/core.jar" />

      <!-- <arch name="x86_64"/> -->
      <arch name="${os.arch}" />

      <!-- Adding contentTypes="public.text" to PDE files and
           contentTypes="public.zip-archive" to PDEZ and PDEX
           causes appbundler to remove the extension handling,
           so double-clicking files no longer works. -->

      <bundledocument extensions="pde"
                      icon="macos/pde.icns"
                      name="Processing Source Code"
                      role="Editor">
      </bundledocument>

      <bundledocument extensions="pyde"
                      icon="macos/pde.icns"
                      name="Processing Python Source Code"
                      role="Editor">
      </bundledocument>

      <bundledocument extensions="pdez"
                      icon="macos/pdez.icns"
                      name="Processing Sketch Bundle"
                      role="Editor">
      </bundledocument>

      <bundledocument extensions="pdex"
                      icon="macos/pdex.icns"
                      name="Processing Contribution Bundle"
                      role="Viewer">
      </bundledocument>

      <scheme value="pde">
        <!-- implements pde:// scheme for URLs -->
      </scheme>

      <!-- !@#*&$ the @2x splash screen implementation was removed by Oracle -->
      <!-- tiffutil -cathidpicheck about.png about\@2x.png -out about.tiff -->
      <!--<option value="-splash:$APP_ROOT/Contents/Java/lib/about.png" />-->

      <!-- Sets dock icon when debugging (not launched via launch svcs) -->
      <option value="-Xdock:icon=$APP_ROOT/Contents/Resources/processing.icns" />
      <!-- Don't think these actually make any difference.
           (The apple.awt.application.name property is used.)-->
      <!--
      <option value="-Xdock:name=Processing" />
      -->

      <!-- Probably no longer needed? [fry 130917]
      <option value="-Xms128M" />
      -->
      <!-- returning 140606 per PDE X request -->
      <option value="-Xmx512M" />

      <option value="-Dapple.awt.application.name=Processing" />

      <!-- avoid conflicts with JNA DLLs already in the path -->
      <option value="-Djna.nosys=true" />

      <!-- deal with jokers who install JOGL, ANTLR, etc system-wide -->
      <!--<option value="-Djava.ext.dirs=$APP_ROOT/Contents/PlugIns/adoptopenjdk-11.0.1.jdk/Contents/Home/lib/ext" />-->

      <option value="-Dapple.laf.useScreenMenuBar=true" />
      <option value="-Dcom.apple.macos.use-file-dialog-packages=true" />
      <option value="-Dcom.apple.macos.useScreenMenuBar=true" />
      <option value="-Dcom.apple.smallTabs=true" />
      <!-- https://github.com/processing/processing4/issues/699 -->
      <option value="-Dapple.awt.application.appearance=system" />

      <!-- https://github.com/jdf/Processing.py-Bugs/issues/322 -->
      <option value="-Dpython.console.encoding=UTF-8" />

      <!-- <option value="-agentpath:/Applications/YourKit-Java-Profiler-2021.3.app/Contents/Resources/bin/mac/libyjpagent.dylib=disablestacktelemetry,exceptions=disable" /> -->

      <!-- Make it possible to get to JavaFX for Tools, Modes, etc. Not recommended,
           to use those, but making it possible since some Tools rely on JavaFX. -->
      <!-- Removing in 4.0 beta 4, for more information:
           https://github.com/processing/processing4/issues/348
      <option value="-Djava.library.path=$APP_ROOT/Contents/Java:$APP_ROOT/Contents/Java/modes/java/libraries/javafx/library/macos" />
      -->

      <!-- Necessary to avoid complaints because JavaFX wants to be a module. -->
      <!-- Removing in 4.0 beta 4, for more information:
           https://github.com/processing/processing4/issues/348
      <option value="- -module-path=$APP_ROOT/Contents/Java/modes/java/libraries/javafx/library/macos/modules" />

      <option value="- -add-modules=javafx.base,javafx.controls,javafx.fxml,javafx.graphics,javafx.media,javafx.swing,javafx.web" />
      -->

      <!-- Required for video capture and microphone input
           https://github.com/processing/processing-sound/issues/51
           https://github.com/processing/processing-video/issues/134 -->
      <plistentry key="NSCameraUsageDescription" type="string"
                  value="The sketch you're running needs access to your video camera." />
      <plistentry key="NSMicrophoneUsageDescription" type="string"
                  value="The sketch you're running needs access to your microphone." />
    </bundleapp>

    <!-- Changed the native app to no longer look for this folder. -->
    <!-- <mkdir dir="macos/work/Processing.app/Contents/Java/Classes" /> -->

    <!-- Temporary fix until new appbundler is included again after solving
         https://github.com/processing/processing/issues/3359
         https://github.com/processing/processing/issues/3360
         The 'keytool' file is deleted by our appbundler. Add it back so that
         Android signing works properly. (Not modifying our appbundler since
         most of the time that appbundler is used, keytool isn't needed).
         Also, because Ant's copy task does not retain file permissions on
         Unix systems, we need to use <exec executable="cp" ... > instead -->
    <exec executable="cp">
      <arg value="-r"/>
      <arg line="${jdk.path.macos}/Contents/Home/bin macos/work/Processing.app/Contents/PlugIns/${jdk.folder}/Contents/Home/bin"/>
    </exec>

    <exec executable="cp">
      <arg value="-r"/>
      <arg line="${jdk.path.macos}/Contents/Home/jmods macos/work/Processing.app/Contents/PlugIns/${jdk.folder}/Contents/Home/jmods"/>
    </exec>

    <!--
    <exec executable="cp">
      <arg value="-r"/>
      <arg line="${jdk.path.macos}/Contents/Home/legal macos/work/Processing.app/Contents/PlugIns/${jdk.folder}/Contents/Home/legal"/>
    </exec>
    -->
    <!-- Throw these 300(!) files into a single zip -->
    <zip destfile="macos/work/Processing.app/Contents/PlugIns/${jdk.folder}/Contents/Home/legal.zip"
         basedir="${jdk.path.macos}/Contents/Home"
         includes="legal/**" />

    <exec executable="cp">
      <arg value="-r"/>
      <arg line="${jdk.path.macos}/Contents/Home/conf macos/work/Processing.app/Contents/PlugIns/${jdk.folder}/Contents/Home/conf"/>
    </exec>

    <property name="contents.dir"
              location="macos/work/Processing.app/Contents" />

    <copy todir="${contents.dir}/Java" preservelastmodified="true">
      <fileset dir=".." includes="core/library/**" /> <!-- why this? -->
      <fileset dir="shared" includes="lib/**" />
      <fileset file="shared/revisions.md" />
    </copy>

    <!-- Can't use this method since the appbundler builds have split:
         we have a fat binary on aarch64 that has a broken x86_64 build,
         and the x86_64 version has no aarch64 build at all.
         For 4.0, this is being copied manually after also doing:
         lipo stub-aarch64-fat -remove x86_64 -output stub-aarch64
         on the binary produce on Apple Silicon, otherwise it looks
         like a legitimate 'Fat' binary which confuses debugging. -->
    <!-- Use the Processing executable as the stub for exported apps.
         This works b/c everything app-specific is in Info.plist. -->
    <!--
    <property name="app.stub"
              value="${contents.dir}/Java/modes/java/application/mac-app-stub" />
    -->
    <!-- Grab a copy of the stub binary before it is signed.
         (See processing.mode.java.JavaBuild for usage.)
         Prevents signing errors with exported apps. -->
    <!--
    <copy file="${contents.dir}/MacOS/Processing" tofile="${app.stub}" />
    -->
    <!-- The ant copy command does not preserve permissions. -->
    <!--
    <chmod file="${app.stub}" perm="ugo+x" />
    -->

    <antcall target="assemble">
      <param name="target.path" value="${contents.dir}/Java" />
    </antcall>

    <delete failonerror="true">
      <fileset refid="jdk-optional-macos" />
    </delete>

    <!-- Python 3 required, now that Python 2 has been removed from macOS -->
    <exec executable="macos/language_gen.py" failonerror="true" />

    <property name="launch4j.dir"
              value="${contents.dir}/Java/modes/java/application/launch4j" />

    <!-- rename the version we need -->
    <move file="${launch4j.dir}/bin/windres-macos"
          tofile="${launch4j.dir}/bin/windres" />
    <move file="${launch4j.dir}/bin/ld-macos"
          tofile="${launch4j.dir}/bin/ld" />

    <!-- make executable (ant doesn't preserve) -->
    <chmod perm="ugo+x" file="${launch4j.dir}/bin/windres" />
    <chmod perm="ugo+x" file="${launch4j.dir}/bin/ld" />

    <!-- remove the others -->
    <delete failonerror="true">
      <fileset dir="${launch4j.dir}/bin" includes="ld-*" />
      <fileset dir="${launch4j.dir}/bin" includes="windres-*" />
    </delete>

    <!-- remove temporary files -->
    <exec executable="rm">
      <arg value="-r"/>
      <arg line="${jdk.path.macos}"/>
    </exec>
  </target>

  <target name="macos-run" depends="macos-build"
          description="Run macOS version">

    <!-- Terminal.app has a new location in Catalina -->
    <available file="/System/Applications/Utilities/Terminal.app" type="dir"
               property="terminal.path"
               value="/System/Applications/Utilities/Terminal.app" />

    <available file="/Applications/Utilities/Terminal.app" type="dir"
               property="terminal.path"
               value="/Applications/Utilities/Terminal.app" />

    <exec executable="open" dir="macos/work" spawn="true">
      <arg value="-a" />
      <arg value="${terminal.path}" />
      <arg value="Processing.app/Contents/MacOS/Processing" />
    </exec>
  </target>

  <target name="macos-run-app" depends="macos-build"
          description="Run macOS version without console">
    <exec executable="open" dir="macos/work" spawn="true">
      <arg value="Processing.app" />
    </exec>
  </target>

  <target name="macos-dist-sign" if="env.PROCESSING_APP_SIGNING">
    <echo>
      Code signing will only work if you have a $99/yr Apple developer ID.
    </echo>

    <!-- Use "3rd Party Mac Developer Application" for the app store,
         instead of "Developer ID Application" when just doing Gatekeeper. -->
    <!--<arg value="3rd Party Mac Developer Application" />-->

    <exec executable="/usr/bin/codesign" dir="macos/work" failonerror="true">
      <arg value="--force" />

      <arg value="--sign" />
      <arg value="Developer ID Application" />

      <arg value="--entitlements" />
      <arg value="../ffs.entitlements" />

      <arg value="Processing.app/Contents/PlugIns/${jdk.folder}" />
    </exec>

    <!-- codesign can't work inside jars? so instead temporarily unpack the files
         that contain dylib entries, just before doing our big signing event -->

    <!--
    <property name="unpack.jogl" value="macos/work/Processing.app/Contents/Java/core/library/jogl-all-natives-macosx-universal" />
    <unzip src="${unpack.jogl}.jar" dest="${unpack.jogl}" />

    <property name="unpack.gluegen" value="macos/work/Processing.app/Contents/Java/core/library/gluegen-rt-natives-macosx-universal" />
    <unzip src="${unpack.gluegen}.jar" dest="${unpack.gluegen}" />
    -->

    <property name="unpack.jssc" value="macos/work/Processing.app/Contents/Java/modes/java/libraries/serial/library/jssc" />
    <unzip src="${unpack.jssc}.jar" dest="${unpack.jssc}-unpack" />

    <property name="unpack.core" value="macos/work/Processing.app/Contents/Java/core" />
    <unzip src="${unpack.core}.jar" dest="${unpack.core}-unpack" />

    <property name="unpack.jna" value="macos/work/Processing.app/Contents/Java/jna" />
    <unzip src="${unpack.jna}.jar" dest="${unpack.jna}-unpack" />

    <property name="unpack.core2" value="macos/work/Processing.app/Contents/Java/core/library/core" />
    <unzip src="${unpack.core2}.jar" dest="${unpack.core2}-unpack" />

    <!-- <unzip src="macos/work/Processing.app/Contents/Java/modes/java/libraries/serial/library/jssc.jar" dest="macos/work/Processing.app/Contents/Java/modes/java/libraries/serial/library/jssc" /> -->

    <apply executable="/usr/bin/codesign" dir="macos/work" failonerror="true">
      <arg value="--sign" />
      <arg value="Developer ID Application" />

      <!-- remove all other signatures -->
      <arg value="--force" />

      <arg value="--entitlements" />
      <arg value="../ffs.entitlements" />

      <!-- recursively sign everything -->
      <arg value="--deep" />

      <!-- enable the "hardened runtime" -->
      <arg value="--options" />
      <arg value="runtime" />

      <fileset dir="macos/work/Processing.app/Contents/Java">
        <patternset>
          <include name="**/*.dylib" />
          <include name="**/*.jnilib" />
          <!-- <include name="**/*.jar" /> -->
          <!-- <include name="**/*.app" /> -->

          <include name="modes/java/application/stub-macos-aarch64" />
          <include name="modes/java/application/stub-macos-x86_64" />
          <include name="modes/java/application/launch4j/bin/windres" />
          <include name="modes/java/application/launch4j/bin/ld" />
          <include name="tools/MovieMaker/tool/ffmpeg" />
        </patternset>
      </fileset>
    </apply>

    <!-- re-package the jar files after signing their macOS contents -->
    <!--
    <zip destfile="${unpack.jogl}.jar" basedir="${unpack.jogl}" />
    <zip destfile="${unpack.gluegen}.jar" basedir="${unpack.gluegen}" />
    -->
    <zip destfile="${unpack.jssc}.jar" basedir="${unpack.jssc}-unpack" />
    <zip destfile="${unpack.core}.jar" basedir="${unpack.core}-unpack" />
    <zip destfile="${unpack.jna}.jar" basedir="${unpack.jna}-unpack" />
    <zip destfile="${unpack.core2}.jar" basedir="${unpack.core2}-unpack" />

    <!-- delete the temporary directories w/ the jar contents -->
    <!--
    <delete dir="${unpack.jogl}" />
    <delete dir="${unpack.gluegen}" />
    -->
    <delete dir="${unpack.jssc}-unpack" />
    <delete dir="${unpack.core}-unpack" />
    <delete dir="${unpack.jna}-unpack" />
    <delete dir="${unpack.core2}-unpack" />

    <!-- sign the outer application, now that we've finished all the contents -->
    <exec executable="/usr/bin/codesign" dir="macos/work" failonerror="true">
      <arg value="--sign" />
      <arg value="Developer ID Application" />

      <!-- remove all other signatures -->
      <arg value="--force" />

      <!-- recursively sign everything -->
      <arg value="--deep" />

      <arg value="--entitlements" />
      <arg value="../ffs.entitlements" />

      <!-- enable the "hardened runtime" -->
      <arg value="--options" />
      <arg value="runtime" />

      <arg value="Processing.app" />
    </exec>

    <!-- Verify that the signature will pass Gatekeeper checks
         https://developer.apple.com/library/mac/technotes/tn2206 -->
    <!--
    <exec executable="/usr/bin/codesign" dir="macos/work">
      <arg value="- -verify" />
      <arg value="- -deep" />
      <arg value="- -verbose=2" />
      <arg value="Processing.app" />
    </exec>
    -->
    <!-- Disabling since it's a lot of gunk but not that useful. -->
  </target>

  <target name="macos-dist-notarize" if="env.PROCESSING_APP_PASSWORD">
    <!-- xcrun: error: unable to find utility "altool", not a developer tool or in PATH -->
    <!-- fix with 'sudo xcode-select -r' -->

    <!-- when it's time to sign/update documents or make an app password: -->
    <!-- https://developer.apple.com/account/ -->

    <exec executable="/usr/bin/xcrun" dir="macos" failonerror="true">
      <arg value="notarytool" />
      <arg value="submit" />

      <!-- spew a bunch of useless garbage that has nothing to do with success/failure -->
      <!-- <arg value="- -verbose" /> -->


      <arg value="--apple-id" />
      <arg value="${env.PROCESSING_APPLE_ID}" />

      <arg value="--password" />
      <arg value="${env.PROCESSING_APP_PASSWORD}" />

      <arg value="--team-id" />
      <arg value="${env.PROCESSING_TEAM_ID}" />

      <arg value="${dist.filename}" />
    </exec>

    <echo>
      Check on notarization status with:

      xcrun notarytool info --apple-id $PROCESSING_APPLE_ID --password $PROCESSING_APP_PASSWORD --team-id $PROCESSING_TEAM_ID [the Submission ID above]
    </echo>
  </target>

  <target name="macos-dist" depends="macos-build"
          description="Create a downloadable .zip for the macOS version">

    <antcall target="macos-dist-sign" />

    <condition property="dist.suffix" value="x64" else="${os.arch}">
      <equals arg1="${os.arch}" arg2="x86_64" />
    </condition>

    <property name="dist.filename"
              value="processing-${version}-macos-${dist.suffix}.zip" />

    <exec executable="ditto" dir="macos/work">
      <arg line="-c -k -rsrc . ../${dist.filename}" />
    </exec>

    <antcall target="macos-dist-notarize" />

    <echo>
      =======================================================
      Processing for macOS was built. Grab it from

      macos/${dist.filename}
      =======================================================
    </echo>
  </target>


  <!-- - - - - - - - -->
  <!-- Linux         -->
  <!-- - - - - - - - -->

  <target name="linux-clean" depends="subprojects-clean" description="Clean linux version">
    <delete dir="linux/work" />
    <delete>
      <fileset dir="linux" includes="processing-*tgz" />
    </delete>
  </target>

  <target name="linux-check-os">
    <if>
      <equals arg1="${platform}" arg2="windows" />
      <then>
        <echo>
          =========================================================
          Processing for Linux can only be built on Linux or macOS.

          Bye.
          =========================================================
        </echo>

        <fail message="wrong platform (${os.name})" />
      </then>
    </if>
  </target>

  <target name="linux-build" depends="revision-check, linux-check-os, jdk-download, subprojects-build, subprojects-build-rpi" description="Build Linux version">
    <mkdir dir="linux/work" />

    <copy todir="linux/work" preservelastmodified="true">
      <fileset dir=".." includes="core/library/**" />
      <fileset dir="shared" includes="launch4j/**" />
      <fileset dir="shared" includes="lib/**"  />
      <fileset dir="shared" includes="modes/**" />
      <fileset file="shared/revisions.md" />
    </copy>

    <antcall target="assemble">
      <param name="target.path" value="linux/work" />
    </antcall>

    <property name="launch4j.dir"
              value="linux/work/modes/java/application/launch4j" />

    <!-- for ARM, we need different binaries for ld and windres -->
    <property name="launch4j.variant" value="linux" />
    <condition property="launch4j.variant"
               value="linux-armv6hf" else="linux">
      <or>
        <equals arg1="${os.arch}" arg2="arm" />
        <equals arg1="${os.arch}" arg2="aarch64" />
      </or>
    </condition>

    <!-- rename the version we need -->
    <move file="${launch4j.dir}/bin/windres-${launch4j.variant}"
          tofile="${launch4j.dir}/bin/windres" />
    <move file="${launch4j.dir}/bin/ld-${launch4j.variant}"
          tofile="${launch4j.dir}/bin/ld" />

    <!-- make executable (ant doesn't preserve) -->
    <chmod perm="ugo+x" file="${launch4j.dir}/bin/windres" />
    <chmod perm="ugo+x" file="${launch4j.dir}/bin/ld" />

    <!-- remove the others -->
    <delete failonerror="true">
      <fileset dir="${launch4j.dir}/bin" includes="ld-*" />
      <fileset dir="${launch4j.dir}/bin" includes="windres-*" />
    </delete>

    <copy todir="linux/work/lib" flatten="true" preservelastmodified="true">
      <fileset refid="runtime.jars" />
    </copy>

    <copy file="linux/processing" todir="linux/work" />
    <chmod perm="ugo+x" file="linux/work/processing" />

    <!-- copy command line tool -->
    <copy file="linux/processing" tofile="linux/work/processing-java" />
    <chmod perm="ugo+x" file="linux/work/processing-java" />

    <!-- This allows Linux users to add mime types to the PDE by simply
         running the install script added to the Processing folder.
         This adds the following features:
         - the icons for the PDE in different resolutions
         - icons for the files
         - a desktop icon
         - when double clicking the *.pde files, the PDE will be opened

         from Sweden with <3
    -->
    <copy file="linux/install.sh" todir="linux/work" />
    <chmod perm="ugo+x" file="linux/work/install.sh" />

    <copy file="linux/uninstall.sh" todir="linux/work" />
    <chmod perm="ugo+x" file="linux/work/uninstall.sh" />

    <copy file="linux/processing-pde.xml" todir="linux/work/lib" />
    <copy file="linux/appdata.xml" todir="linux/work/lib" />
    <copy file="linux/desktop.template" todir="linux/work/lib" />

    <!--
    Cannot use ant version of tar because it doesn't preserve properties.
    <untar compression="gzip"
           dest="linux/work"
           src="linux/jdk.tgz"
           overwrite="false"/>
    -->

    <!--
      http://www.gnu.org/software/tar/manual/html_section/transform.html
    -->
    <exec executable="tar" dir="linux">
      <!-- Change directory -->
      <!--
      <arg value="-C" />
      <arg value="linux/work" />
      <arg value="-xzpf" />
      -->
      <arg value="xfz" />
      <arg value="../${jdk.archive.path}"/>
    </exec>

    <exec executable="rsync" dir="linux">
      <arg value="-a" />
      <arg value="--delete" />
      <arg value="${jdk.folder}/" />
      <arg value="work/java/" />
    </exec>

    <!-- Remove unused JRE bloat. -->
    <delete failonerror="true">
      <fileset refid="jdk-optional-linux" />
    </delete>

    <!-- Throw these 300(!) files into a single zip -->
    <zip destfile="linux/work/java/legal.zip"
         basedir="linux/work/java"
         includes="legal/**" />
    <delete dir="linux/work/java/legal" />

    <exec executable="rm">
      <arg value="-r"/>
      <arg line="linux/${jdk.folder}"/>
    </exec>
  </target>

  <target name="linux-run" depends="linux-build"
          description="Run Linux version">
    <exec executable="./processing" dir="linux/work" spawn="true"/>
  </target>

  <target name="linux-dist" depends="linux-build"
          description="Build .tar.gz of linux version">

    <!-- rename the work folder temporarily -->
    <move file="linux/work" tofile="linux/processing-${version}" />

    <condition property="dist.suffix" value="x64">
      <equals arg1="${os.arch}" arg2="amd64" />
    </condition>

    <condition property="dist.suffix" value="arm32">
      <equals arg1="${os.arch}" arg2="arm" />
    </condition>

    <condition property="dist.suffix" value="arm64">
      <equals arg1="${os.arch}" arg2="aarch64" />
    </condition>

    <property name="linux.dist" value="linux/processing-${version}-linux-${dist.suffix}.tgz" />

    <exec executable="tar">
      <arg value="--directory=linux" />
      <arg value="--file=${linux.dist}" />
      <arg value="-cpz" />
      <arg value="processing-${version}" />
    </exec>

    <!-- put... the candle... back -->
    <!-- (rename the work processing-NNNN version to work) -->
    <move file="linux/processing-${version}" tofile="linux/work" />

    <echo>
      =======================================================
      Processing for Linux was built. Grab the archive from

      ${linux.dist}
      =======================================================
    </echo>
  </target>

  <!-- TODO Hasn't been tested for a bit, so this is probably broken...
            In particular, the JavaScript stanza is unlikely to work
            in Java 17, but there may be other issues. [fry 220124] -->
  <target name="deb" depends="dist"
          description="Build .deb of the Linux version">

    <!-- start with a clean debian folder -->
    <delete dir="linux/debian" quiet="true" />

    <!-- setup the file structure -->
    <mkdir dir="linux/debian/opt" />
    <mkdir dir="linux/debian/usr/bin" />
    <mkdir dir="linux/debian/usr/share/applications/" />
    <mkdir dir="linux/debian/usr/share/mime/packages/" />
    <!-- rename the work folder temporarily -->
    <move file="linux/work" tofile="linux/debian/opt/processing" />
    <symlink link="linux/debian/usr/bin/processing"
             resource="../../opt/processing/processing" />
    <symlink link="linux/debian/usr/bin/processing-java"
             resource="../../opt/processing/processing-java" />

    <!-- place .desktop and .sharedmimeinfo file -->
    <copy file="linux/processing.desktop"
          tofile="linux/debian/usr/share/applications/processing.desktop">
      <filterchain>
        <replacetokens>
          <token key="version" value="${version}" />
        </replacetokens>
      </filterchain>
    </copy>

    <copy file="linux/processing.sharedmimeinfo"
          tofile="linux/debian/usr/share/mime/packages/processing.xml" />

    <!-- Set properties for DEBIAN/control file -->

    <!-- Testing on a Model 3 (not plus), 4, and 400,
         uname is armv7l with raspios dated 2021-10-30.
         For most platforms, use os.arch, but use "armv7l" for
         32-bit pi because just "arm" is unhelpful/ambiguous. -->
    <condition property="deb.arch" value="armv7l" else="${os.arch}">
      <equals arg1="${os.arch}" arg2="arm" />
    </condition>

    <property name="linux.deb"
              value="linux/processing-${version}-linux-${deb.arch}.deb" />

    <length property="deb.bsize" >
      <fileset dir="linux/debian" />
    </length>

    <!-- guessing that this will not be working with Java 17 w/o JS -->
    <script language="javascript">
      <![CDATA[
         var length_bytes = project.getProperty("deb.bsize");
         var length_kbytes = Math.ceil(length_bytes / 1024);
         project.setNewProperty("deb.kbsize", length_kbytes);
      ]]>
    </script>

   <!-- place DEBIAN/control file. -->
    <mkdir dir="linux/debian/DEBIAN" />
    <copy file="linux/control" tofile="linux/debian/DEBIAN/control" >
      <filterchain>
        <replacetokens>
          <token key="version" value="${version}" />
          <token key="size" value="${deb.kbsize}" />
          <token key="arch" value="${deb.arch}" />
        </replacetokens>
      </filterchain >
    </copy >
    <copy file="linux/copyright" tofile="linux/debian/DEBIAN/copyright" />

    <!-- Create .deb file -->
    <exec executable="fakeroot" dir="linux" failonerror="true">
      <arg value="dpkg-deb" />
      <arg value="--build" />
      <arg value="debian" />
      <arg value="../${linux.deb}" />
    </exec>

    <!-- put... the candle... back -->
    <!-- (rename the debian processing version to work) -->
    <move file="linux/debian/opt/processing" tofile="linux/work" />

    <!-- cleanup -->
    <delete dir="linux/debian" />

    <echo>
      ========================================================
      Processing for Debian Linux was built. Grab the deb from

      ${linux.deb}
      ========================================================
    </echo>
  </target>


  <!-- - - - - - - - -->
  <!-- Windows       -->
  <!-- - - - - - - - -->

  <target name="windows-clean" depends="subprojects-clean"
          description="Clean windows version">
    <delete dir="windows/work" />
    <delete>
      <fileset dir="windows" includes="processing-*zip" />
    </delete>
  </target>

  <target name="windows-check-os" unless="windows">
    <!-- Left for consistency. Windows can be built on mac, linux, or windows. -->
  </target>

  <target name="windows-build" depends="revision-check, windows-check-os, jdk-download, subprojects-build" description="Build Windows version">
    <mkdir dir="windows/work" />

    <!-- assemble the pde -->
    <mkdir dir="windows/work/lib" />
    <copy todir="windows/work/lib" flatten="true" preservelastmodified="true">
      <fileset refid="runtime.jars" />
    </copy>

    <!-- unpack the JNA DLLs for Windows to work around
         https://github.com/processing/processing/issues/3624 -->

    <condition property="jna.subfolder" value="win32-x86">
      <equals arg1="${sun.arch.data.model}" arg2="32" />
    </condition>
    <condition property="jna.subfolder" value="win32-x86-64">
      <equals arg1="${sun.arch.data.model}" arg2="64" />
    </condition>

    <unzip src="../app/lib/jna.jar" dest="windows/work/lib">
      <patternset>
        <include name="com/sun/jna/${jna.subfolder}/jnidispatch.dll" />
      </patternset>
      <mapper type="flatten"/>
    </unzip>

    <copy todir="windows/work" preservelastmodified="true">
      <fileset dir=".." includes="core/library/**" />
      <fileset dir="shared" includes="launch4j/**" />
      <fileset dir="shared" includes="lib/**" />
      <fileset dir="shared" includes="modes/**" />
      <fileset file="shared/revisions.md" />
    </copy>

    <copy todir="windows/work/lib" preservelastmodified="true">
      <fileset dir="windows" includes="*.ico" />
    </copy>

    <fixcrlf file="windows/work/revisions.md" eol="crlf" encoding="UTF-8" />

    <antcall target="assemble">
      <param name="target.path" value="windows/work" />
    </antcall>

    <property name="launch4j.dir" value="windows/work/modes/java/application/launch4j" />

    <!-- rename the version we need -->
    <move file="${launch4j.dir}/bin/windres-windows.exe"
          tofile="${launch4j.dir}/bin/windres.exe" />
    <move file="${launch4j.dir}/bin/ld-windows.exe"
          tofile="${launch4j.dir}/bin/ld.exe" />

    <!-- check for cross-build -->
    <if>
      <not>
        <equals arg1="${platform}" arg2="windows" />
      </not>
      <then>
        <move file="${launch4j.dir}/bin/windres-${platform}"
              tofile="${launch4j.dir}/bin/windres" />

        <move file="${launch4j.dir}/bin/ld-${platform}"
              tofile="${launch4j.dir}/bin/ld" />

        <exec executable="chmod">
          <arg value="+x"/>
          <arg line="${launch4j.dir}/bin/windres"/>
        </exec>

        <exec executable="chmod">
          <arg value="+x"/>
          <arg line="${launch4j.dir}/bin/ld"/>
        </exec>
      </then>
    </if>

    <!-- Execute launch4j task -->
    <taskdef name="launch4j"
             classname="net.sf.launch4j.ant.Launch4jTask"
             classpath="${launch4j.dir}/launch4j.jar;
                        ${launch4j.dir}/lib/xstream.jar" />

    <!-- not all launch4j options are available when embedded inside this
         file (i.e. the icon param doesn't work), so use a config file -->
    <launch4j configFile="windows/config.xml" />
    <launch4j configFile="windows/config-cmd.xml" />

    <!-- remove the other launch4j executables -->
    <delete failonerror="true">
      <fileset dir="${launch4j.dir}/bin" includes="ld-*" />
      <fileset dir="${launch4j.dir}/bin" includes="windres-*" />
      <fileset dir="${launch4j.dir}/bin" includes="windres" />
      <fileset dir="${launch4j.dir}/bin" includes="ld" />
    </delete>

    <!-- cygwin requires html, dll, and exe to have the +x flag -->
    <chmod perm="ugo+x">
      <fileset dir="windows/work" includes="**/*.html, **/*.dll, **/*.exe" />
    </chmod>

    <!-- Hopefully this is OK with the permissions (unlike Linux),
         since those shouldn't matter on Windows. -->
    <unzip dest="windows/work"
           src="${jdk.archive.path}"
           overwrite="false" />

    <!-- Rename the unpacked JDK to just 'java' and move to dist -->
    <move file="windows/work/${jdk.folder}" tofile="windows/work/java" />

    <!-- Throw these 300(!) files into a single zip -->
    <zip destfile="windows/work/java/legal.zip"
         basedir="windows/work/java"
         includes="legal/**" />
    <delete dir="windows/work/java/legal" />

    <!-- Remove unused Java bloat -->
    <delete failonerror="true">
      <fileset refid="jdk-optional-windows" />
    </delete>
  </target>

  <target name="windows-run" depends="windows-build"
          description="Run windows version">
    <exec executable="windows/work/processing.exe"
          dir="windows/work" spawn="true"/>
  </target>

  <target name="windows-dist" depends="windows-build"
          description="Create .zip files of windows version">

    <condition property="dist.suffix" value="x64" else="${os.arch}">
      <equals arg1="${os.arch}" arg2="amd64" />
    </condition>

    <property name="windows.dist" value="windows/processing-${version}-windows-${dist.suffix}.zip" />

    <zip destfile="${windows.dist}">
      <zipfileset dir="windows/work"
                  prefix="processing-${version}" />
    </zip>

    <echo>
      =======================================================
      Processing for Windows was built. Grab the archive from

      ${windows.dist}
      =======================================================
    </echo>
  </target>


  <!-- OUT OF DATE -->
  <!-- bundle a bunch of PNGs into an OS X iconset -->
  <target name="iconset">
    <mkdir dir="${icon.set}" />
    <!--<echo message="root = ${icon.root} / set = ${icon.set}" />-->

    <copy file="${icon.root}-16.png"
          tofile="${icon.set}/icon_16x16.png" />
    <copy file="${icon.root}-32.png"
          tofile="${icon.set}/icon_16x16@2x.png" />

    <copy file="${icon.root}-32.png"
          tofile="${icon.set}/icon_32x32.png" />
    <copy file="${icon.root}-64.png"
          tofile="${icon.set}/icon_32x32@2x.png" />

    <copy file="${icon.root}-128.png"
          tofile="${icon.set}/icon_128x128.png" />
    <copy file="${icon.root}-256.png"
          tofile="${icon.set}/icon_128x128@2x.png" />

    <copy file="${icon.root}-256.png"
          tofile="${icon.set}/icon_256x256.png" />
    <copy file="${icon.root}-512.png"
          tofile="${icon.set}/icon_256x256@2x.png" />

    <copy file="${icon.root}-512.png"
          tofile="${icon.set}/icon_512x512.png" />
    <copy file="${icon.root}-1024.png"
          tofile="${icon.set}/icon_512x512@2x.png" />

    <exec executable="iconutil" logError="true">
      <arg line="-c icns -o ${icon.icns} ${icon.set}" />
    </exec>

    <delete dir="${icon.set}" />
  </target>


  <!-- OUT OF DATE -->
  <!-- Target to create the icons... putting this in here rather than docs.
       For OS X (though Linux might work), not intended for general use,
       because it requires things like iconutil (on OS X) or ImageMagick's
       convert tool (primarily in *nix environments). -->
  <target name="icons">
    <property name="icon.set" value="/tmp/pde.iconset" />

    <!-- create iconset for the PDE application for macOS -->
    <antcall target="iconset">
      <param name="icon.root" value="shared/lib/icons/pde" />
      <param name="icon.icns" value="macos/processing.icns" />
    </antcall>

    <!-- create iconset for exported sketch on macOS -->
    <antcall target="iconset">
      <param name="icon.root" value="../core/src/icon/icon" />
      <param name="icon.icns" value="../java/application/sketch.icns" />
    </antcall>

    <!-- Create .ico for the PDE itself
         https://msdn.microsoft.com/en-us/library/dn742485.aspx
         "Application icons and Control Panel items: The full set includes
         16x16, 32x32, 48x48, and 256x256 (code scales between 32 and 256).
         The .ico file format is required. For Classic Mode, the full set
         is 16x16, 24x24, 32x32, 48x48 and 64x64."
         We're missing size 24x24, but, eh... -->
    <exec executable="convert" dir="shared/lib/icons">
      <arg line="pde-16.png pde-32.png pde-48.png pde-64.png pde-256.png ../../../windows/application.ico" />
    </exec>

    <!-- Create .ico for exported Java applications -->
    <exec executable="convert" dir="../core/src/icon">
      <arg line="icon-16.png icon-32.png icon-48.png icon-64.png icon-256.png ../../../java/application/sketch.ico" />
    </exec>
  </target>


  <!-- - - - - - - - - -->
  <!-- Developer Docs -->
  <!-- - - - - - - - - -->

  <target name="doc">

    <mkdir dir="javadoc" />

    <!-- Core is in the classpath, so we must build it. -->
    <subant buildpath="../core" target="build" failonerror="true" />

    <!-- build doc for core -->
    <exec executable="find" dir="javadoc" discardError="true">
      <arg line="core -type f -exec rm -rf {} ';'" />
    </exec>

    <javadoc access="public" author="false" classpath="../core/library/jogl-all.jar:../core/bin:../core/library/gluegen-rt.jar" destdir="javadoc/core" nodeprecated="false" nodeprecatedlist="false" noindex="false" nonavbar="false" notree="false" source="${jdk.train}" splitindex="false" use="false" version="false">

      <!-- provide links for java.* classes.
           also suppresses the java.lang prefix in the text.  -->
      <link href="https://docs.oracle.com/en/java/javase/${jdk.train}/docs/api/" />

      <!-- prevent files from always appearing to have changed -->
      <arg value="-notimestamp" />

      <arg value="-quiet" />

      <!-- Suppress errors and display some information. -->
      <tag name="webref" enabled="false" />
      <tag name="nowebref" enabled="false" />
      <tag name="generate" enabled="false" />
      <tag name="instanceName" enabled="false" />
      <tag name="see_external" enabled="false" />
      <tag name="brief" description="In brief:" />
      <tag name="usage" />
      <arg value="-Xdoclint:reference,accessibility" />

      <packageset dir="../core/src">
        <include name="processing/**" />
      </packageset>

    </javadoc>

    <!-- build everything else -->
    <exec executable="find" dir="javadoc" discardError="true">
      <arg line="everything -type f -exec rm -rf {} ';'" />
    </exec>

    <javadoc access="public" author="false" classpath="../app/lib/ant.jar:../app/lib/ant-launcher.jar:../app/lib/jna.jar:../app/lib/jna-platform.jar:../app/lib/flatlaf.jar:../core/bin:../core/library/gluegen-rt.jar:../core/library/jogl-all.jar:../java/libraries/svg:../java/libraries/pdf/library/itext.jar:../java/libraries/dxf:../java/libraries/serial/library:${java.home}/lib/tools.jar" destdir="javadoc/everything" nodeprecated="false" nodeprecatedlist="false" noindex="false" nonavbar="false" notree="false" source="${jdk.train}" splitindex="false" use="false" version="false" noqualifier="all">

      <arg value="-notimestamp" />

      <arg value="-quiet" />

      <link href="https://docs.oracle.com/en/java/javase/${jdk.train}/docs/api/" />

      <packageset dir="../app/src">
        <include name="antlr/**" />
        <include name="processing/**" />
      </packageset>

      <tag name="webref" enabled="false" />
      <tag name="nowebref" enabled="false" />
      <tag name="generate" enabled="false" />
      <tag name="instanceName" enabled="false" />
      <tag name="see_external" enabled="false" />
      <tag name="brief" description="In brief:" />
      <tag name="usage" />
      <arg value="-Xdoclint:reference,accessibility" />

      <!--<packageset dir="../app/generated">
        <include name="processing/**" />
      </packageset>-->

      <packageset dir="../core/src">
        <include name="processing/**" />
      </packageset>
    </javadoc>


    <!-- do libraries -->
    <exec executable="find" dir="javadoc" discardError="true">
      <arg line="libraries -type f -exec rm -rf {} ';'" />
    </exec>

    <javadoc access="public" author="false" classpath="../app/lib/ant.jar:../app/lib/ant-launcher.jar:../app/lib/jna.jar:../app/lib/jna-platform.jar:../core/bin:../core/library/gluegen-rt.jar:../core/library/jogl-all.jar:../java/libraries/svg/library/batik.jar:../java/libraries/pdf/library/itext.jar:../java/libraries/dxf:../java/libraries/serial/library/jssc.jar:${java.home}/lib/tools.jar" destdir="javadoc/libraries" nodeprecated="false" nodeprecatedlist="false" noindex="false" nonavbar="false" notree="false" source="${jdk.train}" splitindex="false" use="false" version="false" noqualifier="all">

      <arg value="-notimestamp" />

      <arg value="-quiet" />

      <link href="https://docs.oracle.com/en/java/javase/${jdk.train}/docs/api/" />
      <link href="../../javadoc/core/" />

      <tag name="webref" enabled="false" />
      <tag name="nowebref" enabled="false" />
      <tag name="generate" enabled="false" />
      <tag name="instanceName" enabled="false" />
      <tag name="see_external" enabled="false" />
      <tag name="brief" description="In brief:" />
      <tag name="usage" />
      <arg value="-Xdoclint:reference,accessibility" />

      <packageset dir="../java/libraries/dxf/src">
        <include name="processing/**" />
      </packageset>
      <packageset dir="../java/libraries/io/src">
        <include name="processing/**" />
      </packageset>
      <packageset dir="../java/libraries/net/src">
        <include name="processing/**" />
      </packageset>
      <packageset dir="../java/libraries/pdf/src">
        <include name="processing/**" />
      </packageset>
      <packageset dir="../java/libraries/serial/src">
        <include name="processing/**" />
      </packageset>
      <packageset dir="../java/libraries/svg/src">
        <include name="processing/**" />
      </packageset>
    </javadoc>

<!--
    <copy file="javadoc/stylesheet.css"
          tofile="javadoc/everything/stylesheet.css" />
    <copy file="javadoc/index.html"
          tofile="javadoc/everything/index.html" />
-->
  </target>


  <!-- Cleaning the build and libraries -->

  <target name="clean" description="Perform a spring cleaning"
          depends="linux-clean, windows-clean, macos-clean, subprojects-clean">
  </target>

  <target name="clean-libs" description="Purge downloaded support libraries">
    <subant buildpath="../core" target="clean-libs"/>
    <subant buildpath="../app" target="clean-libs"/>
    <subant buildpath="../java/libraries/svg" target="clean-libs"/>
  </target>

</project>
